"""第一章示例：Python 3.9+，只使用标准库。参数均为教学设定。"""

from math import sqrt


JOBS = [[10, 2], [4, 6], [8, 0]]  # 每行依次是黑白页数、彩色页数
WEIGHTS = [3, 5]                 # 两类页面分别需要的秒数
BIAS = 20                       # 每份文档的固定开销
MODEL_WEIGHTS = [[3, 2], [5, 4]]  # 每列对应一台打印机
MODEL_BIASES = [20, 30]
U = [3, 2]
V = [1, 2]
TRANSFORM = [[2, 1], [0, 1]]


def linear(pages, a=3, b=20):
    return a * pages + b


def dot(u, v):
    if len(u) != len(v):
        raise ValueError("点积要求两个向量的分量数相同")
    return sum(left * right for left, right in zip(u, v))


def shape(matrix):
    if not matrix or not matrix[0]:
        raise ValueError("这个示例只处理非空矩阵")
    columns = len(matrix[0])
    if any(len(row) != columns for row in matrix):
        raise ValueError("矩阵的每一行必须一样长")
    return len(matrix), columns


def matvec(matrix, vector):
    _, columns = shape(matrix)
    if columns != len(vector):
        raise ValueError("矩阵的列数必须等于向量的分量数")
    return [dot(row, vector) for row in matrix]


def matmul(left, right):
    rows, inner = shape(left)
    right_rows, columns = shape(right)
    if inner != right_rows:
        raise ValueError("左矩阵的列数必须等于右矩阵的行数")
    result = []
    for i in range(rows):
        row = []
        for j in range(columns):
            value = 0
            for k in range(inner):
                value += left[i][k] * right[k][j]
            row.append(value)
        result.append(row)
    return result


def main():
    seconds = linear(24)
    print(f"24 页：{seconds} 秒，约 {seconds / 60:.2f} 分钟")
    print("u + v =", [a + b for a, b in zip(U, V)])
    print("2u =", [2 * value for value in U])
    print("u · v =", dot(U, V))
    u_length = sqrt(dot(U, U))
    v_length = sqrt(dot(V, V))
    print(f"u 的长度：{u_length:.3f}")
    print(f"v 沿 u 方向的投影长度：{dot(U, V) / u_length:.3f}")
    print(f"u 与 v 的余弦相似度：{dot(U, V) / (u_length * v_length):.3f}")

    print("X 的形状：", shape(JOBS))
    weighted = matvec(JOBS, WEIGHTS)
    print("Xw =", weighted)
    print("一台打印机的预测（秒）：", [value + BIAS for value in weighted])

    raw = matmul(JOBS, MODEL_WEIGHTS)
    predicted = [[value + MODEL_BIASES[j] for j, value in enumerate(row)]
                 for row in raw]
    print("XW =", raw)
    print("两台打印机的预测（秒）：", predicted)
    print("A 作用于 [1, 2]：", matvec(TRANSFORM, [1, 2]))


if __name__ == "__main__":
    main()
