[ prog / sol / mona ]

prog


e and the Stern-Brocot tree

1 2021-02-09 06:48

Found some Scheme code that I wrote when I was reading Concrete Mathematics

The Stern–Brocot tree was discovered independently by Moritz Stern (1858) and Achille Brocot (1861). Stern was a German number theorist; Brocot was a French clockmaker who used the Stern–Brocot tree to design systems of gears with a gear ratio close to some desired value by finding a ratio of smooth numbers near that value.

(text below from Concrete Mathematics)

The idea is to start with the two fractions (0/1, 1/0) and then to repeat the following opeation as many times as desired:

Insert (m + m')/(n + n') between two adjacent fractions m/n and m'/n'

The new fraction (m + m')/(n + n') is called the _mediant_ of m/n and m'/n'. For example, the first step gives us one new entry between 0/1 and 1/0:

0/1, 1/1, 1/0

and the next step gives two more

0/1, 1/2, 1/1, 2/1, 1/0

The next gives four more,

0/1, 1/3, 1/2, 2/3, 1/1, 3/2, 2/1, 3/1, 1/0

The entire array can be regarded as an infinite binary tree structure whose top levels look like this:

                          1          1           0
                          — - - - -  —  - - - -  —
                          0          1           1
                                  /     \
                                 /       \
                                /         \
                               /           \
                            1 /             \ 2
                            —                 —
                            2                 1
                          /   \             /   \
                         /     \           /     \
                        /       \         /       \
                       1         2       3         3
                       —         —       —         —
                       3         3       2         1
                      / \       / \     / \       / \
                     1   2     3   3   4   5     5   4
                     —   —     —   —   —   —     —   —
                     4   5     5   4   3   3     2   1

We can, in fact, regard the Stern-Brocot tree as a number system for representing rational numbers, because each positive, reduced fraction occurs exactly once. Let's use the letters L and R to stand for going down to the left or right branch as we proceed from the root of the tree to a particular fraction; then a string of L's and R's uniquely identifies a place in the tree. For example, LRRL means that we go left from 1/1 down to 1/2, then right to 2/3, then right to 3/4, then left to 5/7. The fraction 1/1 corresponds to the empty string, let's agree to call it I.

Graham, Knuth, Patashnik, Concrete Mathematics, Addison Wesley, 2nd ed. pp 115-123

2 2021-02-09 06:54

We define

S = a string of L's and R's
f(S) = fraction corresponding to S
M(S) = ((n m) (n' m')) = a 2x2 matrix that holds the four quantities involved in the ancestral fractions m/n and m'/n'
M(I) = ((1 0) (0 1))
M(SL) = M(S) . ((1 0) (1 1))
M(SR) = M(S) . ((1 1) (0 1))

Therefore, if we define L and R as 2x2 matrices,
L = ((1 0) (1 1))
R = ((1 1) (0 1))

In Scheme:

