fun/collatz.bruijn
# bruijn collatz.bruijn
# fun collatz implementation using binary abstract machine
# inspired by David Barina's algorithm
# adapted for LC by fusing certain operations and carefully choosing encodings and bases
# no dependence on std/Number/... because of golfing plans
:import std/Combinator .
# :import std/Number/Binary .
start (+01189998819991197253b)
# TODO: could we also strip leading zeroes here?
≠²!‣ [[[[3 z a¹ a⁰ k]]]] ⧗ Binary → Binary
z [0 3 3]
a¹ &[[[0 (4 1) (4 1)]]]
a⁰ &[[[0 2 (3 1)]]]
=²?‣ [0 [[1]] [[[0]]] [[[1]]]] ⧗ Binary → Bit
≠²?‣ [0 [[0]] [[[1]]] [[[0]]]] ⧗ Binary → Bit
↑¹‣ [[[[1 (3 2 1 0)]]]] ⧗ Binary → Binary
↑⁰‣ [[[[0 (3 2 1 0)]]]] ⧗ Binary → Binary
…↑… [[[[[4 1 0 (3 2 1 0)]]]]] ⧗ Bit → Binary → Binary
++‣ [0 z a¹ a⁰ ki] ⧗ Binary → Binary
z [0 (+0b) (+1b)]
a¹ &[[[0 ↑¹2 ↑⁰1]]]
a⁰ &[[[0 ↑⁰2 ↑¹2]]]
/²‣ [0 z a¹ a⁰ [[0]]] ⧗ Binary → Binary
z [0 (+0b) (+0b)]
a¹ &[[[0 ↑¹2 2]]]
a⁰ &[[[0 ↑⁰2 2]]]
# converts the normal binary representation into abstract
→^‣ [0 z a¹ a⁰] ⧗ Binary → AbstractBinary
z (+0b)
a¹ [[[[1 3]]]]
a⁰ [[[[0 3]]]]
# converts the abstracted binary representation back to normal
→_‣ y [[0 z a¹ a⁰]] ⧗ AbstractBinary → Binary
z (+0b)
a¹ [↑¹(2 0)]
a⁰ [↑⁰(2 0)]
# a + b
# TODO: can we do this without abstracting?
…+… [[abs 1 →^0]] ⧗ Binary → Binary → Binary
abs [c (0 z a¹ a⁰)]
c¹ [1 ↑⁰(3 0 [[1]]) ↑¹(3 0 [[0]])]
a¹ [[[1 (c¹ 1) c¹' c¹]]]
c¹' [1 ↑ (3 0 [[1]])]
a⁰ [[[1 (c⁰ 1) c¹ c⁰]]]
c⁰ [1 ↑ (3 0 [[0]])]
z [[0 ++(→_1) →_1]]
c [[1 0 [[0]]]]
=¹?‣ [0 z a¹ a⁰ [[1]]] ⧗ Binary → Binary
z [0 [[0]] [[1]]]
a¹ &[[[0 1 [[0]]]]]
a⁰ &[[[0 [[0]] [[0]]]]]
# interestingly, ≠²!(↑¹0 + 0) as a side effect strips leading zeroes, TODO: overhead?
# :test (=¹?(+1b)) ([[1]])
# :test (=¹?[[[1 (0 2)]]]) ([[1]])
# :test (=¹?[[[1 (0 (0 2))]]]) ([[1]])
# :test (=¹?[[[1 (0 (0 (0 2)))]]]) ([[1]])
:test (=¹?(+0b)) ([[0]])
:test (=¹?(+2b)) ([[0]])
:test (=¹?(+3b)) ([[0]])
:test (=¹?(+4b)) ([[0]])
:test (=¹?(+5b)) ([[0]])
:test (=¹?(+6b)) ([[0]])
:test (=¹?(+7b)) ([[0]])
:test (=¹?(+8b)) ([[0]])
:test (=¹?(+9b)) ([[0]])
:test (=¹?(+10b)) ([[0]])
collatz make-odd → (z [[rec]]) ⧗ Binary → Boolean
make-odd [=²?0 ≠²!(/²0) 0]
rec =¹?0 case-end case-rec
case-rec 1 ≠²!(↑¹0 + 0)
case-end [[1]]
odd-collatz z [[rec]] ⧗ Binary → Boolean
rec =¹?0 case-end case-rec
case-rec 1 ≠²!(↑¹0 + 0)
case-end [[1]]
main [collatz start]