xref: /aosp_15_r20/external/libaom/tools/gop_bitrate/python/bitrate_accuracy.py (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1import numpy as np
2
3# Model A only.
4# Uses least squares regression to find the solution
5# when there is one unknown variable.
6def lstsq_solution(A, B):
7    A_inv = np.linalg.pinv(A)
8    x = np.matmul(A_inv, B)
9    return x[0][0]
10
11# Model B only.
12# Uses the pseudoinverse matrix to find the solution
13# when there are two unknown variables.
14def pinv_solution(A, mv, B):
15    new_A = np.concatenate((A, mv), axis=1)
16    new_A_inv = np.linalg.pinv(new_A)
17    new_x = np.matmul(new_A_inv, B)
18    print("pinv solution:", new_x[0][0], new_x[1][0])
19    return (new_x[0][0], new_x[1][0])
20
21# Model A only.
22# Finds the coefficient to multiply A by to minimize
23# the percentage error between A and B.
24def minimize_percentage_error_model_a(A, B):
25    R = np.divide(A, B)
26    num = 0
27    den = 0
28    best_x = 0
29    best_error = 100
30    for r_i in R:
31        num += r_i
32        den += r_i**2
33    if den == 0:
34        return 0
35    return (num/den)[0]
36
37# Model B only.
38# Finds the coefficients to multiply to the frame bitrate
39# and the motion vector bitrate to minimize the percent error.
40def minimize_percentage_error_model_b(r_e, r_m, r_f):
41    r_ef = np.divide(r_e, r_f)
42    r_mf = np.divide(r_m, r_f)
43    sum_ef = np.sum(r_ef)
44    sum_ef_sq = np.sum(np.square(r_ef))
45    sum_mf = np.sum(r_mf)
46    sum_mf_sq = np.sum(np.square(r_mf))
47    sum_ef_mf = np.sum(np.multiply(r_ef, r_mf))
48    # Divides x by y. If y is zero, returns 0.
49    divide = lambda x, y : 0 if y == 0 else x / y
50    # Set up and solve the matrix equation
51    A = np.array([[1, divide(sum_ef_mf, sum_ef_sq)],[divide(sum_ef_mf, sum_mf_sq), 1]])
52    B = np.array([divide(sum_ef, sum_ef_sq), divide(sum_mf, sum_mf_sq)])
53    A_inv = np.linalg.pinv(A)
54    x = np.matmul(A_inv, B)
55    return x
56
57# Model A only.
58# Calculates the least squares error between A and B
59# using coefficients in X.
60def average_lstsq_error(A, B, x):
61    error = 0
62    n = 0
63    for i, a in enumerate(A):
64        a = a[0]
65        b = B[i][0]
66        if b == 0:
67            continue
68        n += 1
69        error += (b - x*a)**2
70    if n == 0:
71        return None
72    error /= n
73    return error
74
75# Model A only.
76# Calculates the average percentage error between A and B.
77def average_percent_error_model_a(A, B, x):
78    error = 0
79    n = 0
80    for i, a in enumerate(A):
81        a = a[0]
82        b = B[i][0]
83        if b == 0:
84            continue
85        n += 1
86        error_i = (abs(x*a-b)/b)*100
87        error += error_i
88    error /= n
89    return error
90
91# Model B only.
92# Calculates the average percentage error between A and B.
93def average_percent_error_model_b(A, M, B, x):
94    error = 0
95    for i, a in enumerate(A):
96        a = a[0]
97        mv = M[i]
98        b = B[i][0]
99        if b == 0:
100            continue
101        estimate = x[0]*a
102        estimate += x[1]*mv
103        error += abs(estimate - b) / b
104    error *= 100
105    error /= A.shape[0]
106    return error
107
108def average_squared_error_model_a(A, B, x):
109    error = 0
110    n = 0
111    for i, a in enumerate(A):
112        a = a[0]
113        b = B[i][0]
114        if b == 0:
115            continue
116        n += 1
117        error_i = (1 - x*(a/b))**2
118        error += error_i
119    error /= n
120    error = error**0.5
121    return error * 100
122
123def average_squared_error_model_b(A, M, B, x):
124    error = 0
125    n = 0
126    for i, a in enumerate(A):
127        a = a[0]
128        b = B[i][0]
129        mv = M[i]
130        if b == 0:
131            continue
132        n += 1
133        error_i = 1 - ((x[0]*a + x[1]*mv)/b)
134        error_i = error_i**2
135        error += error_i
136    error /= n
137    error = error**0.5
138    return error * 100
139
140# Traverses the data and prints out one value for
141# each update type.
142def print_solutions(file_path):
143    data = np.genfromtxt(file_path, delimiter="\t")
144    prev_update = 0
145    split_list_indices = list()
146    for i, val in enumerate(data):
147        if prev_update != val[3]:
148            split_list_indices.append(i)
149            prev_update = val[3]
150    split = np.split(data, split_list_indices)
151    for array in split:
152        A, mv, B, update = np.hsplit(array, 4)
153        z = np.where(B == 0)[0]
154        r_e = np.delete(A, z, axis=0)
155        r_m = np.delete(mv, z, axis=0)
156        r_f = np.delete(B, z, axis=0)
157        A = r_e
158        mv = r_m
159        B = r_f
160        all_zeros = not A.any()
161        if all_zeros:
162            continue
163        print("update type:", update[0][0])
164        x_ls = lstsq_solution(A, B)
165        x_a = minimize_percentage_error_model_a(A, B)
166        x_b = minimize_percentage_error_model_b(A, mv, B)
167        percent_error_a = average_percent_error_model_a(A, B, x_a)
168        percent_error_b = average_percent_error_model_b(A, mv, B, x_b)[0]
169        baseline_percent_error_a = average_percent_error_model_a(A, B, 1)
170        baseline_percent_error_b = average_percent_error_model_b(A, mv, B, [1, 1])[0]
171
172        squared_error_a = average_squared_error_model_a(A, B, x_a)
173        squared_error_b = average_squared_error_model_b(A, mv, B, x_b)[0]
174        baseline_squared_error_a = average_squared_error_model_a(A, B, 1)
175        baseline_squared_error_b = average_squared_error_model_b(A, mv, B, [1, 1])[0]
176
177        print("model,\tframe_coeff,\tmv_coeff,\terror,\tbaseline_error")
178        print("Model A %_error,\t" + str(x_a) + ",\t" + str(0) + ",\t" + str(percent_error_a) + ",\t" + str(baseline_percent_error_a))
179        print("Model A sq_error,\t" + str(x_a) + ",\t" + str(0) + ",\t" + str(squared_error_a) + ",\t" + str(baseline_squared_error_a))
180        print("Model B %_error,\t" + str(x_b[0]) + ",\t" + str(x_b[1]) + ",\t" + str(percent_error_b) + ",\t" + str(baseline_percent_error_b))
181        print("Model B sq_error,\t" + str(x_b[0]) + ",\t" + str(x_b[1]) + ",\t" + str(squared_error_b) + ",\t" + str(baseline_squared_error_b))
182        print()
183
184if __name__ == "__main__":
185    print_solutions("data2/all_lowres_target_lt600_data.txt")
186