# MIT License, Copyright (c) 2022 Marvin Borner # inspiration from T.Æ. Mogensen and Douglas W. Jones (see refs in README) # → refer to std/Math for more advanced functions :import std/Box B :import std/Combinator . :import std/Logic . :import std/Pair . # negative trit indicating coefficient of (-1) t⁻ [[[2]]] ⧗ Trit # positive trit indicating coefficient of (+1) t⁺ [[[1]]] ⧗ Trit # zero trit indicating coefficient of 0 t⁰ [[[0]]] ⧗ Trit # returns true if a trit is negative t⁻? [0 true false false] ⧗ Trit → Boolean :test (t⁻? t⁻) (true) :test (t⁻? t⁺) (false) :test (t⁻? t⁰) (false) # returns true if a trit is positive t⁺? [0 false true false] ⧗ Trit → Boolean :test (t⁺? t⁻) (false) :test (t⁺? t⁺) (true) :test (t⁺? t⁰) (false) # returns true if a trit is zero t⁰? [0 false false true] ⧗ Trit → Boolean :test (t⁰? t⁻) (false) :test (t⁰? t⁺) (false) :test (t⁰? t⁰) (true) # lshifts a negative trit into a balanced ternary number ↑⁻‣ [[[[[2 (4 3 2 1 0)]]]]] ⧗ Number → Number :test (↑⁻(+0)) ((-1)) :test (↑⁻(-1)) ((-4)) :test (↑⁻(+42)) ((+125)) # lshifts a positive trit into a balanced ternary number ↑⁺‣ [[[[[1 (4 3 2 1 0)]]]]] ⧗ Number → Number :test (↑⁺(+0)) ((+1)) :test (↑⁺(-1)) ((-2)) :test (↑⁺(+42)) ((+127)) # lshifts a zero trit into a balanced ternary number ↑⁰‣ [[[[[0 (4 3 2 1 0)]]]]] ⧗ Number → Number :test (↑⁰(+0)) ([[[[0 3]]]]) :test (↑⁰(+1)) ((+3)) :test (↑⁰(+42)) ((+126)) # lshifts a specified trit into a balanced ternary number …↑… [[[[[[5 2 1 0 (4 3 2 1 0)]]]]]] ⧗ Trit → Number → Number :test (t⁻ ↑ (+42)) (↑⁻(+42)) :test (t⁺ ↑ (+42)) (↑⁺(+42)) :test (t⁰ ↑ (+42)) (↑⁰(+42)) # lshifts balanced ternary number without pushing new trit # basically removes mst or leading 0 ←‣ [^(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number z (+0) : true a⁻ &[[(0 (+0) ↑⁻1) : false]] a⁺ &[[(0 (+0) ↑⁺1) : false]] a⁰ &[[(0 (+0) ↑⁰1) : false]] :test (←(+3)) ([[[[0 3]]]]) :test (←(+5)) ([[[[2 (2 3)]]]]) # rshifts a zero trit into a balanced ternary number (pad) →⁰‣ [[[[[4 (0 3) 2 1 0]]]]] ⧗ Number → Number # rshifts least significant trit of a balanced ternary number # WARNING: Not necessarily equivalent to (/ (+3)): e.g. /³(+5) == (+2)! div³ [~(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number z (+0) : (+0) a⁻ &[[↑⁻1 : 1]] a⁺ &[[↑⁺1 : 1]] a⁰ &[[↑⁰1 : 1]] /³‣ div³ :test (/³(+6)) ((+2)) :test (/³(-6)) ((-2)) :test (/³(+5)) ((+2)) # extracts least significant trit from a balanced ternary number lst [0 t⁰ [t⁻] [t⁺] [t⁰]] ⧗ Number → Trit :test (lst (-1)) (t⁻) :test (lst (+0)) (t⁰) :test (lst (+1)) (t⁺) :test (lst (+42)) (t⁰) # extracts most significant trit from a balanced ternary number mst* [B.get t⁰ (0 z a⁻ a⁺ a⁰)] ⧗ Number → Trit z B.empty a⁻ \B.store! t⁻ a⁺ \B.store! t⁺ a⁰ \B.store! t⁰ :test (mst* (-1)) (t⁻) :test (mst* (+0)) (t⁰) :test (mst* (+1)) (t⁺) :test (mst* (+42)) (t⁺) :test (mst* [[[[(0 (1 (0 3)))]]]]) (t⁰) # extracts most significant trit from a balanced ternary number # ignores leading 0s mst [B.get t⁰ (0 z a⁻ a⁺ a⁰)] ⧗ Number → Trit z B.empty a⁻ \B.store! t⁻ a⁺ \B.store! t⁺ a⁰ [0] :test (mst (-1)) (t⁻) :test (mst (+0)) (t⁰) :test (mst (+1)) (t⁺) :test (mst (+42)) (t⁺) # returns true if balanced ternary number is zero zero? [0 true [false] [false] i] ⧗ Number → Boolean =?‣ zero? :test (=?(+0)) (true) :test (=?(-1)) (false) :test (=?(+1)) (false) :test (=?(+42)) (false) # returns true if the number is even (remainder mod 2 == 0) # TODO: faster solution (using tupling?) even? z [[rec]] ⧗ Number → Boolean rec =?0 case-end case-rec case-rec t⁰? (lst 0) (1 /³0) ¬(1 /³0) case-end true =²?‣ even? :test (=²?(+0)) (true) :test (=²?(+1)) (false) :test (=²?(+41)) (false) :test (=²?(+42)) (true) # converts the normal balanced ternary representation into abstract # infinity can't be abstracted in finite time # → the abstract representation is used in eq?/add/sub/mul abstract! [0 z a⁻ a⁺ a⁰] ⧗ Number → AbstractNumber z (+0) a⁻ [[[[[2 4]]]]] a⁺ [[[[[1 4]]]]] a⁰ [[[[[0 4]]]]] →^‣ abstract! :test (→^(-3)) ([[[[0 [[[[2 [[[[3]]]]]]]]]]]]) :test (→^(+0)) ([[[[3]]]]) :test (→^(+3)) ([[[[0 [[[[1 [[[[3]]]]]]]]]]]]) # converts the abstracted balanced ternary representation back to normal normal! y [[0 z a⁻ a⁺ a⁰]] ⧗ AbstractNumber → Number z (+0) a⁻ [↑⁻(2 0)] a⁺ [↑⁺(2 0)] a⁰ [↑⁰(2 0)] →_‣ normal! :test (→_[[[[3]]]]) ((+0)) :test (→_(→^(+42))) ((+42)) :test (→_(→^(-42))) ((-42)) # returns true if two balanced ternary numbers are equal # → ignores leading 0s! eq? [[abs 1 →^0]] ⧗ Number → Number → Boolean abs [0 z a⁻ a⁺ a⁰] z [=?(→_0)] a⁻ [[0 false [2 0] [false] [false]]] a⁺ [[0 false [false] [2 0] [false]]] a⁰ [[0 (1 0) [false] [false] [2 0]]] …=?… eq? # adds (+1) to a balanced ternary number (can introduce leading 0s) inc [~(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number z (+0) : (+1) a⁻ &[[↑⁻1 : ↑⁰1]] a⁺ &[[↑⁺1 : ↑⁻0]] a⁰ &[[↑⁰1 : ↑⁺1]] ++‣ inc :test (++(-42) =? (-41)) (true) :test (++(-1) =? (+0)) (true) :test (++(+0) =? (+1)) (true) :test (++(++(++(++(++(+0))))) =? (+5)) (true) :test (++(+42) =? (+43)) (true) # subtracts (+1) from a balanced ternary number (can introduce leading 0s) dec [~(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number z (+0) : (-1) a⁻ &[[↑⁻1 : ↑⁺0]] a⁺ &[[↑⁺1 : ↑⁰1]] a⁰ &[[↑⁰1 : ↑⁻1]] --‣ dec :test (--(-42) =? (-43)) (true) :test (--(+0) =? (-1)) (true) :test (--(--(--(--(--(+5))))) =? (+0)) (true) :test (--(+1) =? (+0)) (true) :test (--(+42) =? (+41)) (true) # adds two balanced ternary numbers (can introduce leading 0s) add [[abs 1 →^0]] ⧗ Number → Number → Number abs [c (0 z a⁻ a⁺ a⁰)] b⁻ [1 ↑⁺(3 0 t⁻) ↑⁰(3 0 t⁰) ↑⁻(3 0 t⁰)] b⁰ [1 ↑ (3 0 t⁰)] b⁺ [1 ↑⁰(3 0 t⁰) ↑⁻(3 0 t⁺) ↑⁺(3 0 t⁰)] a⁻ [[[1 (b⁻ 1) b⁻' b⁰ b⁻]]] b⁻' [1 ↑⁰(3 0 t⁻) ↑⁻(3 0 t⁰) ↑⁺(3 0 t⁻)] a⁺ [[[1 (b⁺ 1) b⁰ b⁺' b⁺]]] b⁺' [1 ↑⁺(3 0 t⁰) ↑⁰(3 0 t⁺) ↑⁻(3 0 t⁺)] a⁰ [[[1 (b⁰ 1) b⁻ b⁺ b⁰]]] z [[0 --(→_1) ++(→_1) →_1]] c [[1 0 t⁰]] …+… add :test ((-42) + (-1) =? (-43)) (true) :test ((-5) + (+6) =? (+1)) (true) :test ((-1) + (+0) =? (-1)) (true) :test ((+0) + (+0) =? (+0)) (true) :test ((+1) + (+2) =? (+3)) (true) :test ((+42) + (+1) =? (+43)) (true) # returns true if balanced ternary number is negative negative? t⁻? ∘ mst ⧗ Number → Boolean ?‣ positive? :test (>?(+0)) (false) :test (>?(-1)) (false) :test (>?(+1)) (true) :test (>?(+42)) (true) # negates a balanced ternary number negate [[[[[4 3 1 2 0]]]]] ⧗ Number → Number -‣ negate :test (-(+0)) ((+0)) :test (-(-1)) ((+1)) :test (-(+42)) ((-42)) # subtracts two numbers sub [[1 + -0]] ⧗ Number → Number → Number …-… sub # returns true if number is greater than other number gt? positive? ∘∘ sub ⧗ Number → Number → Boolean …>?… gt? :test ((+1) >? (+2)) (false) :test ((+2) >? (+2)) (false) :test ((+3) >? (+2)) (true) # returns eq, gt, lt depending on comparison of two numbers compare-case [[[[[go (1 - 0)]]]]] ⧗ a → b → c → Number → Number → d go [=?0 5 (>?0 4 3)] # ============================================================================ # # most relevant functions are defined - we can now derive from Generic/Number! # # ============================================================================ # :input std/Generic/Number # converts a balanced ternary number to a list of trits number→trits [0 z a⁻ a⁺ a⁰] ⧗ Number → (List Trit) z [[0]] a⁻ pair t⁻ a⁺ pair t⁺ a⁰ pair t⁰ :test (number→trits (+0)) ([[0]]) :test (number→trits (+5)) (t⁻ : (t⁻ : (t⁺ : [[0]]))) # strips leading 0s from a balanced ternary number strip [^(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number z (+0) : true a⁻ &[[↑⁻1 : false]] a⁺ &[[↑⁺1 : false]] a⁰ &[[(0 (+0) ↑⁰1) : 0]] %‣ strip :test (%[[[[0 3]]]]) ((+0)) :test (%[[[[2 (0 (0 (0 (0 3))))]]]]) ((-1)) :test (%(+42)) ((+42)) # negates a balanced ternary number if <0 abs [ substitute church numbers apply z [[[rec]]] ⧗ Number → (a → a) → a → a rec =?1 case-end case-apply case-apply 0 ∘ (2 --1 0) case-end i :test (apply (+5) ++‣ (+3)) ((+8)) # multplies two balanced ternary numbers (can introduce leading 0s) mul [[1 z a⁻ a⁺ a⁰]] ⧗ Number → Number → Number z (+0) a⁻ [↑⁰0 - 1] a⁺ [↑⁰0 + 1] a⁰ [↑⁰0] …⋅… mul :test ((+42) ⋅ (+0) =? (+0)) (true) :test ((-1) ⋅ (+42) =? (-42)) (true) :test ((+3) ⋅ (+11) =? (+33)) (true) :test ((+42) ⋅ (-4) =? (-168)) (true) # divs a balanced ternary number by two (binary >>1) div² [z [[[[rec]]]] (+0) 0 0] ⧗ Number → Number rec =?1 case-end case-div case-div 3 /³(2 + 0) /³1 0 case-end 2 /²‣ div² :test (/²(+6) =? (+3)) (true) :test (/²(-6) =? (-3)) (true) :test (/²(+5) =? (+2)) (true) # divs a balanced ternary number by three by fixing rshift /³*‣ [fix /³0] fix [/²(1 - 0)] :test (/³*(+6) =? (+2)) (true) :test (/³*(-6) =? (-2)) (true) :test (/³*(+5) =? (+1)) (true) # ceiled integer log₃ by counting number of trits # also counts leading 0s log₃* [0 (+0) inc inc inc] ⧗ Number → Number # ceiled integer log₃ by counting number of trits log₃ log₃* ∘ strip ⧗ Number → Number :test (log₃ (+0)) ((+0)) :test (log₃ (+5)) ((+3)) :test (log₃ (+42)) ((+5)) # returns the smallest number in a range such that a predicate is true binary-search z [[[[rec]]]] ⧗ (Number → Boolean) → Number → Number → Number rec (0 =? 1) case-end case-search case-search go /²(0 + 1) go [3 0 (4 3 2 0) (4 3 ++0 1)] case-end 0 :test (binary-search [(0 ⋅ 0) >? (+150)] (+0) (+100)) ((+13)) # returns the maximum of a unimodal function in a specified domain ternary-search z [[[[rec]]]] ⧗ (Number → Number) → Number → Number → Number rec (1 =? 0) case-end case-search case-search go (1 + /³*(0 - 1)) (0 - /³*(0 - 1)) call [=?0 (6 5 ++2 --1) (>?0 (6 5 4 --1) (6 5 ++2 3))] go [[call ((4 1) - (4 0))]] case-end 0 :test ((ternary-search [-((0 - (+3)) ⋅ (0 - (+3)))] (+0) (+5)) =? (+3)) (true) # pads a ternary number with 0s until it's as long a another ternary number pad y [[[(log₃* 0) ugly hacks with force+log₃) # TODO: remove the final `huh` correction step (probably some off-by-one bug?) # TODO: not actually that efficient right now quot-rem [[[[[z [[[[rec]]]] 1 (+0) 4]]] ?1 ⋀? 6) ⋁? (?1) fix (6 --5 2 1)] (8 add sub 1 6) fix 6 --5 0 (9 dec inc 1) lt [-0 >? 2 ⋁? (-0 =? 2 ⋀? ? 2] (+0) 1)]] ⧗ Number → Number → (Pair Number Number) go [0 : (2 - (1 ⋅ 0))] # divs two balanced ternary numbers div ^‣ ∘∘ quot-rem ⧗ Number → Number → Number …/… div :test ((+42) / (+4) =? (+10)) (true) :test ((+5) / (+3) =? (+1)) (true) :test ((-5) / (-3) =? (+1)) (true) :test ((-5) / (+3) =? (-2)) (true) :test ((+5) / (-3) =? (-2)) (true) # bad mod implementation using repeated subtraction mod* z [[[rec]]] ⧗ Number → Number → Number rec [=?0 0 (