Skip to content

Commit

Permalink
refactor(osmomath): limit pow iterations in osmomath
Browse files Browse the repository at this point in the history
  • Loading branch information
p0mvn committed Oct 4, 2023
1 parent ac922e4 commit b489a40
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 13 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#6309](https://github.com/osmosis-labs/osmosis/pull/6309) Add Cosmwasm Pool Queries to Stargate Query
* [#6493](https://github.com/osmosis-labs/osmosis/pull/6493) Add PoolManager Params query to Stargate Whitelist
* [#6421](https://github.com/osmosis-labs/osmosis/pull/6421) Moves ValidatePermissionlessPoolCreationEnabled out of poolmanager module

* [#6627](https://github.com/osmosis-labs/osmosis/pull/6627) Limit pow iterations in osmomath.

## v19.2.0

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.17
github.com/ory/dockertest/v3 v3.10.0
github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3
github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230924192433-36cf2950dca4
github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20231003135651-7418f98f1a04
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20230929193736-aae32321cac7
github.com/osmosis-labs/osmosis/x/epochs v0.0.3-0.20230911120014-b14342e08daf
github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.9-0.20230911120014-b14342e08daf
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,8 @@ github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 h1:Ylmch
github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3/go.mod h1:lV6KnqXYD/ayTe7310MHtM3I2q8Z6bBfMAi+bhwPYtI=
github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230924192433-36cf2950dca4 h1:venI3u6DjxKcQbjiCO3V8s0ww/jx+cAZRkpwLHadms8=
github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20230924192433-36cf2950dca4/go.mod h1:IlCTpM2uoi8SUAigc9r9kAaoz7K5H9O84u7CwaTLDdY=
github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20231003135651-7418f98f1a04 h1:C8LtPGkhJxfJNj7Xtok1If5yAV53O6XG3USaOJSgeg4=
github.com/osmosis-labs/osmosis/osmomath v0.0.7-0.20231003135651-7418f98f1a04/go.mod h1:jtOM+8RJMOn5e8YIaodzvO0b8kvBcHDgtCVCmWrx6wU=
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20230929193736-aae32321cac7 h1:E5rwhxKEt6XOIfLkoLNiqCCFNCymJjiwMYIP+0ABMKM=
github.com/osmosis-labs/osmosis/osmoutils v0.0.7-0.20230929193736-aae32321cac7/go.mod h1:YT53hlXr54D4MVKp3eoBxigiiYvy3F+h+xTZuGPW5R8=
github.com/osmosis-labs/osmosis/x/epochs v0.0.3-0.20230911120014-b14342e08daf h1:8lkIsAj3L7zxvOZbqVLNJRpSdDxaYhYfAIG7XjPaJiU=
Expand Down
14 changes: 10 additions & 4 deletions osmomath/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
// TODO: Analyze choice here.
var powPrecision, _ = NewDecFromStr("0.00000001")

const powIterationLimit = 245_000

var (
one_half Dec = MustNewDecFromStr("0.5")
one Dec = OneDec()
Expand Down Expand Up @@ -81,8 +83,8 @@ func Pow(base Dec, exp Dec) Dec {

// Contract: 0 < base <= 2
// 0 <= exp < 1.
func PowApprox(base Dec, exp Dec, precision Dec) Dec {
if !base.IsPositive() {
func PowApprox(originalBase Dec, exp Dec, precision Dec) Dec {
if !originalBase.IsPositive() {
panic(fmt.Errorf("base must be greater than 0"))
}

Expand All @@ -93,7 +95,7 @@ func PowApprox(base Dec, exp Dec, precision Dec) Dec {
// Common case optimization
// Optimize for it being equal to one-half
if exp.Equal(one_half) {
output, err := base.ApproxSqrt()
output, err := originalBase.ApproxSqrt()
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -129,7 +131,7 @@ func PowApprox(base Dec, exp Dec, precision Dec) Dec {
// TODO: Check with our parameterization
// TODO: If theres a bug, balancer is also wrong here :thonk:

base = base.Clone()
base := originalBase.Clone()
x, xneg := AbsDifferenceWithSign(base, one)
term := OneDec()
sum := OneDec()
Expand Down Expand Up @@ -166,6 +168,10 @@ func PowApprox(base Dec, exp Dec, precision Dec) Dec {
} else {
sum.AddMut(term)
}

if i == powIterationLimit {
panic(fmt.Errorf("failed to reach precision within %d iterations, best guess: %s for %s^%s", powIterationLimit, sum, originalBase, exp))
}
}
return sum
}
42 changes: 36 additions & 6 deletions osmomath/math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestAbsDifferenceWithSign(t *testing.T) {

func TestPowApprox(t *testing.T) {
testCases := []struct {
expectPanic bool
base Dec
exp Dec
powPrecision Dec
Expand All @@ -44,10 +45,10 @@ func TestPowApprox(t *testing.T) {
},
{
// zero base, this should panic
base: ZeroDec(),
exp: OneDec(),
powPrecision: MustNewDecFromStr("0.00001"),
expectedResult: ZeroDec(),
base: ZeroDec(),
exp: OneDec(),
powPrecision: MustNewDecFromStr("0.00001"),
expectPanic: true,
},
{
// large base, small exp
Expand Down Expand Up @@ -84,17 +85,46 @@ func TestPowApprox(t *testing.T) {
powPrecision: MustNewDecFromStr("0.00000001"),
expectedResult: OneDec(),
},
{
// base close to 2

base: MustNewDecFromStr("1.999999999999999999"),
exp: SmallestDec(),
powPrecision: powPrecision,
// In Python: 1.000000000000000000693147181
expectedResult: OneDec(),
},
{
// base close to 2 and hitting iteration bound

base: MustNewDecFromStr("1.999999999999999999"),
exp: MustNewDecFromStr("0.1"),
powPrecision: powPrecision,

// In Python: 1.071773462536293164

expectPanic: true,
},
{
// base close to 2 under iteration limit

base: MustNewDecFromStr("1.99999"),
exp: MustNewDecFromStr("0.1"),
powPrecision: powPrecision,
// In Python: 1.071772926648356147102864087
expectedResult: MustNewDecFromStr("1.071772926648356147"),
},
}

for i, tc := range testCases {
var actualResult Dec
ConditionalPanic(t, tc.base.IsZero(), func() {
ConditionalPanic(t, tc.expectPanic, func() {
fmt.Println(tc.base)
actualResult = PowApprox(tc.base, tc.exp, tc.powPrecision)
require.True(
t,
tc.expectedResult.Sub(actualResult).Abs().LTE(tc.powPrecision),
fmt.Sprintf("test %d failed: expected value & actual value's difference should be less than precision", i),
fmt.Sprintf("test %d failed: expected value & actual value's difference should be less than precision, expected: %s, actual: %s, precision: %s", i, tc.expectedResult, actualResult, tc.powPrecision),
)
})
}
Expand Down
8 changes: 7 additions & 1 deletion osmomath/pow_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,13 @@ func BenchmarkSlowPowCases(b *testing.B) {
exp Dec
}{
{
base: MustNewDecFromStr("1.99999999999999"),
// Original worst case:
// 1.99999999999999
// 0.1
//
// The values below are hand-picked to be close to the worst case
// while under the iteration bound.
base: MustNewDecFromStr("1.99999"),
exp: MustNewDecFromStr("0.1"),
},
}
Expand Down

0 comments on commit b489a40

Please sign in to comment.