def test_quad_degree(): """ Проверяем АСТ для ИКФ Q: почему в некоторых случаях x^n интегрируется почти без ошибок при n узлах ИКФ? """ x0, x1 = 0, 1 max_degree = 7 max_nodes = 7 for deg in range(max_degree): p = Monome(deg) y0 = p[x0, x1] node_counts = range(1, max_nodes+1) Y = [quad(p, x0, x1, np.linspace(x0, x1, node_count)) for node_count in node_counts] # Y = [quad(p, x0, x1, x0 + (x1-x0) * np.random.random(node_count)) for node_count in max_node_count] accuracy = get_accuracy(Y, y0 * np.ones_like(Y)) # Проверяем точность for node_count, acc in zip(node_counts, accuracy): if node_count >= deg + 1: assert acc > 6 plt.plot(node_counts, accuracy, '.:', label=f'x^{deg}') plt.legend() plt.ylabel('accuracy') plt.xlabel('node_count') plt.suptitle(f'test quad') plt.show()
def test_weighted_quad_degree(): """ Проверяем АСТ для ИКФ с весами Посчитаем n-ый момент весовой функции двумя способами: - через moments() - численно через quad() """ x0, x1 = 1, 3 alpha = 0.14 beta = 0.88 max_degree = 7 for deg in range(1, max_degree): p = Monome(deg) xs = np.linspace(x0, x1, 6)[1:-1] # 4 points => accuracy degree is 3 res = quad(p, x0, x1, xs, a=x0, alpha=alpha) ans = moments(deg, x0, x1, a=x0, alpha=alpha)[-1] d = abs(res - ans) print(f'{deg:2}-a: {res:8.3f} vs {ans:8.3f}, delta = {d:e}') if deg < len(xs): assert d < 1e-6 res = quad(p, x0, x1, xs, b=x1, beta=beta) ans = moments(deg, x0, x1, b=x1, beta=beta)[-1] d = abs(res - ans) print(f'{deg:2}-b: {res:8.3f} vs {ans:8.3f}, delta = {d:e}') if deg < len(xs): assert d < 1e-6
def test_quad_gauss_degree(): """ check gaussian quadrature degree """ x0, x1 = 0, 1 max_degree = 8 for deg in range(2, max_degree): p = Monome(deg) y0 = p[x0, x1] max_node_count = range(2, 6) Y = [ quad_gauss(p, x0, x1, node_count) for node_count in max_node_count ] accuracy = get_log_error(Y, y0 * np.ones_like(Y)) accuracy[np.isinf(accuracy)] = 17 # check accuracy is good enough for node_count, acc in zip(max_node_count, accuracy): if 2 * node_count >= deg + 1: assert acc > 6 plt.plot(max_node_count, accuracy, '.:', label=f'x^{deg}') plt.legend() plt.ylabel('accuracy') plt.xlabel('node count') plt.suptitle(f'test quad gauss') plt.show()
def test_quad_gauss_degree(): """ Проверяем АСТ для ИКФ Гаусса """ x0, x1 = 0, 1 max_degree = 8 for deg in range(max_degree): p = Monome(deg) y0 = p[x0, x1] node_counts = range(1, 6) Y = [quad_gauss(p, x0, x1, node_count) for node_count in node_counts] accuracy = get_accuracy(Y, y0 * np.ones_like(Y)) # Проверяем точность for node_count, acc in zip(node_counts, accuracy): if 2 * node_count >= deg + 1: assert acc > 6 plt.plot(node_counts, accuracy, '.:', label=f'x^{deg}') plt.legend() plt.ylabel('accuracy') plt.xlabel('node count') plt.suptitle(f'test quad gauss') plt.show()
def test_composite_quad(n_nodes): """ Проверяем 2-, 3-, 5-узловые СКФ Q: объясните скорость сходимости для каждого случая """ fig, ax = plt.subplots(1, 2) x0, x1 = 0, 1 L = 2 n_intervals = [L ** q for q in range(0, 8)] for i, degree in enumerate((5, 6)): p = Monome(degree) Y = [composite_quad(p, x0, x1, n_intervals=n, n_nodes=n_nodes) for n in n_intervals] accuracy = get_accuracy(Y, p[x0, x1] * np.ones_like(Y)) x = np.log10(n_intervals) # оценка сходимости ind = np.isfinite(x) & np.isfinite(accuracy) k, b = np.polyfit(x[ind], accuracy[ind], 1) aitken_degree = aitken(*Y[0:6:2], L ** 2) ax[i].plot(x, k*x+b, 'b:', label=f'{k:.2f}*x+{b:.2f}') ax[i].plot(x, aitken_degree*x+b, 'm:', label=f'aitken ({aitken_degree:.2f})') ax[i].plot(x, accuracy, 'kh', label=f'accuracy for x^{degree}') ax[i].set_title(f'{n_nodes}-node CQ for x^{degree}') ax[i].set_xlabel('log10(n_intervals)') ax[i].set_ylabel('accuracy') ax[i].legend() if n_nodes < degree: assert np.abs(aitken_degree - k) < 0.5, \ f'Aitken estimation {aitken_degree:.2f} is too far from actual {k:.2f}' plt.show()
def test_weighted_quad_degree(): """ check weighted quadrature degree we compare n-th moment of weight function calculated in two ways: - by moments() - numerically by quad() """ x0, x1 = 1, 3 alpha = 0.14 beta = 0.88 max_degree = 7 for deg in range(1, max_degree): p = Monome(deg) xs = np.linspace(x0, x1, 6)[1:-1] # 4 points => accuracy degree is 3 res = quad(p, x0, x1, xs, a=x0, alpha=alpha) ans = moments(deg, x0, x1, a=x0, alpha=alpha)[-1] d = abs(res - ans) print(f'{deg:2}-a: {res:8.3f} vs {ans:8.3f}, delta = {d:e}') if deg < len(xs): assert d < 1e-6 res = quad(p, x0, x1, xs, b=x1, beta=beta) ans = moments(deg, x0, x1, b=x1, beta=beta)[-1] d = abs(res - ans) print(f'{deg:2}-b: {res:8.3f} vs {ans:8.3f}, delta = {d:e}') if deg < len(xs): assert d < 1e-6
def tes_quad_degree(): """ check quadrature degree Q: why in some cases x^n integrated perfectly with only n nodes? """ x0, x1 = 0, 1 max_degree = 7 for deg in range(1, max_degree): p = Monome(deg) y0 = p[x0, x1] max_node_count = range(1, max_degree + 1) Y = [ quad(p, x0, x1, np.linspace(x0, x1, node_count)) for node_count in max_node_count ] # Y = [quad(p, x0, x1, x0 + (x1-x0) * np.random.random(node_count)) for node_count in max_node_count] accuracy = get_log_error(Y, y0 * np.ones_like(Y)) accuracy[np.isinf(accuracy)] = 17 # check accuracy is good enough for node_count, acc in zip(max_node_count, accuracy): if node_count >= deg + 1: assert acc > 6 plt.plot(max_node_count, accuracy, '.:', label=f'x^{deg}') plt.legend() plt.ylabel('accuracy') plt.xlabel('node_count') plt.suptitle(f'test quad') plt.show()
def test_weighted_quad_degree(): """ check weighed quadrature degree """ x0, x1 = 1, 3 alpha = 0.14 beta = 0.88 max_degree = 7 for deg in range(1, max_degree): p = Monome(deg) xs = np.linspace(x0, x1, 6)[1:-1] # 4 points => accuracy degree is 3 res = quad(p, x0, x1, xs, alpha=alpha) ans = weight(deg, x0, x1, alpha=alpha) d = abs(res - ans) print(f'{deg:2}-a: {res:8.3f} vs {ans:8.3f}, delta = {d:e}') if deg < len(xs): assert d < 1e-6 res = quad(p, x0, x1, xs, beta=beta) ans = weight(deg, x0, x1, beta=beta) d = abs(res - ans) print(f'{deg:2}-b: {res:8.3f} vs {ans:8.3f}, delta = {d:e}') if deg < len(xs): assert d < 1e-6
def test_composite_quad(): plt.figure() x0, x1 = 0, 1 L = 2 n_intervals = [L**q for q in range(0, 8)] n_nodes = 3 for i, degree in enumerate((5, 6)): p = Monome(degree) Y = [ composite_quad(p, x0, x1, n_intervals=n, n_nodes=n_nodes) for n in n_intervals ] accuracy = get_log_error(Y, p[x0, x1] * np.ones_like(Y)) x = np.log10(n_intervals) # check convergence ind = np.isfinite(x) & np.isfinite(accuracy) k, b = np.polyfit(x[ind], accuracy[ind], 1) aitken_degree = aitken(*Y[0:6:2], L**2) plt.subplot(1, 2, i + 1) plt.plot(x, k * x + b, 'b:', label=f'{k:.2f}*x+{b:.2f}') plt.plot(x, aitken_degree * x + b, 'm:', label=f'aitken estimation') plt.plot(x, accuracy, 'kh', label=f'accuracy for x^{degree}') plt.xlabel('log10(node count)') plt.ylabel('accuracy') plt.legend() assert np.abs(aitken_degree - k) < 0.5, \ f'Aitken estimation {aitken_degree:.2f} is too far from actual {k:.2f}' plt.show()
def test_composite_quad(n_nodes): """ test composite 2-, 3-, 5-node quads Q: explain converge speed for each case """ fig, ax = plt.subplots(1, 2) x0, x1 = 0, 1 L = 2 n_intervals = [L ** q for q in range(0, 8)] for i, degree in enumerate((5, 6)): p = Monome(degree) Y = [composite_quad(p, x0, x1, n_intervals=n, n_nodes=n_nodes) for n in n_intervals] accuracy = get_log_error(Y, p[x0, x1] * np.ones_like(Y)) x = np.log10(n_intervals) # check convergence ind = np.isfinite(x) & np.isfinite(accuracy) k, b = np.polyfit(x[ind], accuracy[ind], 1) aitken_degree = aitken(*Y[0:6:2], L ** 2) ax[i].plot(x, k*x+b, 'b:', label=f'{k:.2f}*x+{b:.2f}') ax[i].plot(x, aitken_degree*x+b, 'm:', label=f'aitken ({aitken_degree:.2f})') ax[i].plot(x, accuracy, 'kh', label=f'accuracy for x^{degree}') ax[i].set_title(f'{n_nodes}-node CQ for x^{degree}') ax[i].set_xlabel('log10(n_intervals)') ax[i].set_ylabel('accuracy') ax[i].legend() if n_nodes < degree: assert np.abs(aitken_degree - k) < 0.5, \ f'Aitken estimation {aitken_degree:.2f} is too far from actual {k:.2f}' plt.show()
def test_quad_degree(): """ Проверяем АСТ для ИКФ Q: почему в некоторых случаях x^n интегрируется почти без ошибок при n узлах ИКФ? A: Поскольку многочлен Лагранжа Ln является алгебраическим многочленом степени n − 1, то по построению, он имеет алгебраический порядок точности не ниже n − 1. Однако если n нечетно, т.е. когда середина отрезка [a, b] входит в состав сетки, то формула оказывается точна и для многочленов степени n. """ x0, x1 = 0, 1 max_degree = 7 max_nodes = 7 for deg in range(max_degree): p = Monome(deg) y0 = p[x0, x1] node_counts = range(1, max_nodes + 1) Y = [ quad(p, x0, x1, np.linspace(x0, x1, node_count)) for node_count in node_counts ] # Y = [quad(p, x0, x1, x0 + (x1-x0) * np.random.random(node_count)) for node_count in node_counts] accuracy = get_accuracy(Y, y0 * np.ones_like(Y)) # Проверяем точность for node_count, acc in zip(node_counts, accuracy): if node_count >= deg + 1: assert acc > 6 plt.plot(node_counts, accuracy, '.:', label=f'x^{deg}') plt.legend() plt.ylabel('accuracy') plt.xlabel('node_count') plt.suptitle(f'test quad') plt.show()