From 05e7a8a62ea98232dd0c4245fa9e5ee52d96fadf Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 16 Apr 2024 11:35:17 +0200 Subject: [PATCH] test: ensuring old bounds behavior is unchanged --- contracts/mocks/newton_y_large_gamma.vy | 2 +- contracts/mocks/newton_y_small_gamma.vy | 13 ++++---- tests/unitary/math/test_newton_y.py | 40 +++++++++++++++---------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/contracts/mocks/newton_y_large_gamma.vy b/contracts/mocks/newton_y_large_gamma.vy index 13d55ae9..a48c713a 100644 --- a/contracts/mocks/newton_y_large_gamma.vy +++ b/contracts/mocks/newton_y_large_gamma.vy @@ -92,8 +92,8 @@ def newton_y(ANN: uint256, gamma: uint256, x: uint256[N_COINS], D: uint256, i: u if gamma > MAX_GAMMA_SMALL: lim_mul = unsafe_div(unsafe_mul(lim_mul, MAX_GAMMA_SMALL), gamma) # smaller than 100.0 - iterations: uint256 = 0 y: uint256 = 0 + iterations: uint256 = 0 y, iterations = self._newton_y(ANN, gamma, x, D, i, lim_mul) frac: uint256 = y * 10**18 / D diff --git a/contracts/mocks/newton_y_small_gamma.vy b/contracts/mocks/newton_y_small_gamma.vy index a1c5a2b5..8fad9a5d 100644 --- a/contracts/mocks/newton_y_small_gamma.vy +++ b/contracts/mocks/newton_y_small_gamma.vy @@ -14,7 +14,7 @@ MAX_A: constant(uint256) = N_COINS**N_COINS * A_MULTIPLIER * 1000 @internal @pure -def _newton_y(ANN: uint256, gamma: uint256, x: uint256[N_COINS], D: uint256, i: uint256) -> uint256: +def _newton_y(ANN: uint256, gamma: uint256, x: uint256[N_COINS], D: uint256, i: uint256) -> (uint256, uint256): """ Calculating x[i] given other balances x[0..N_COINS-1] and invariant D ANN = A * N**N @@ -74,22 +74,25 @@ def _newton_y(ANN: uint256, gamma: uint256, x: uint256[N_COINS], D: uint256, i: diff = y_prev - y if diff < max(convergence_limit, y / 10**14): - return y + return y, j raise "Did not converge" @external @pure -def newton_y(ANN: uint256, gamma: uint256, x: uint256[N_COINS], D: uint256, i: uint256) -> uint256: +def newton_y(ANN: uint256, gamma: uint256, x: uint256[N_COINS], D: uint256, i: uint256) -> (uint256, uint256): # Safety checks assert ANN > MIN_A - 1 and ANN < MAX_A + 1 # dev: unsafe values A assert gamma > MIN_GAMMA - 1 and gamma < MAX_GAMMA + 1 # dev: unsafe values gamma assert D > 10**17 - 1 and D < 10**15 * 10**18 + 1 # dev: unsafe values D - y: uint256 = self._newton_y(ANN, gamma, x, D, i) + y: uint256 = 0 + iterations: uint256 = 0 + + y, iterations = self._newton_y(ANN, gamma, x, D, i) frac: uint256 = y * 10**18 / D assert (frac >= 10**16 - 1) and (frac < 10**20 + 1) # dev: unsafe value for y - return y + return y, iterations diff --git a/tests/unitary/math/test_newton_y.py b/tests/unitary/math/test_newton_y.py index ada48cb6..914f56ae 100644 --- a/tests/unitary/math/test_newton_y.py +++ b/tests/unitary/math/test_newton_y.py @@ -1,6 +1,6 @@ import boa import pytest -from hypothesis import given, settings +from hypothesis import event, given, settings from hypothesis import strategies as st N_COINS = 2 @@ -12,8 +12,10 @@ MIN_A = int(N_COINS**N_COINS * A_MUL / 10) MAX_A = int(N_COINS**N_COINS * A_MUL * 1000) -MIN_GAMMA = 10**10 -MAX_GAMMA = 3 * 10**17 +# Old bounds for gamma +# should be used only when comparing convergence with the old version +MIN_GAMMA_CMP = 10**10 +MAX_GAMMA_CMP = 2 * 10**15 @pytest.fixture(scope="module") @@ -23,7 +25,7 @@ def math_large_gamma(): @pytest.fixture(scope="module") def math_small_gamma(): - return boa.load("contracts/mock/newton_y_small_gamma.vy") + return boa.load("contracts/mocks/newton_y_small_gamma.vy") @given( @@ -37,17 +39,25 @@ def math_small_gamma(): yD=st.integers( min_value=10**17 // 2, max_value=10**19 // 2 ), # <- ratio 1e18 * y/D, typically 1e18 * 1 - gamma=st.integers(min_value=MIN_GAMMA, max_value=MAX_GAMMA), + gamma=st.integers(min_value=MIN_GAMMA_CMP, max_value=MAX_GAMMA_CMP), j=st.integers(min_value=0, max_value=1), ) @settings(max_examples=MAX_SAMPLES, deadline=None) -def test_iteration_diff(math_large_gamma, A, D, xD, yD, gamma, j): - pass - # TODO: make a test that: - # - measures how many iterations it takes for the - # old value to converge between the two versions - # - makes sure that we're converging to the correct value - # - use hypothesis.event to have some clear statistics about - # the differences in divergence - # X = [D * xD // 10**18, D * yD // 10**18] - # math_large_gamma.newton_y(A, gamma, X, D, j) +def test_newton_y_equivalence( + math_small_gamma, math_large_gamma, A, D, xD, yD, gamma, j +): + """ + Tests whether the newton_y function converges to the same + value for both the old and new versions + """ + X = [D * xD // 10**18, D * yD // 10**18] + y_small, iterations_old = math_small_gamma.newton_y(A, gamma, X, D, j) + y_large, iterations_new = math_large_gamma.newton_y(A, gamma, X, D, j) + + # print(math_large_gamma.internal._newton_y) + + event(f"converges in {iterations_new} iterations") + + # create events depending on the differences between iterations + assert iterations_old - iterations_new == 0 + assert y_small == y_large