(define I '((1 0) (0 1)))
(define R  '((1 0) (1 1)))
(define L '((1 1) (0 1)))

While we're at it let's define a few useful operations.
Since we're representing matrices as lists, we'll need matrix multiplication

(define (mat-mul m1 m2)
  (map
   (lambda (row)
     (apply map (lambda column (apply + (map * row column))) m2))
   m1))

and conversion from the 2x2 matrix representation to rational number

(define (mat->rat mat)
  `(/ ,(+ (caadr mat) (cadadr mat)) ,(+ (caar mat) (cadar mat))))
3 2021-02-09 06:56

Irrational numbers don't appear in the Stern-Brocot tree, but all the rational numbers that are ``close'' to them do. We can find the infinite representation of an irrational number α with this procedure:

if α < 1 then (output(L); α := α / (1 - α))
         else (output(R); α := α - 1)

In Scheme

(define (brocot-string num steps)
  (letrec ((helper (lambda (num acc steps)
                     (cond ((equal? steps 0) (reverse acc))
                           ((< num 1) (helper (/ num (- 1 num)) (cons 'L acc) (- steps 1)))
                           (else (helper (- num 1) (cons 'R acc) (- steps 1)))))))
    (helper num '() steps)))

Now we can look for a regular pattern

> (brocot-string 2.7182818284590452353599104282424311632484 32)
'(R R L R R L R L L L L R L R R R R R R L R L L L L L L L L R L R)

In the Stern-Brocot system e = R²LR²LRL⁴RLR⁶LRL⁸RLR¹⁰LRL¹²....

We'll use infinite streams to represent this string. We start with the sequence of bases RLRLRL...

(require srfi/41)
(define bases (stream-cons R (stream-cons L bases)))

The sequence of exponents is (2,1,1,2,1,1,4,1,1,6,1,1,8,1,1,10...) You may recognize Euler's continued fraction https://oeis.org/A003417

(define exponents
  (stream-map
   (lambda (x)
     (cond ((equal? x 1) 2)
           ((equal? (modulo x 3) 0) (- x (/ x 3)))
           (else 1)))
   (stream-from 1)))

Now we just have to zip the two streams

(define exp-pairs (stream-zip bases exponents))

and we build the infinite sequence of rational approximations of e

(define-stream (exponentiate a b)
  (if (equal? b 0)
      empty-stream
      (stream-cons a (exponentiate a (- b 1)))))

(define-stream (make-e-seq pairs)
  (let ((a (cadr (stream-car pairs)))
        (b (car (stream-car pairs))))
    (if (equal? a 1)
      (stream-cons b (make-e-seq (stream-cdr pairs)))
      (stream-append (exponentiate b a) (make-e-seq (stream-cdr pairs))))))
      
(define e-seq (make-e-seq exp-pairs))

We define a function to calculate the nth rational approximation of e in our Stern-Brocot representation like this

(define (e ref)
  (mat->rat (stream-ref (stream-scan mat-mul I e-seq) ref)))

now let's test our code

> (require math/bigfloat)
> (bf-precision 100000)
> (time (bf (eval (e 1000000))))
cpu time: 3258 real time: 3260 gc time: 1711
(time (bf (eval (e 1000000))))
(bf #e2.7182818284590452353...)

Yields a result correct to 6331 digits. While far from being the most efficient way to approximate e, that was fun!

4 2021-02-09 07:56

What's the fraction 1/0 supposed to be?

5 2021-02-09 08:20

>>4
According to Donald Knuth

I guess 1/0 is infinity "in lowest terms"

0/1 and 1/0 do not belong to the Stern-Brocot language, they're only the ancestral fractions of the empty element 1/1. Scaffolding.

6 2021-02-09 11:00 *

This is not your personal blog.

7 2021-02-09 11:08 *

>>6
By far more /prog/ than the last 20 posts.

8 2021-02-09 11:22 *

In a similar spirit but not as advanced, including a small challenge at the end:
https://textboard.org/prog/34#t34p165

9 2021-02-09 12:14 *

>>7
Who cares, it is a wall of text and should be posted elsewhere.

10 2021-02-09 13:18 *

>>6,8
There were discussions here about Concrete Mathematics in the past, I thought someone might be interested in a Scheme implementation of cool clockmaker technologies.
But ok, I should have turned this into some kind of challenge like "let's post original ways to approximate e".
>>8
Missed that. Thanks.

11 2021-02-09 13:46 *

>>1
erratum

                          0          1           1
                          — - - - -  —  - - - -  —
                          1          1           0
                                  /     \
                                 /       \
                                /         \
                               /           \
                            1 /             \ 2
                            —                 —
                            2                 1
                          /   \             /   \
                         /     \           /     \
                        /       \         /       \
                       1         2       3         3
                       —         —       —         —
                       3         3       2         1
12 2021-02-09 14:19 *

>>9
You mean code walls of text that belong on /prog/ or refuting >>1-kun for having shit code walls of text that could be simpler and cleaner elegant code five liners at most?

13 2021-02-10 02:41 *

Some other nice patterns in the Stern-Brocot tree:

> (brocot-string (sqrt 2) 32)
'(R L L R R L L R R L L R R L L R R L L R R L L R R L L R R L L R)
> (brocot-string (sqrt 3) 32)
'(R L R R L R R L R R L R R L R R L R R L R R L R R L R R L R R L)
> (define phi (/ (+ 1 (sqrt 5)) 2))
> (brocot-string phi 32)
'(R L R L R L R L R L R L R L R L R L R L R L R L R L R L R L R L)
14 2021-02-10 12:46

>>13
What is the characterization of the subset of real numbers whose SB string expansion can be recognized by a FSM?

class SBtree:
   @ staticmethod
   def string (x):
      while x > 0:
         if x < 1:
            yield 'L'
            x = x / (1 - x)
         else:
            yield 'R'
            x = x - 1

   @ staticmethod
   def nstring (x, n):
      return ''.join (itertools.islice (SBtree.string (x), n))


>>> sb.SBtree.nstring (math.sqrt (2), 32)
'RLLRRLLRRLLRRLLRRLLRRLLRRLLRRLLR'
>>> sb.SBtree.nstring (math.sqrt (3), 32)
'RLRRLRRLRRLRRLRRLRRLRRLRRLRRLRRL'
>>> sb.SBtree.nstring (math.sqrt (5), 32)
'RRLLLLRRRRLLLLRRRRLLLLRRRRLLLLRR'
>>> sb.SBtree.nstring (math.sqrt (7), 32)
'RRLRLRRRRLRLRRRRLRLRRRRLRLRRRRLR'
>>> sb.SBtree.nstring ((1 + math.sqrt (5)) / 2, 32)
'RLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL'
>>> sb.SBtree.nstring (math.e, 32)
'RRLRRLRLLLLRLRRRRRRLRLLLLLLLLRLR'
>>> sb.SBtree.nstring (math.pi, 32)
'RRRLLLLLLLRRRRRRRRRRRRRRRLRRRRRR'
15 2021-02-10 14:34 *

>>14
I don't know if they have a name. The pattern of irrational number approximations in the Stern-Brocot tree is similar to the continued fraction, a more common notation than the Stern-Brocot tree sequences.

sqrt(2) = [1;2,2,2,2,2,...] (algebraic)
phi = [1;1,1,1,1,1,1,...] (algebraic)
e = [2;1,2,1,1,4,1,1,6,1,1,8,...] (transcendental)
cube root of 2 = [1;3,1,5,1,1,4,1,1,8,1,14,1,10,2,1,4,12,2,3,2...] (algebraic, non periodic CF)
π = [3;7,15,1,292,1,1,1,2,1,3,1,...] (transcendental, no known pattern)

My guess is that there's an infinite but countable number of regular patterns you can use to generate an irrational number. Since the set of irrational numbers is uncountable almost all continued fractions of irrational numbers have no pattern.

16 2021-02-11 00:27

I do appreciate this and would like to see more of these. But I would change the format a bit.
You could write the problem in the OP as a motivator, and a link to a literary .scm file with the solution.

17 2021-02-11 08:43 *

>>16
The guy doesn't care, he just writes down his stream of consciousness, and dumps it on the board.

18 2021-02-13 17:00

maybe verbose but I would rather see this than recycled memes complaining about rust

19 2021-02-14 07:41

rewrite Stern-Brocot tree in rust(lacks example)
http://rosettacode.org/wiki/Stern-Brocot_sequence

20 2021-02-14 09:03

>>19
And then try to do that once you have the sequence. This rational is an approximation of e.

> (time (e 1000000))
cpu time: 2995 real time: 2997 gc time: 1174
'(/
  340017086135953955237517024368071023319667336443292804743952295811218300447359859240275563254009942677431489707597147675747035681413226512627011095930560268265456381178976392711767087225557220527288583530246999554026111396756681847411034069691700458364305110849779785985479469458249422285136155670021333443718590111827401706503305002386802304743268641986242675018801066689637090293781703589884119797742595395970458469615457316464652161835058300625085365074839652205963909281728057007645884413972470559421095590641084923213749096077911891464157447244982848623998799902248659508491205347662407542487598477506176854976430107224759805723469500480207518560065060801139517286177001208163592054763542622442833088837014707870098680498790101406422989090225950831187269091905076078387996734933063315154563648844011105458348826524339618765836090847570234445324485311773505775960915934136456454684723065101560864875759072426638458977878476314281969987155314153269630993616187041722772926774199317277275408014196669434574127395283760934088304504454441826341472487028029542307844361121860169948845000863967607247499379959564922815018909507873427673764317550105676071503852510957626027913732521804089379035997601445017705811769908093393745107753664844766235361183695170527428489809363428463651419304155765399729238548589316792609372558848237780044857470539820865022763311896953342264917235482949907211105305961474199254134498023181661330808198705378200836895070871333229848624381644393862053739146946714031748697068394959781227898824577572717091477283125470687771132502660646193012227555089150091316446335434009362342321577385694092293349561432035238800308129504247688449971272567391760416476691624159595214779684041072400751170742699454671514147869612822126793025761288002185791555487625331998621292869836022457378328419035361513580174231044804345605326811465916238059290186883564724761265694886919748527987916817620628526399573566506494861425004396642032056780484911383385189989513516563131778797299221345966468968956122130938820067631844304729073653295278994294270111849584185735076742525508006069816526335483941312168466769941517563643711961854946980989175852514399703705680462519538562629390325716019370164673384882170485495116424556766549082251149470708965255450905049612453587859276129878129571158069679466773167708728881129438071391603459651281058662550128959761153549617728975030404264330537814833057633963701181617935774238987394896893837492212211374342977762904418298881285931234958814978103651305047589748736431989381870422496158486260942264340691466697262368432164893697234466153250046703893250452429139844480273241829106099238215033421990835160228005567092855709150858705097715014615303931593755514322351810007680897794492648609028769501447879692294277237362011716820403857042445580674191735659531498184966721518718160689953505802281847373678940279750467265390416599246074195127826056496476091242971985446723655542587173824287311438381591741110560862978217691099053628393417793105301826047059921235216516021504425461929120276377753800102305173326425003579123379528380303069690154701626211729549743364833186844412203484432054917804678030588228660410069011019359882579002
  125085295636436909683809909842556856885178429583466250503633118421625758576495571982549603221529371824249449947226736257956572986278847452327489918555893035992800158136526570747790366607976473974086490509833266140241624411002520378548860256844094890877496352409672412181476991240644660422957359119247812657697715895808101749155909929315560672524600833028834500581928675977242236292980202330265409027931557849262071183680232807134194663977226617526758164092581075236564819647024212853553521938166754805064971997583680157504280085693771587742124565102644454392184568192455131506363793673061697667809133470803909462294541130705110877585153688820760830173021946921156853394209265699621359388107424247279451921507178896866252151258182423463805654515203717737130171743215112991658603794371604988588191145881380551692440558754609581883970182436373351721827090765483767025558740593461170481647907645229692750706772617083777913648346892911751008260597754177442242884897528540552656654142051828032526143451856483844303282993772253401076047130518814970561671090962371290205074655269040331486455093397311641724716513914711853050343863410602433828186055109883845169168186241477852812819511630717226031782266261200943940615962914287809900772211847247623544281170759686802721987002900335098524747135307554944852406985163571494649355659613567838732869723194876669393386105031678437801228285473666870189915779831674530812838317813362749429334047728206554077502413410488307816529862238758762434688416460199490950423539362723027760398951127569670882323069657999986406666638536904433413611732504237085435613428187295322449920616488897190353761498046868750584302985283042516291072517661563543124917633435349040950215732545008269904452842072489224708167231629873428753864275250495686428820211229340636698055009463068010066247920722428973426571945857005028864658276369838400927087527667218274517604615390540969915685158805164446004960391637638952325069774576683392245223799253721839340049299692557960655127171880922366931873834678505507980929392029365039716768900191201134404082041954658457421412098953281935182415736165076549914653156936288250673567627314590360080813173455844097539997651557001995149793696142371449923446980427725864245921082517781640485031251339553931144656900391589822516702794312100705930445806007992360069962039035567107884172990813990752000736096406721872831171253639698564151167421533401665295128817139455342798715270038691942997621086685910211094868754454516817862989819051640051770874497216852913390188488061385723926005176343183394443750361968944989563225128221788985578992361222409045215774195773008647206524738774180554917621147514549299392328337681997169072439473578702176284273236998017086945818255227347039675511648057103771074013479256786923260298195015744892867688675269801389398308311777208591853723170164583690632297703927756753727378438541760265853399635262151837406060792526386670515259891008695811004879840637123479657107736250722757524021127684175490377871823327703940937023628221667804570593378320396524365465248186987504652311179460359354823215116827906074424119159403212171240501026466951623914101612248957295893464404775833237162234624918433172999)
21 2021-02-14 09:11

Also note that the if the stream exponents is Euler's continued fraction, the stream bases (RLRLRLRLRLRLR...) is nothing else than the golden ratio in our Stern-Brocot tree number system. So, if you want a rational approximation of Φ instead, just do this

> (define (Φ ref)
    (mat->rat (stream-ref (stream-scan mat-mul I bases) ref)))
> (time (Φ 10000))
cpu time: 33 real time: 34 gc time: 15
'(/
  88083137989997064605355872998857923445691333015376030932812485815888664307789011385238647061572694566755888008658862476758094375234981509702215595106015601812940878487465890539696395631360292400123725490667987980947195761919733084221263262792135552511961663188744083262743015393903228035182529922900769207624088879893951554938584166812233127685528968882435827903110743620870056104022290494963321073406865860606579792362403866826411642270661211435590340090149458419810817251120025713501918959350654895682804718752319215892119222907223279849851227166387954139546662644064653804466345416102543306712688251378793506564112970620367672131344559199027717813404940431009754143637417645359401155245658646088296578097547699141284451819782703782878668237441026255023475279003880007450550868002409533068098127495095667313120369142331519140185017719214501847645741030739351025342932514280625453085775191996236343792432215700850773568257988920265539647922172315902209901079830195949058505943508013044450503826167880993094540503572266189964694973263576375908606977788395730196227274629745722872833622300472769312273603346624292690875697438264265712313123637644491367875538847442013130532147345613099333195400845560466085176375175045485046787815133225349388996334014329318304865656815129208586686515835880811316065788759195646547703631454040090435955879604123186007481842117640574158367996845627012099571008761776991075470991386301988104753915798231741447012236434261594666985397841758348337030914623617101746431922708522824868155612811426016775968762121429282582582088871795463467796927317452368633552346819405423359738696980252707545944266042764236577381721803749442538053900196250284054406347238606575093877669323501452512412179883698552204038865069179867773579705703841178650618818357366165649529547898801198617541432893443650952033983923542592952070864044249738338089778163986683069566736505126466886304227253105034231716761535350441178724210841830855527586882822093246545813120624113290391593897765219320931179697869997243770533719319530526369830529543842405655495229382251039116426750156771132964376
  54438373113565281338734260993750380135389184554695967026247715841208582865622349017083051547938960541173822675978026317384359584751116241439174702642959169925586334117906063048089793531476108466259072759367899150677960088306597966641965824937721800381441158841042480997984696487375337180028163763317781927941101369262750979509800713596718023814710669912644214775254478587674568963808002962265133111359929762726679441400101575800043510777465935805362502461707918059226414679005690752321895868142367849593880756423483754386342639635970733756260098962462668746112041739819404875062443709868654315626847186195620146126642232711815040367018825205314845875817193533529827837800351902529239517836689467661917953884712441028463935449484614450778762529520961887597272889220768537396475869543159172434537193611263743926337313005896167248051737986306368115003088396749587102619524631352447499505204198305187168321623283859794627245919771454628218399695789223798912199431775469705216131081096559950638297261253848242007897109054754028438149611930465061866170122983288964352733750792786069444761853525144421077928045979904561298129423809156055033032338919609162236698759922782923191896688017718575555520994653320128446502371153715141749290913104897203455577507196645425232862022019506091483585223882711016708433051169942115775151255510251655931888164048344129557038825477521111577395780115868397072602565614824956460538700280331311861485399805397031555727529693399586079850381581446276433858828529535803424850845426446471681531001533180479567436396815653326152509571127480411928196022148849148284389124178520174507305538928717857923509417743383331506898239354421988805429332440371194867215543576548565499134519271098919802665184564927827827212957649240235507595558205647569365394873317659000206373126570643509709482649710038733517477713403319028105575667931789470024118803094604034362953471997461392274791549730356412633074230824051999996101549784667340458326852960388301120765629245998136251652347093963049734046445106365304163630823669242257761468288461791843224793434406079917883360676846711185597501)

This has very little to do with the code on the rosettacode's page, it's something fun from Concrete Mathematics

22 2021-02-23 23:44

>>21

cpu time: 33 real time: 34 gc time: 15

target 1.618033988749895
result 1.618033988749895
88083137989997064605355872998857923445691333015376030932812485815888664307789011385238647061572694566755888008658862476758094375234981509702215595106015601812940878487465890539696395631360292400123725490667987980947195761919733084221263262792135552511961663188744083262743015393903228035182529922900769207624088879893951554938584166812233127685528968882435827903110743620870056104022290494963321073406865860606579792362403866826411642270661211435590340090149458419810817251120025713501918959350654895682804718752319215892119222907223279849851227166387954139546662644064653804466345416102543306712688251378793506564112970620367672131344559199027717813404940431009754143637417645359401155245658646088296578097547699141284451819782703782878668237441026255023475279003880007450550868002409533068098127495095667313120369142331519140185017719214501847645741030739351025342932514280625453085775191996236343792432215700850773568257988920265539647922172315902209901079830195949058505943508013044450503826167880993094540503572266189964694973263576375908606977788395730196227274629745722872833622300472769312273603346624292690875697438264265712313123637644491367875538847442013130532147345613099333195400845560466085176375175045485046787815133225349388996334014329318304865656815129208586686515835880811316065788759195646547703631454040090435955879604123186007481842117640574158367996845627012099571008761776991075470991386301988104753915798231741447012236434261594666985397841758348337030914623617101746431922708522824868155612811426016775968762121429282582582088871795463467796927317452368633552346819405423359738696980252707545944266042764236577381721803749442538053900196250284054406347238606575093877669323501452512412179883698552204038865069179867773579705703841178650618818357366165649529547898801198617541432893443650952033983923542592952070864044249738338089778163986683069566736505126466886304227253105034231716761535350441178724210841830855527586882822093246545813120624113290391593897765219320931179697869997243770533719319530526369830529543842405655495229382251039116426750156771132964376
54438373113565281338734260993750380135389184554695967026247715841208582865622349017083051547938960541173822675978026317384359584751116241439174702642959169925586334117906063048089793531476108466259072759367899150677960088306597966641965824937721800381441158841042480997984696487375337180028163763317781927941101369262750979509800713596718023814710669912644214775254478587674568963808002962265133111359929762726679441400101575800043510777465935805362502461707918059226414679005690752321895868142367849593880756423483754386342639635970733756260098962462668746112041739819404875062443709868654315626847186195620146126642232711815040367018825205314845875817193533529827837800351902529239517836689467661917953884712441028463935449484614450778762529520961887597272889220768537396475869543159172434537193611263743926337313005896167248051737986306368115003088396749587102619524631352447499505204198305187168321623283859794627245919771454628218399695789223798912199431775469705216131081096559950638297261253848242007897109054754028438149611930465061866170122983288964352733750792786069444761853525144421077928045979904561298129423809156055033032338919609162236698759922782923191896688017718575555520994653320128446502371153715141749290913104897203455577507196645425232862022019506091483585223882711016708433051169942115775151255510251655931888164048344129557038825477521111577395780115868397072602565614824956460538700280331311861485399805397031555727529693399586079850381581446276433858828529535803424850845426446471681531001533180479567436396815653326152509571127480411928196022148849148284389124178520174507305538928717857923509417743383331506898239354421988805429332440371194867215543576548565499134519271098919802665184564927827827212957649240235507595558205647569365394873317659000206373126570643509709482649710038733517477713403319028105575667931789470024118803094604034362953471997461392274791549730356412633074230824051999996101549784667340458326852960388301120765629245998136251652347093963049734046445106365304163630823669242257761468288461791843224793434406079917883360676846711185597501
stack 6

$ python3 -m timeit -s 'import flake.sbtree as mod' 'mod.work_speclimit (mod.Specs.Phi (), 10000)'
10000 loops, best of 3: 137 usec per loop
23 2021-02-23 23:49
target 1.414213562373095
result 1.414213562373095
912372904077792820333022931514683905196095335332461243563566371630623725027756174840958798586146594892914095401037642377610054228482576727704110500231020662439134133236781589366415205524878535314722341540748126631282687462031097448656828645302597037940779004487605981247667669583729123395867583899548179259053671636594464946726564337037930617138893433544440429360350179319034433043179386253653890778056959564090099584131042792609171485551446220287193670064157175032113243945323799379335206189982084006721103924837454561272670000817253624301004165698525457461249517756759114499889703222149412160665301694111168795976530493998573585466679141412035628294794135220268925566327084096717726075716622819757810639450486297919988578046158833828525325469062759563222180775691512072690399043415592162621696366117965993334661822419744848270408206137218896579046774810149448397093592171548356413795629132503305148903487947415107183019346627904110216664835865582002041482574392065817955357317802858225690925207376993605542582914690980260418563086534219739082870274044629514790108045021964648588957147877553335242189622725230861151908928597780357076966509346517444159661044195373532127149501448465623900205359156173053520045633506497748488413010211676218187024245944636731897289083327716265252592579848721079948056891537057074054078404059256984291844030570801386300484362165471294405751570533709092619045671164240921912086888637832641806419666332796920984444963799864385789395922731763421593489233820681623305468082385959617126639107953866786715082681199375295298398342516439245368301352147472945010786588515500962019666031356507887402263555290987070386890083958938515638981902578172203283552384977890173501578909020338496992971143893003367573490861994803868623180409853340292013727017820739449406566091157326121807628137523647618653406547187947774090879311484132159187408769424091732434374817993103851978756820565200612073505393
645145067444270761356716481857445357641649553114979126977678963754439951082038984632678061418130657858763297544529821984444895464626862603691739802477466631503873767432694953865148667058442664481918025121653166100343954869841332731542457362834113318740074258352418751185500785071084474652030341872751114517691124799298946476356463130421256001538326419686685024658804199090849748412873447604535750572396245530424783088241899918727047006913682721495224443247600409827124799470185578822892780248099201063388167346497317474442071198019623551456189630759811865831617485719078716492727748680645636681156261142523348830419155615693078563602052074308536791767398023563062654117446029432097791614030894600205918745588000027749241499556416620236383481141542139618267239995908984466111486647077115808307902368887069463321555768022390997259037097147923161550796376448633639191058160377727679526847368225829716455421516498274839007505526603632830905156575689466421113905804893041617407988995957582361699110853657191118269861280913215596304247181727470222880786012786174601277208667732522083157085633502053869442681988756433014137552047292645249667623080960158029307041797974528005411231083666859195730472054478916752735859020924743323704976823318050126745409118196223466719223339522073412802366352813857415809629646773071321021322915809378632028416028413299468319362402530515502588589399067652778615784607050131186014530406266363654361196873709332572288106710280508411833502919921220462451339963101921144001361401160661249966470252485720782595383560914505654141717325381005598727773686382562943798678618507388289518297731421477986248887295505359290084507833070865662747168546322649930506385522948488952975319520205239729675192003571242819758609748037543641240137577371696785255726670121334640733501179715052678269583483097831741247328687771258281063372501649165518987809812008399308777781407031699396066250798983206988348120665
stack 6

$ python3 -m timeit -s 'import flake.sbtree as mod' 'mod.work_speclimit (mod.Specs.Sqrt2 (), 10000)'
10000 loops, best of 3: 121 usec per loop
24 2021-02-23 23:53
target 1.732050807568877
result 1.732050807568877
37333050739547620284741346177443232768419828695576483192119227709011874720867558339004144048908608643954187575967122760016462436597149422351883158769394191023679913703570251600882068481387414359397619517424061973492935942203954445483788494431222578988497811330117180887243303058687612115480389195262103976386982801547226241736184765087358487101684839240435787719763032119054686805648308753341087388646696533367579871775911044407929199778666970896621939895063461817937810347316850879892599866435706231219754394830144519751453447850442566201884566425006242081130213811073324017618229313206662953896117018758439730158342409695682744685435055507681964742791636723618042926447421832733978027037356893003642400795083277917572826017744015949356157886964966927490914775661127518930358507018785066186644947170327972057946083883044850852277818698118365103260660825088738036827240142991301488107222873963750819769771904654194225287688794059905383024205725563175121133535944182786005199341008982313788920025582392443629294875181601118908847120206222270984968236498764086338625250980712437368193355490705121246779227656912224111729593933533272780650483740863985497980606931536674447177718482803533891496589890376318229724885453329711793624837676433843135324083030155160267058536032981571743325390625805043153062883213991856782364670780605229622859726138556007967627528794502411945065099156358124051734768863065914792552486457279065577226417382681617126063892480294139719789670858396610321459720941260501653332523601524041423566189024845550000941398132271344064174395659569621527186657227534096104268698881663551635501366925200893982635208764415188639236599527755755220572368830848307065718490436530312669439969677316707180302233189875768562448229382203076191884103142375500528208253188467810619697091413712152142298355067830147049981234594952906086026836206347827204014637887719424320921238973858066084698096953687711047
21554246894147775797650832578303319263028404773092017926791774965040179802055156425720667289665504525915863815507020606442822591122943147707530277952196331686389340468052522281951900764255429081274790186257286268230621724824017922276471739177768334695384953697871877837881155031465359055028538862532846056226236947786925864165196534881747615168645767076159981751248460569675652894545741239891833300198605315822337729504784372003441206061759695669624704595618478359792979354122596033333248015656636731973572897856628025650797008826972131622163470243837577196348969655965538229305259367543808617363175028855903945171232070605035695614607015184689952951586312421207546531341892706569271601923463595043791163292377687138580802118407026421147932224182625632590924856698714323013638768197141356547467582293140034400356391974440346504311412439829638421716251542120579618728973231768592667750073773590267419218843931830221497884407792589017184003540992191405403034918783995177085651898934538952701703076197715837649791991627458931196137767975686601141239200515090942654152115666835346260740768607950637521722151011656654374992897516330417865006506372510681289630018666381838777552937120944730239512806638205231951609646164304538015782410981802569959188173997031855775431753188170602372552800771539717805865719257089560105167973807987552658427273583942730449293553775055987686609702926083577493656009021484804414735012057096501093436794050801716970153395976595414469165021583793220009073307292114697925615393562085411284136700452395376891838361636625895532086290413315475775102695473088715260812363265582034603291944111937827403421961367979542615557894681375864831794298679205586154133397902722523733839564466051081942627041120700837220749704695868172599837356090872581186433799610358187908547841059944683830596399048437391260574434794830712097077693113271446484457383044766723608216668485987749656447980544044121356
stack 7

$ python3 -m timeit -s 'import flake.sbtree as mod' 'mod.work_speclimit (mod.Specs.Sqrt3 (), 10000)'
10000 loops, best of 3: 127 usec per loop
25 2021-02-23 23:56
target 2.236067977499790
result 2.236067977499790
41332294493938545531741898189124475002595083290489742271982042410001179649590638352971327178662782342658715702623030919737457907830190691919815009012258506376641135023825853565815239172591664165125213495590102205194513046640807952860130344653843839739939014372203482062252430269007112899956699379555747989512246507615679658302303597205403785255823841691991082530008399436256706957923656044401564042746883350613913909297196677594960296197551329608870980667422294986691904386738935339267820859141352189405773882440494245555502768587027398841266564236644931168995594325256768307938601042996121095218241154575833662343043702732992390353103692853602670343958004075610587622455232284763903928028648731969351298672275652254240329774371782479484528772043935076738418647432348313216320003488034702089990883852569243503909749609181481316530786070722847681935414366840677535822771205760207869055158774687324451786213766720466147055533425266225306535307310450569765855050917117310080021623332198083686457831950357034237316279546694295104672547709923461351337599635696874489909962163561569998895704141643514246636570145413107594734738158346892744164182479359093299630818413585724011399825669588321391668100430142680865137048656972350481497356791937266235756440335503077080610088030645733619795947172505340600403178545449010069030779945613043875596021032181052174542895568049342840041819628616283091446792264365775194267951629158048818995367725670881481269134411330911655910252452531346900379867176605513744986701481901397038137684255542940091075132568064399281896930450391998725001
18484364030897371437300920331810666605620710023854620676063981218524652362414027825042685017628799482783457930163920239444169022341244320998258403142770892372144915632343436000992920792602361123265031091519899666493465827806254868440765822317542750159888888783785299054848253120329811978818108194558415103032630528570493513177986315310466471480532082979588479340324654453261594178812021489384865926085887335446285369050537228888493984139295507672130875197799909665706437635949989954884651880162170248896892053994937480676824100235778078258089007324143972798519797707032130647969884610321425997189568119602840375894038155972908248004382498468916557706979429998716578160611084323023757946616513714721274482895333064156415741467388984618053241491703589401980162709229995190315146112057114148528371268073240697867276018185731510023421667460054167043946189996319239451804850583222207623709979312120485235589607032199701387734728901493075402111739944241663097291682065128415467408794012133045576298823323231644319444771309101979838714607268362885013353236236279028547075826693271711076508425978753112672873471483112345162587327323284559170894801540946256076581492385877327920830212228117773961574323020309037154581962604279919770924565083410929733620139585525373839607694142835671049697791915617732496134164500439645102443987515076670635346496272691715990210824938942259376967327736103437367741646251904790549748690944569347164625686510650942902612493691144502089014530540918554198933184653476942446080685583723088707560004626657585412385543184301378502185399284958449745001
stack 6

$ python3 -m timeit -s 'import flake.sbtree as mod' 'mod.work_speclimit (mod.Specs.Sqrt5 (), 10000)'
10000 loops, best of 3: 93.6 usec per loop
26 2021-02-23 23:58
target 2.645751311064591
result 2.645751311064591
88685109179915130341887104907585686521847537035156964074461380628433449732421486996699064062444540064158389056209363824310211054734553092226299945457021199112700497855553114289504071487912489870285448166897774268426045437736838881291135766978714310577197146720994928482690407035258346866833661597831052596381967292664054207176771296004452023561901916859428680387946648537327818721735456944347866760599816478742091731402036923914749011584466135017369187496638702604704904099567360882401992490615065358974108247116798594573520556021596510768434830377703395683058096577446210575258033599847116433595329505939001912158627483541548413908052794044326067277738229833351839833732621914148391648757352594454100888285735908886235371717556569350093976323499838384402503010849693022056133132459889455774624180654855740421068215212274465740819478763364431816220680747532316564598964601291404834137936045821906603748156817494328651241872320246841849963968760441611551680171915171870107132895649133384251789520357115932060244542818093510776757680312455843828454609567341874249691543056825373273269204071745454267556076788350083854242116696619839481745027404336920399635197690200093935910164689111311839586735442346668112486814384577793261763215032118149485337833479163988065715333603367509804484339306442650722582405639197507565528586654028311449710723867519836823306113282478980440642161464033492837646551961460316452507922119182266791487068039633701371545426504396858443073658611354269445043000296653262607719089598658043789113954673633318703927713435275149460809489273849788240351191345839326411839428019773563791946938637627130882929019426915426450059256851311863911361172986681994529441158570079902956177659085523863706292659368
33519820554952402077344952617115996430062602096298132910527390831423668803224786792409482114736441464414434466600804779984731735712635377260497095812209531262037812938763480625651274971130960829211892715611645468602169701448987251532767391210039108389525077224714582291644331715154178763831397834298494044533585708820980314756995071855712127833971373932571326174459953709149532727724636735804897739228824429719381518007647530374783592205329481298090989741894174116420193651705325603383474062569368008883036209486064571228798270612570245995726989027981078917804184187499121621704880192862070899839335763600538337612503028675222083143790259516383967477391105199604260172432581074516295386295207443781246839223963989741293797783635987581484624039801831036560454434936317427599590411496224537788272692769212532372138459731579486311965568423854036095144587150585857725218696351547762091779862472592476271252396689972340657268628812154795429091581895847878967677044235215574631131931485165870936334656348188917546216466160109951993701418977615343196637062373754515878578286200786667708184435930028647016106141546838211875075480787744084715947501964293329801736675201320126556780597972877755791737287370240036747650626088972123685671173383351988672241516353767982686940196092077710683695881056812441315674315369699222038356904379301779532128607451321996820067317087887933988110334316185513431274490816808887993078291114719390594741039617560489171670668108767799640798842133852400136686687954287968401830668881914079204844843027519987932569505672423814843276175818680085566684747600593430391192915923373560623197517985154594912997008324835735525214421317644885339320934402944417757163610788379320383776665001229589830530087683
stack 7

$ python3 -m timeit -s 'import flake.sbtree as mod' 'mod.work_speclimit (mod.Specs.Sqrt7 (), 10000)'
10000 loops, best of 3: 120 usec per loop
27 2021-02-24 00:29

[1/2]

import math


# 0 1   a c   a a+c   1 1   a+c c   1 0
# 1 0   b d   b b+d   0 1   b+d d   1 1
class Matrix:
   I = [1, 0, 0, 1]
   S = [0, 1, 1, 0]
   L = [1, 1, 0, 1]
   R = [1, 0, 1, 1]

   @ staticmethod
   def new ():
      return [None] * 4

   @ staticmethod
   def copy (m):
      return m [:]

   @ staticmethod
   def copyinto (msrc, mdst):
      mdst [:] = msrc

   @ staticmethod
   def pair (m):
      return (m [0] + m [1], m [2] + m [3])

   @ staticmethod
   def mul (m1, m2, mout):
      mout [0] = m1 [0] * m2 [0] + m1 [1] * m2 [2]
      mout [1] = m1 [0] * m2 [1] + m1 [1] * m2 [3]
      mout [2] = m1 [2] * m2 [0] + m1 [3] * m2 [2]
      mout [3] = m1 [2] * m2 [1] + m1 [3] * m2 [3]


class Stack:
   @ staticmethod
   def alloc (size, matrixclass):
      new = matrixclass.new
      return [new () for k in range (size)]

   @ staticmethod
   def ensure (stack, need, matrixclass):
      have = len (stack)
      if have < need:
         stack.extend (Stack.alloc (need - have, matrixclass))


class Expo:
   @ staticmethod
   def bits (m, exp, mstack, stackpos, matrixclass):
      MC = matrixclass

      if exp < 1:
         MC.copyinto (MC.I, mstack [stackpos])
         return

      if exp == 1:
         MC.copyinto (m, mstack [stackpos])
         return

      outnow     = stackpos
      outother   = stackpos + 1
      powernow   = stackpos + 2
      powerother = stackpos + 3
      div, mod   = divmod (exp, 2)
      left       = div
      mul        = MC.mul

      Stack.ensure (mstack, stackpos + 4, MC)
      MC.copyinto (m, mstack [powernow])
      MC.copyinto (m if mod else MC.I, mstack [outnow])

      while left:
         div, mod = divmod (left, 2)
         left     = div
         mul (mstack [powernow], mstack [powernow], mstack [powerother])
         powernow, powerother = powerother, powernow
         if mod:
            mul (mstack [outnow], mstack [powernow], mstack [outother])
            outnow, outother = outother, outnow

      if outnow != stackpos:
         MC.copyinto (mstack [outnow], mstack [stackpos])


# context
#    stack
#    matrixclass
class Group:
   @ classmethod
   def kind (cls):
      pass

   def eval (self, ctx, stackpos):
      pass


class EmptyGroup (Group):
   @ classmethod
   def kind (cls):
      return "empty"

   def eval (self, ctx, stackpos):
      MC    = ctx ["matrixclass"]
      stack = ctx ["stack"      ]
      MC.copyinto (MC.I, stack [stackpos])


class FixedGroup (Group):
   @ classmethod
   def kind (cls):
      return "fixed"

   def __init__ (self, fixedstr):
      self.fixedstr = fixedstr

   def eval (self, ctx, stackpos):
      MC    = ctx ["matrixclass"]
      stack = ctx ["stack"      ]
      fs    = self.fixedstr
      count = len (fs)

      if count < 1:
         MC.copyinto (MC.I, stack [stackpos])
         return

      sym = {'L': MC.L, 'R': MC.R}

      if count == 1:
         MC.copyinto (sym [fs], stack [stackpos])
         return

      div, mod = divmod (count - 1, 2)

      if mod:
         now   = stackpos + 1
         other = stackpos
      else:
         now   = stackpos
         other = stackpos + 1

      Stack.ensure (stack, stackpos + 2, MC)
      mnow   = stack [now  ]
      mother = stack [other]
      MC.copyinto (sym [fs [0]], mnow)
      mul    = MC.mul
      fspos  = 1

      for k in range (div):
         mul (mnow,   sym [fs [fspos    ]], mother)
         mul (mother, sym [fs [fspos + 1]], mnow)
         fspos += 2

      if mod:
         mul (mnow, sym [fs [fspos]], mother)
28 2021-02-24 00:31

[2/2]

class ListGroup (Group):
   @ classmethod
   def kind (cls):
      return "list"

   def __init__ (self, groups):
      self.groups = groups

   def eval (self, ctx, stackpos):
      MC    = ctx ["matrixclass"]
      stack = ctx ["stack"      ]
      gs    = self.groups
      count = len (gs)

      if count < 1:
         MC.copyinto (MC.I, stack [stackpos])
         return

      if count == 1:
         gs [0].eval (ctx, stackpos)
         return

      div, mod = divmod (count - 1, 2)

      if mod:
         now   = stackpos + 1
         other = stackpos
      else:
         now   = stackpos
         other = stackpos + 1

      Stack.ensure (stack, stackpos + 3, MC)
      factor  = stackpos + 2
      mfactor = stack [factor]
      mnow    = stack [now   ]
      mother  = stack [other ]
      gs [0].eval (ctx, now)
      mul     = MC.mul
      gspos   = 1

      for k in range (div):
         gs [gspos    ].eval (ctx, factor)
         mul (mnow,   mfactor, mother)
         gs [gspos + 1].eval (ctx, factor)
         mul (mother, mfactor, mnow)
         gspos += 2

      if mod:
         gs [gspos].eval (ctx, factor)
         mul (mnow, mfactor, mother)


class ExpoGroup (Group):
   @ classmethod
   def kind (cls):
      return "expo"

   def __init__ (self, base, expo, *, alwaysevalbase = False):
      self.base           = base
      self.expo           = expo
      self.alwaysevalbase = alwaysevalbase

   def eval (self, ctx, stackpos):
      MC     = ctx ["matrixclass"]
      stack  = ctx ["stack"      ]
      base   = self.base
      expo   = self.expo
      always = self.alwaysevalbase

      if (expo < 1) and not always:
         MC.copyinto (MC.I, stack [stackpos])
         return

      Stack.ensure (stack, stackpos + 2, MC)
      base.eval (ctx, stackpos)
      Expo.bits (stack [stackpos], expo, stack, stackpos + 1, MC)
      MC.copyinto (stack [stackpos + 1], stack [stackpos])


class Spec:
   @ classmethod
   def kind (cls):
      pass

   @ classmethod
   def targetfloat (cls):
      pass


class StarSpec (Spec):
   @ classmethod
   def kind (cls):
      return "star"

   def __init__ (self, group):
      self.group = group


class Compiler:
   @ staticmethod
   def fixedlimit (spec, limit):
      what = spec.kind ()
      ret  = getattr (Compiler, "fixedlimit_" + what) (spec, limit)
      return ret

   @ staticmethod
   def fixedlimit_star (spec, limit):
      if limit < 1:
         return {
            "group": EmptyGroup (),
            "count": 0,
         }

      g    = spec.group
      what = g.kind ()

      if what != "fixed":
         raise ValueError (what)

      fs    = g.fixedstr
      fslen = len (fs)

      if fslen < 1:
         raise ValueError (fslen)

      div, mod = divmod (limit, fslen)

      if mod:
         h = ListGroup ([
            ExpoGroup (g, div),
            FixedGroup (fs [:mod])])
      else:
         h = ExpoGroup (g, div)

      return {
         "group": h,
         "count": limit,
      }


class Specs:
   class Phi (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return (1 + math.sqrt (5)) / 2

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RL"))

   class Sqrt2 (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return math.sqrt (2)

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RLLR"))

   class Sqrt3 (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return math.sqrt (3)

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RLR"))

   class Sqrt5 (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return math.sqrt (5)

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RRLLLLRR"))

   class Sqrt7 (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return math.sqrt (7)

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RRLRLRR"))


def work_speclimit (spec, limit):
   log    = print
   M      = Matrix
   C      = Compiler
   slots  = 2
   mstack = Stack.alloc (slots, M)
   target = spec.targetfloat ()
   ctx    = {
      "matrixclass": M,
      "stack":       mstack,
   }

   log ("target {:.15f}".format (target))

   ret   = C.fixedlimit (spec, limit)
   group = ret ["group"]
   group.eval (ctx, 1)
   M.mul (M.S, mstack [1], mstack [0])
   a, b  = M.pair (mstack [0])

   log ("result {:.15f}".format (a / b))
   log ("{:d}".format (a))
   log ("{:d}".format (b))
   log ("stack {:d}".format (len (mstack)))
29 2021-02-24 08:40 *

Is there anything more ugly than inserting whitespace before the opening parenthesis?

30 2021-02-24 11:37

>>29
not using lisp scheme and instead algol

31 2021-02-24 16:37

>>30
True

32 2021-02-25 01:38

>>20

cpu time: 2995 real time: 2997 gc time: 1174

 group List (Fixed RRLRR, List (Loop (498, List (Store (a, List (Load (a, Fixed LR), Load (l4, Fixed LLLL))), Store (b, List (Load (b, Fixed RLRR), Load (r4, Fixed RRRR))))), List (Fixed LR, Expo (Fixed L, 1996), Fixed RL, Expo (Fixed R, 999))))
target 2.718281828459045
result 2.718281828459045
340017086135953955237517024368071023319667336443292804743952295811218300447359859240275563254009942677431489707597147675747035681413226512627011095930560268265456381178976392711767087225557220527288583530246999554026111396756681847411034069691700458364305110849779785985479469458249422285136155670021333443718590111827401706503305002386802304743268641986242675018801066689637090293781703589884119797742595395970458469615457316464652161835058300625085365074839652205963909281728057007645884413972470559421095590641084923213749096077911891464157447244982848623998799902248659508491205347662407542487598477506176854976430107224759805723469500480207518560065060801139517286177001208163592054763542622442833088837014707870098680498790101406422989090225950831187269091905076078387996734933063315154563648844011105458348826524339618765836090847570234445324485311773505775960915934136456454684723065101560864875759072426638458977878476314281969987155314153269630993616187041722772926774199317277275408014196669434574127395283760934088304504454441826341472487028029542307844361121860169948845000863967607247499379959564922815018909507873427673764317550105676071503852510957626027913732521804089379035997601445017705811769908093393745107753664844766235361183695170527428489809363428463651419304155765399729238548589316792609372558848237780044857470539820865022763311896953342264917235482949907211105305961474199254134498023181661330808198705378200836895070871333229848624381644393862053739146946714031748697068394959781227898824577572717091477283125470687771132502660646193012227555089150091316446335434009362342321577385694092293349561432035238800308129504247688449971272567391760416476691624159595214779684041072400751170742699454671514147869612822126793025761288002185791555487625331998621292869836022457378328419035361513580174231044804345605326811465916238059290186883564724761265694886919748527987916817620628526399573566506494861425004396642032056780484911383385189989513516563131778797299221345966468968956122130938820067631844304729073653295278994294270111849584185735076742525508006069816526335483941312168466769941517563643711961854946980989175852514399703705680462519538562629390325716019370164673384882170485495116424556766549082251149470708965255450905049612453587859276129878129571158069679466773167708728881129438071391603459651281058662550128959761153549617728975030404264330537814833057633963701181617935774238987394896893837492212211374342977762904418298881285931234958814978103651305047589748736431989381870422496158486260942264340691466697262368432164893697234466153250046703893250452429139844480273241829106099238215033421990835160228005567092855709150858705097715014615303931593755514322351810007680897794492648609028769501447879692294277237362011716820403857042445580674191735659531498184966721518718160689953505802281847373678940279750467265390416599246074195127826056496476091242971985446723655542587173824287311438381591741110560862978217691099053628393417793105301826047059921235216516021504425461929120276377753800102305173326425003579123379528380303069690154701626211729549743364833186844412203484432054917804678030588228660410069011019359882579002
125085295636436909683809909842556856885178429583466250503633118421625758576495571982549603221529371824249449947226736257956572986278847452327489918555893035992800158136526570747790366607976473974086490509833266140241624411002520378548860256844094890877496352409672412181476991240644660422957359119247812657697715895808101749155909929315560672524600833028834500581928675977242236292980202330265409027931557849262071183680232807134194663977226617526758164092581075236564819647024212853553521938166754805064971997583680157504280085693771587742124565102644454392184568192455131506363793673061697667809133470803909462294541130705110877585153688820760830173021946921156853394209265699621359388107424247279451921507178896866252151258182423463805654515203717737130171743215112991658603794371604988588191145881380551692440558754609581883970182436373351721827090765483767025558740593461170481647907645229692750706772617083777913648346892911751008260597754177442242884897528540552656654142051828032526143451856483844303282993772253401076047130518814970561671090962371290205074655269040331486455093397311641724716513914711853050343863410602433828186055109883845169168186241477852812819511630717226031782266261200943940615962914287809900772211847247623544281170759686802721987002900335098524747135307554944852406985163571494649355659613567838732869723194876669393386105031678437801228285473666870189915779831674530812838317813362749429334047728206554077502413410488307816529862238758762434688416460199490950423539362723027760398951127569670882323069657999986406666638536904433413611732504237085435613428187295322449920616488897190353761498046868750584302985283042516291072517661563543124917633435349040950215732545008269904452842072489224708167231629873428753864275250495686428820211229340636698055009463068010066247920722428973426571945857005028864658276369838400927087527667218274517604615390540969915685158805164446004960391637638952325069774576683392245223799253721839340049299692557960655127171880922366931873834678505507980929392029365039716768900191201134404082041954658457421412098953281935182415736165076549914653156936288250673567627314590360080813173455844097539997651557001995149793696142371449923446980427725864245921082517781640485031251339553931144656900391589822516702794312100705930445806007992360069962039035567107884172990813990752000736096406721872831171253639698564151167421533401665295128817139455342798715270038691942997621086685910211094868754454516817862989819051640051770874497216852913390188488061385723926005176343183394443750361968944989563225128221788985578992361222409045215774195773008647206524738774180554917621147514549299392328337681997169072439473578702176284273236998017086945818255227347039675511648057103771074013479256786923260298195015744892867688675269801389398308311777208591853723170164583690632297703927756753727378438541760265853399635262151837406060792526386670515259891008695811004879840637123479657107736250722757524021127684175490377871823327703940937023628221667804570593378320396524365465248186987504652311179460359354823215116827906074424119159403212171240501026466951623914101612248957295893464404775833237162234624918433172999
stack 12

$ python3 -m timeit -s 'import flake.sbtree as mod' 'mod.work_speclimit (mod.Specs.E (), 1000000)'
100 loops, best of 3: 4.5 msec per loop
33 2021-02-25 11:07

Spec for the e stream:

class StamploopSpec (Spec):
   @ classmethod
   def kind (cls):
      return "stamploop"

   def __init__ (self, stamp):
      self.stamp = stamp

   def stamplength (self, index):
      pass

   def tailgroup (self, index):
      pass


def work_loadstore_repeat ():
   return ListGroup ([
      StoreGroup ("a", ListGroup ([
         LoadGroup ("a", FixedGroup ("LR")),
         LoadGroup ("l4", FixedGroup ("LLLL"))])),
      StoreGroup ("b", ListGroup ([
         LoadGroup ("b", FixedGroup ("RLRR")),
         LoadGroup ("r4", FixedGroup ("RRRR"))]))])


class EStamp (StamploopSpec):
   def __init__ (self):
      StamploopSpec.__init__ (self,
         work_loadstore_repeat ())

   def stamplength (self, index):
      return 14 + 8 * index

   def tailgroup (self, index):
      return ListGroup ([
         FixedGroup ("LR"),
         ExpoGroup (FixedGroup ("L"), 4 + 4 * index),
         FixedGroup ("RL"),
         ExpoGroup (FixedGroup ("R"), 6 + 4 * index)])


class Specs:
   class E (ListGroup):
      @ classmethod
      def targetfloat (cls):
         return math.e

      def __init__ (self):
         ListGroup.__init__ (self, [
            FixedGroup ("RRLRR"), EStamp ()])
34 2021-02-25 12:57

The daily code-dump is much appreciated.

35 2021-02-25 21:00

The additional building blocks used by the e spec:

# context
#    stack
#    matrixclass
#    storage
class Group:
   @ classmethod
   def kind (cls):
      pass

   def eval (self, ctx, stackpos):
      pass

   def show (self):
      pass

   def isfixed (self):
      pass

   def fixedlength (self):
      pass


class LoopGroup (ListGroup):
   class Loop:
      def __init__ (self, count, item):
         self.count = count
         self.item  = item

      def __len__ (self):
         return self.count

      def __getitem__ (self, key):
         return self.item
         # no slicing

   @ classmethod
   def kind (cls):
      return "loop"

   def __init__ (self, count, group):
      ListGroup.__init__ (self, LoopGroup.Loop (count, group))
      self.count = count
      self.group = group

   def show (self):
      return "Loop ({}, {})".format (self.count, self.group.show ())

   def isfixed (self):
      return self.group.isfixed ()

   def fixedlength (self):
      return self.count * self.group.fixedlength ()


class LoadGroup (Group):
   @ classmethod
   def kind (cls):
      return "load"

   def __init__ (self, name, fallback):
      self.name     = name
      self.fallback = fallback

   def eval (self, ctx, stackpos):
      MC      = ctx ["matrixclass"]
      stack   = ctx ["stack"      ]
      storage = ctx ["storage"    ]
      name    = self.name
      value   = storage.get (name)

      if value is None:
         self.fallback.eval (ctx, stackpos)
         storage [name] = MC.copy (stack [stackpos])
      else:
         MC.copyinto (value, stack [stackpos])

   def show (self):
      return "Load ({}, {})".format (self.name, self.fallback.show ())

   def isfixed (self):
      return False

   def fixedlength (self):
      raise Wrong


class StoreGroup (Group):
   @ classmethod
   def kind (cls):
      return "store"

   def __init__ (self, name, group):
      self.name  = name
      self.group = group

   def eval (self, ctx, stackpos):
      MC      = ctx ["matrixclass"]
      stack   = ctx ["stack"      ]
      storage = ctx ["storage"    ]
      name    = self.name
      group   = self.group

      group.eval (ctx, stackpos)
      # after
      m = storage.get (name)

      if m is None:
         storage [name] = MC.copy (stack [stackpos])
      else:
         MC.copyinto (stack [stackpos], m)

   def show (self):
      return "Store ({}, {})".format (self.name, self.group.show ())

   def isfixed (self):
      return self.group.isfixed ()

   def fixedlength (self):
      return self.group.fixedlength ()
36 2021-02-26 04:19

The evaluation context updated with storage:

def work_fixedgroup (target, group, *, debug = True, matrixclass = None):
   log    = print
   M      = Matrix if matrixclass is None else matrixclass
   slots  = 2
   mstack = Stack.alloc (slots, M)
   ctx    = {
      "matrixclass": M,
      "stack":       mstack,
      "storage":     {},
   }

   if debug:
      log (" group {}".format (group.show ()))
      log ("target {:.15f}".format (target))

   group.eval (ctx, 1)
   M.mul (M.S, mstack [1], mstack [0])
   a, b = M.pair (mstack [0])

   if debug:
      log ("result {:.15f}".format (a / b))
      log ("{:d}".format (a))
      log ("{:d}".format (b))
      log ("stack {:d}".format (len (mstack)))


def work_speclimit (spec, limit, *, debug = True, matrixclass = None, compiler = None):
   C      = Compiler if compiler is None else compiler
   target = spec.targetfloat ()
   ret    = C.fixedlimit (spec, limit)
   group  = ret ["group"]

   work_fixedgroup (target, group, debug = debug, matrixclass = matrixclass)
37 2021-02-26 10:43

The updated compiler:

class Compiler:
   @ staticmethod
   def fixedlimit (spec, limit):
      what = spec.kind ()
      fun  = getattr (Compiler, "fixedlimit_" + what)

      # after
      if limit < 1:
         return {
            "group": EmptyGroup (),
            "count": 0,
         }

      ret = fun (spec, limit)
      return ret

   @ staticmethod
   def fixedlimit_fixed (spec, limit):
      fs    = spec.fixedstr
      fslen = len (fs)

      if fslen < 1:
         return {
            "group": EmptyGroup (),
            "count": 0,
         }

      if fslen <= limit:
         return {
            "group": spec,
            "count": fslen,
         }

      return {
         "group": FixedGroup (fs [:limit]),
         "count": limit,
      }

   @ staticmethod
   def fixedlimit_expo (spec, limit):
      base    = spec.base
      baselen = base.fixedlength ()
      expo    = spec.expo
      have    = expo * baselen

      if have < 1:
         return {
            "group": EmptyGroup (),
            "count": 0,
         }

      if have <= limit:
         return {
            "group": spec,
            "count": have,
         }

      div, mod = divmod (limit, baselen)

      if mod:
         ret  = Compiler.fixedlimit (base, mod)
         gmod = ret ["group"]

         if ret ["count"] != mod:
            raise Wrong (mod, ret ["count"])

         if div:
            if div > 1:
               h = ListGroup ([ExpoGroup (base, div), gmod])
            else:
               h = ListGroup ([base, gmod])
         else:
            h = gmod
      else:
         if div > 1:
            h = ExpoGroup (base, div)
         else:
            h = base

      return {
         "group": h,
         "count": limit,
      }

   @ staticmethod
   def fixedlimit_list (spec, limit):
      gs    = spec.groups
      gslen = len (gs)

      if gslen < 1:
         return {
            "group": EmptyGroup (),
            "count": 0,
         }

      take = []
      left = limit
      used = 0
      flim = Compiler.fixedlimit

      while (left > 0) and (used < gslen):
         ret   = flim (gs [used], left)
         used += 1
         now   = ret ["count"]

         if now > 0:
            take.append (ret ["group"])
            left -= now

      taken = len (take)

      if taken < 1:
         return {
            "group": EmptyGroup (),
            "count": 0,
         }

      return {
         "group": take [0] if taken == 1 else ListGroup (take),
         "count": limit - left,
      }

   @ staticmethod
   def fixedlimit_star (spec, limit):
      g = spec.group

      if not g.isfixed ():
         raise Wrong (g.kind ())

      have = g.fixedlength ()

      if have < 1:
         raise Wrong

      div, mod = divmod (limit, have)

      if mod:
         ret  = Compiler.fixedlimit (g, mod)
         gmod = ret ["group"]

         if ret ["count"] != mod:
            raise Wrong (mod, ret ["count"])

         if div:
            if div > 1:
               h = ListGroup ([ExpoGroup (g, div), gmod])
            else:
               h = ListGroup ([g, gmod])
         else:
            h = gmod
      else:
         if div > 1:
            h = ExpoGroup (g, div)
         else:
            h = g

      return {
         "group": h,
         "count": limit,
      }

   @ staticmethod
   def fixedlimit_stamploop (spec, limit):
      more  = True
      index = 0
      left  = limit
      stal  = spec.stamplength

      while more:
         now = stal (index)

         if now <= left:
            index += 1
            left  -= now
            more   = (left > 0)
         else:
            more   = False

      out = []

      if index > 1:
         out.append (LoopGroup (index, spec.stamp))
      elif index == 1:
         out.append (spec.stamp)

      if left > 0:
         g    = spec.tailgroup (index)
         ret  = Compiler.fixedlimit (g, left)
         gmod = ret ["group"]

         if ret ["count"] != left:
            raise Wrong (left, ret ["count"])

         out.append (gmod)

      outlen = len (out)

      if outlen < 1:
         raise Wrong

      return {
         "group": out [0] if outlen == 1 else ListGroup (out),
         "count": limit,
      }
38 2021-02-26 10:56

Ratios from OP's timings, using vanilla python without gmpy2. For (phi, 10^4) >>21 >>22:

>>> 33000 / 137
240.87591240875912

For (e, 10^6) >>20 >>32:

>>> 2995 / 4.5
665.5555555555555

Both ratios will increase when the stream index increases.

39 2021-02-26 14:09 *

Mhhh, undocumented spam-code... love it when it takes up more than half the space on the frontpage.

40 2021-02-26 21:50 *

>>39
Everything is documented in >>1.

41 2021-02-27 04:07

Moving the integer arithmetic to gmpy2 yields a modest speedup for (e, 10^6), shaving off less than 8% of the run time.

$ python3 -m timeit -s 'import numsci.sbtree as mod' 'mod.work_speclimit (mod.fsb.Specs.E (), 1000000)'
100 loops, best of 3: 4.17 msec per loop

The gains should increase for higher stream positions as multiplications take over the bulk of the run time.

class Matrix:
   z0 = gmpy2.mpz (0)
   z1 = gmpy2.mpz (1)

   I = [z1, z0, z0, z1]
   S = [z0, z1, z1, z0]
   L = [z1, z1, z0, z1]
   R = [z1, z0, z1, z1]
42 2021-02-27 08:54

>>40
We all know that that is not how code documentation works.

43 2021-02-27 11:19

Here is stream index 10^12 in the e stream, to check against other implementations.
http://0x0.st/-K_o.gz

$ gawk '{ if (length ($0) < 1000) { print NR ": " $0 } else { print NR "! " length ($0) } }' e12.txt
1:  group List (Fixed RRLRR, List (Loop (499998, List (Store (a, List (Load (a, Fixed LR), Load (l4, Fixed LLLL))), Store (b, List (Load (b, Fixed RLRR), Load (r4, Fixed RRRR))))), List (Fixed LR, Expo (Fixed L, 1999996), Fixed RL, Expo (Fixed R, 999999))))
2: target 2.718281828459045
3: result 2.718281828459045
4! 6167766
5! 6167765
6: stack 12

The download is nearly 6 megabytes, the uncompressed file just over 12 megabytes and the numerator has 6167766 digits, so text editors might not like it.

>>40
Do not feed.

44 2021-02-28 11:54

The phi stream grows much faster in numerator and denominator digit counts, since they are essentially the fibs, and by stream index 10^9 we are already past 200 million.

$ gawk '{ if (length ($0) < 1000) { print NR ": " $0 } else { print NR "! " length ($0) } }' phi9.txt
1:  group Expo (Fixed RL, 500000000)
2: target 1.618033988749895
3: result 1.618033988749895
4! 208987641
5! 208987641
6: stack 6

The e stream was still just a little over 6 million digits >>43 at a thousand times the stream index. For verification here is the hash of the phi 10^9 numerator:

$ sha1sum <(gawk 'NR == 4 { printf "%s", $0 }' phi9.txt)
4a74c3993775189c754cfcc6ecf5de166bb718c7  /dev/fd/63

And the hash of the denominator:

$ sha1sum <(gawk 'NR == 5 { printf "%s", $0 }' phi9.txt)
24e5e3350b839eea494e9daec46eec323f0f32dd  /dev/fd/63
45 2021-02-28 12:29 *

>>43
We all know who the real troll here is.
If there is no substantial engagement in the thread, we all know who the real spammer is. Just get your own site.

46 2021-03-01 11:28

The (e, 10^12) link >>43 will expire at some point so here is the hash of the numerator:

$ sha1sum <(gawk 'NR == 4 { printf "%s", $0 }' e12.txt)
2a4d66da41f5564d04a5c4356159dbc7ccdd9827  /dev/fd/63

And the hash of the denominator:

$ sha1sum <(gawk 'NR == 5 { printf "%s", $0 }' e12.txt)
e405d307f115213561485d57d5e4d9b8f658b047  /dev/fd/63
47 2021-03-02 14:35

Stream index 10^9 for the Sqrt2 >>28 stream:

$ gawk '{ if (length ($0) < 1000) { print NR ": " $0 } else { print NR "! " length ($0) } }' sqrt29.txt
1:  group Expo (Fixed RLLR, 250000000)
2: target 1.414213562373095
3: result 1.414213562373095
4! 191387843
5! 191387843
6: stack 6

The hash of the numerator:

$ sha1sum <(gawk 'NR == 4 { printf "%s", $0 }' sqrt29.txt)
e726c20ee05cebf894df98462d5c793a08318c66  /dev/fd/63

The hash of the denominator:

$ sha1sum <(gawk 'NR == 5 { printf "%s", $0 }' sqrt29.txt)
86e33050005cc854e7ba9b734b9f2a2f1333e6a0  /dev/fd/63

A hypothesis >>43 >>44 presents itself. It would seem that the number of L -> R and R -> L switches is an indicator of the rate at which the numerator and denominator will grow.

spec  index    digits group
e     10^12   6167766 RRLRR(LRL[4+4*k]RLR[8+4*k])*
phi   10^9  208987641 (RL)*
sqrt2 10^9  191387843 (RLLR)*

The phi stream has the maximum number of switches a stream can have, and it grows the fastest. The sqrt2 stream has half the number of switches and it grows slower than phi. The e stream has contiguous runs of increasing length between switches, and it grows very slowly. This should predict the rate of growth of the other >>28 streams based on their generating pattern.

48 2021-03-02 18:39 *

* cricket sounds *

49 2021-03-02 23:38

The [8+4*k] (eight) in >>47 is a typo. The correct length of the R run is [6+4*k] (six) as in >>33.

An equivalent group for e is:

R(RLR[2+4*k]LRL[4+4*k])*
50 2021-03-03 11:07

(Sqrt3, 10^9) >>28:

$ gawk '{ if (length ($0) < 1000) { print NR ": " $0 } else { print NR "! " length ($0) } }' sqrt39.txt
1:  group List (Expo (Fixed RLR, 333333333), Fixed R)
2: target 1.732050807568877
3: result 1.732050807568877
4! 190649183
5! 190649183
6: stack 7

Numerator/denominator hashes:

$ sha1sum <(gawk 'NR == 4 { printf "%s", $0 }' sqrt39.txt)
d464586d1eccfb68056109d70d486a142f9d8992  /dev/fd/63
$ sha1sum <(gawk 'NR == 5 { printf "%s", $0 }' sqrt39.txt)
98fcfa9aada30daa813b423f30f79a1d6390b902  /dev/fd/63

(Sqrt5, 10^9) >>28:

$ gawk '{ if (length ($0) < 1000) { print NR ": " $0 } else { print NR "! " length ($0) } }' sqrt59.txt
1:  group Expo (Fixed RRLLLLRR, 125000000)
2: target 2.236067977499790
3: result 2.236067977499790
4! 156740731
5! 156740731
6: stack 6

Numerator/denominator hashes:

$ sha1sum <(gawk 'NR == 4 { printf "%s", $0 }' sqrt59.txt)
c6e680622d444ae51479e5f4f8e2f2902436674f  /dev/fd/63
$ sha1sum <(gawk 'NR == 5 { printf "%s", $0 }' sqrt59.txt)
7396e2d4afd5060c98e11267bbb4c80389325a35  /dev/fd/63

(Sqrt7, 10^9) >>28:

$ gawk '{ if (length ($0) < 1000) { print NR ": " $0 } else { print NR "! " length ($0) } }' sqrt79.txt
1:  group List (Expo (Fixed RRLRLRR, 142857142), Fixed RRLRLR)
2: target 2.645751311064591
3: result 2.645751311064591
4! 171773357
5! 171773356
6: stack 7

Numerator/denominator hashes:

$ sha1sum <(gawk 'NR == 4 { printf "%s", $0 }' sqrt79.txt)
06253fc6faf29a64a2cc1bd2a0b159e2968865ab  /dev/fd/63
$ sha1sum <(gawk 'NR == 5 { printf "%s", $0 }' sqrt79.txt)
e91a7792c7c4c91e0c57b432036306c4c72b83c1  /dev/fd/63
51 2021-03-03 11:11

The hypothesis of >>47 does not hold.

spec  index    digits group
e     10^12   6167766 RRLRR(LRL[4+4*k]RLR[6+4*k])*
sqrt5 10^9  156740731 (RRLLLLRR)*
sqrt7 10^9  171773357 (RRLRLRR)*
sqrt3 10^9  190649183 (RLR)*
sqrt2 10^9  191387843 (RLLR)*
phi   10^9  208987641 (RL)*

Sqrt3 has more switches (2N/3) than Sqrt2 (N/2) but grows at a slower rate. Sqrt7 also has more switches (4N/7) than Sqrt2 and slower growth.

52 2021-03-03 11:29 *

https://www.youtube.com/watch?v=RAA1xgTTw9w

53 2021-03-28 04:56

Just realized the Stern-Brocot tree being the list of all coprime numbers could be used to generate the pythagorean triples (uint a,b,c such that a²+b²=c²). We need to take only the right subtree where every m > n.
Euclide's formula to generate a pythagorean triple, with m and n coprimes:

a = m²-n², b = 2mn, c = m²+n²

If we need only primitive pythagorean triples then we just need to filter out the fractions where both m and n are odd.

54


VIP:

do not edit these