need a big pascal's table
Posted: Fri Aug 19, 2022 3:52 pm
i need a big pascal's triangle (say, 10,000 rows)
tried with normal numbers
⎕FR←645 ⋄⎕ts⋄ sink←{⍉(⍳⍵)∘.!⍳⍵} 1029 ⋄ ⎕ts
2022 8 19 10 52 37 354
2022 8 19 10 52 37 571
⎕FR←645 ⋄⎕ts⋄ sink←{⍉(⍳⍵)∘.!⍳⍵} 1030 ⋄ ⎕ts
2022 8 19 10 52 50 483
DOMAIN ERROR
⎕FR←645 ⋄ ⎕TS ⋄ sink←{⍉(⍳⍵)∘.!⍳⍵}1030 ⋄ ⎕TS
bignums takes about 5 minutes for 2060 rows, about 19 minutes for 4096 rows, still running after an hour for 10240 rows
∧
⎕FR←1287 ⋄ ⎕ts⋄ sink←{⍉(⍳⍵)∘.!⍳⍵}2060 ⋄ ⎕ts
2022 8 19 10 53 4 848
2022 8 19 10 58 23 138
anybody have any clever tricks to speed it up ? [i suppose i could wait several hours to compute it once and store the result in a memory mapped file. but having to multiply a bignum pascal triangle by another matrix would take a long time ... but i was hoping someone whose comp sci is better than mine would say "here is a way to generate the logs of pascals triangle,and instead of multiplying a matrix by pascal triangle you could just add logs, and taking the antilogs is easy enough, and 64 bit logs will give you enough precision for 10,000 rows ")
the use case is the function below, in particular lines 14, 32, and 33
∇ crrtree2 [⎕]∇
[0] crrtree2←{
[1] ⍝ why separate crr tree generation from crr pricing?
[2] ⍝ cuz sometimes you just want to pathwise monte carlo through a crr tree not backwards loop over it
[3] ⍝ so break tree generation out from traditional crr pricing
[4]
[5] ⍝ ⍵[1]=strike, ⍵[2]=spotprice,
[6] ⍝ ⍵[3]=expiry in years, 1 month=12÷365.25 or 12÷tradingdays←12×21
[7] ⍝ ⍵[4]=annualized volatility, 21%/yr would = 0.21
[8] ⍝ ⍵[5]=NUMBER of timesteps N.B. root=timestep zero, so tree with 6 end leaves has 5 timesteps
[9] ⍝ ⍵[6]=irate, 5%/yr would = 0.05
[10] ⍝ ⍵[7]=optional (for stock) annual dividend rate
[11] ⍝ MANDITORY THAT ⍵[6]=⍵[7] FOR OPTIONS ON FUTURES
[12]
[13] ⍝ result[1;;] is stock price at node, result[2;;] prob ANY SINGLE PATH reaching node
[14] ⍝ result[3;;] total prob reaching node = (prob SINGLE PATH)×(NUMB PATHS=Pascals triangle)
[15]
[16] spot expiry vol timesteps irate divrate←1↓7↑⍵ ⍝ 1↓ as trees dont need strike arg of option pricer ⍵
[17] ⎕IO←1 ⍝ I've 5 fingers, not 4 fingers and zeroeth thumb
[18]
[19] mask←(⍳1+timesteps)∘.≤⍳1+timesteps⍝ "mask×" will be used to zero out tree below diagonal
[20]
[21] u←*vol×(∆t←expiry÷timesteps)*0.5 ⍝ multiplicative size up jump
[22] d←*-vol×∆t*0.5 ⍝ multiplicative size down jump, also = 1÷u
[23]
[24] uppowers←maskׯ1++\mask ⍝ numb up jumps to reach a node, ¯1+ sets tree root to zero jumps
[25] downpowers←mask×|uppowers-[2]¯1+⍳1+timesteps ⍝ numb down jumps to get to node
[26]
[27] prices←mask×spot×(u*uppowers)×d*downpowers ⍝ prices at node through time.
[28] ⍝ ⍝ yep, above prices table couldve been a tacit fork with some ⊢s, ⊣s, and ⍨s
[29] ⍝ ⍝ I DONT CARE, CLARITY OVER CODE GOLF
[30]
[31] Pd←1-Pu←((*∆t×irate-divrate)-d)÷u-d ⍝ Pu=up probability, Pd=down probability
[32] P1Path←mask×(Pu*uppowers)×Pd*downpowers ⍝ probability ANY ONE SINGLE path hits node
[33] PAnyPath←mask×P1Path×⍉pascal timesteps+1 ⍝ probability ANYofALL paths hits node
[34] ↑prices P1Path PAnyPath ⍝ result = rank 3 flat array ⍴=(3,(1+timesstep),1+timestep)
[35] }
crrtree2 uses this subfunction
∇ pascal [⎕]∇
[0] pascal←{⍝ returns ⍵ lines pof pascals triangle
[1]
[2] ⎕IO←0
[3] ⍉(⍳⍵)∘.!⍳⍵
[4] }
above two functions are subfunctions of a Cox Ross Rubenstein option pricer
∇ crrpricer2 [⎕]∇
[0] crrpricer2←{
[1] ⍝ return CRR value of an American or European option
[2] ⍝ Euro redundant to closed form Euro Black Scholes, but useful for futures & calibrating volatility smiles tables
[3]
[4] ⍝ ⍺[1]←1 for American exercise, 0 for European Exercise
[5] ⍝ ⍺[2] put/call ¯1=put, +1=call
[6]
[7] ⍝ ⍵[1]= strike, ⍵[2]=spotprice
[8] ⍝ ⍵[3]=expiry in years, 1 month=12÷year←365.25 or 12÷year←12×21 (21=tradingdays per month)
[9] ⍝ ⍵[4]=annualized volatility, 35 percent =0.35
[10] ⍝ ⍵[5]=NUMBER of timesteps N.B. root=timestep zero, so tree with 6 end leaves has 5 timesteps
[11] ⍝ ⍵[6]=irate, 5%/yr=0.05
[12] ⍝ ⍵[7]=optional (for stock) annual dividend rate
[13] ⍝ MANDITORY THAT ⍵[6]=⍵[7] FOR FUTURES
[14]
[15] isAmer PutCall←⍺
[16] strike spot expiry vol timesteps irate divrate←7↑⍵
[17]
[18] ⎕IO←1 ⍝ I've 5 fingers, not 4 fingers and zeroeth thumb
[19]
[20] mask←(⍳1+timesteps)∘.≤⍳1+timesteps ⍝ mask has 1s for valid nodes, 0s for invalid below diagonal
[21]
[22] trees←crrtree2 ⍵ ⍝ treeS[1;;]=prices, [2;;]=prob 1 single path hits node, [3;;]=sum of prob each individual path h
its node
[23]
[24] ⍝ disc∆t←÷*irate×expiry÷timesteps ⍝ present val of $1 1∆t in future
[25] disc∆t←÷1+irate×expiry÷timesteps ⍝ should be EXACTLY same as above, but small diff
[26]
[27] Pu Pd←2↑trees[3;;2] ⍝ prob up and down jumps
[28] prctree←(↓[1]mask)/¨↓[1]trees[1;;] ⍝ trimmed nested VectorOfVectors of price tree
[29] intrinsic←0⌈PutCall×prctree-|strike ⍝ in the money amount at each node
[30]
[31] {(⍺×isAmer)⌈disc∆t×(Pu,Pd)+.×0 ¯1↓0 1⌽⍵,[0.5]⍵}/intrinsic ⍝ THE BIG FOLD FROM THE RIGHT
[32] ⍝ 0k, wrote the above as a joke to prove i can write as cryptic a line of APL as anyone else.
[33] ⍝ IN PRODUCTION CODE I'd write "foo/intrinsics" while defining "foo" as below
[34]
[35] ⍝ foo←{
[36] ⍝ ⍝ whats going on with that reduction above
[37] ⍝ ⍝ ⍺="current i.e " now's " intrinsics, ⍵=intrinscs 1∆t forward in time
[38]
[39] ⍝ intrinsics←0 ¯1↓ 0 1 ⌽ ⍵,[0.5]⍵ ⍝ intrinsic 1∆t ahead [1;]=intrinsic if upjump, [2;]=intrinsic if downjump
[40] ⍝ expval←(Pu,Pd)+.×intrinsics ⍝ expval=(ProbUpJump×upIntrinsics)+(ProbDownJump×downIntrinsics)
[41] ⍝ discval←disc∆t×expval ⍝ discval=discounted expval to "now" of intrinsics[1∆t ahead]
[42]
[43] ⍝ result← (⍺×isAmer)⌈discval ⍝ IsAmer×MAX(intrinsic "now" vs expval intrinsic 1∆t ahead)
[44] ⍝ ⍝ if isAmer=0, makes now's intrinsics=0, equivalent to European exercise
[45]
[46] ⍝ ⎕←result
[47] ⍝ }
[48] }
tried with normal numbers
⎕FR←645 ⋄⎕ts⋄ sink←{⍉(⍳⍵)∘.!⍳⍵} 1029 ⋄ ⎕ts
2022 8 19 10 52 37 354
2022 8 19 10 52 37 571
⎕FR←645 ⋄⎕ts⋄ sink←{⍉(⍳⍵)∘.!⍳⍵} 1030 ⋄ ⎕ts
2022 8 19 10 52 50 483
DOMAIN ERROR
⎕FR←645 ⋄ ⎕TS ⋄ sink←{⍉(⍳⍵)∘.!⍳⍵}1030 ⋄ ⎕TS
bignums takes about 5 minutes for 2060 rows, about 19 minutes for 4096 rows, still running after an hour for 10240 rows
∧
⎕FR←1287 ⋄ ⎕ts⋄ sink←{⍉(⍳⍵)∘.!⍳⍵}2060 ⋄ ⎕ts
2022 8 19 10 53 4 848
2022 8 19 10 58 23 138
anybody have any clever tricks to speed it up ? [i suppose i could wait several hours to compute it once and store the result in a memory mapped file. but having to multiply a bignum pascal triangle by another matrix would take a long time ... but i was hoping someone whose comp sci is better than mine would say "here is a way to generate the logs of pascals triangle,and instead of multiplying a matrix by pascal triangle you could just add logs, and taking the antilogs is easy enough, and 64 bit logs will give you enough precision for 10,000 rows ")
the use case is the function below, in particular lines 14, 32, and 33
∇ crrtree2 [⎕]∇
[0] crrtree2←{
[1] ⍝ why separate crr tree generation from crr pricing?
[2] ⍝ cuz sometimes you just want to pathwise monte carlo through a crr tree not backwards loop over it
[3] ⍝ so break tree generation out from traditional crr pricing
[4]
[5] ⍝ ⍵[1]=strike, ⍵[2]=spotprice,
[6] ⍝ ⍵[3]=expiry in years, 1 month=12÷365.25 or 12÷tradingdays←12×21
[7] ⍝ ⍵[4]=annualized volatility, 21%/yr would = 0.21
[8] ⍝ ⍵[5]=NUMBER of timesteps N.B. root=timestep zero, so tree with 6 end leaves has 5 timesteps
[9] ⍝ ⍵[6]=irate, 5%/yr would = 0.05
[10] ⍝ ⍵[7]=optional (for stock) annual dividend rate
[11] ⍝ MANDITORY THAT ⍵[6]=⍵[7] FOR OPTIONS ON FUTURES
[12]
[13] ⍝ result[1;;] is stock price at node, result[2;;] prob ANY SINGLE PATH reaching node
[14] ⍝ result[3;;] total prob reaching node = (prob SINGLE PATH)×(NUMB PATHS=Pascals triangle)
[15]
[16] spot expiry vol timesteps irate divrate←1↓7↑⍵ ⍝ 1↓ as trees dont need strike arg of option pricer ⍵
[17] ⎕IO←1 ⍝ I've 5 fingers, not 4 fingers and zeroeth thumb
[18]
[19] mask←(⍳1+timesteps)∘.≤⍳1+timesteps⍝ "mask×" will be used to zero out tree below diagonal
[20]
[21] u←*vol×(∆t←expiry÷timesteps)*0.5 ⍝ multiplicative size up jump
[22] d←*-vol×∆t*0.5 ⍝ multiplicative size down jump, also = 1÷u
[23]
[24] uppowers←maskׯ1++\mask ⍝ numb up jumps to reach a node, ¯1+ sets tree root to zero jumps
[25] downpowers←mask×|uppowers-[2]¯1+⍳1+timesteps ⍝ numb down jumps to get to node
[26]
[27] prices←mask×spot×(u*uppowers)×d*downpowers ⍝ prices at node through time.
[28] ⍝ ⍝ yep, above prices table couldve been a tacit fork with some ⊢s, ⊣s, and ⍨s
[29] ⍝ ⍝ I DONT CARE, CLARITY OVER CODE GOLF
[30]
[31] Pd←1-Pu←((*∆t×irate-divrate)-d)÷u-d ⍝ Pu=up probability, Pd=down probability
[32] P1Path←mask×(Pu*uppowers)×Pd*downpowers ⍝ probability ANY ONE SINGLE path hits node
[33] PAnyPath←mask×P1Path×⍉pascal timesteps+1 ⍝ probability ANYofALL paths hits node
[34] ↑prices P1Path PAnyPath ⍝ result = rank 3 flat array ⍴=(3,(1+timesstep),1+timestep)
[35] }
crrtree2 uses this subfunction
∇ pascal [⎕]∇
[0] pascal←{⍝ returns ⍵ lines pof pascals triangle
[1]
[2] ⎕IO←0
[3] ⍉(⍳⍵)∘.!⍳⍵
[4] }
above two functions are subfunctions of a Cox Ross Rubenstein option pricer
∇ crrpricer2 [⎕]∇
[0] crrpricer2←{
[1] ⍝ return CRR value of an American or European option
[2] ⍝ Euro redundant to closed form Euro Black Scholes, but useful for futures & calibrating volatility smiles tables
[3]
[4] ⍝ ⍺[1]←1 for American exercise, 0 for European Exercise
[5] ⍝ ⍺[2] put/call ¯1=put, +1=call
[6]
[7] ⍝ ⍵[1]= strike, ⍵[2]=spotprice
[8] ⍝ ⍵[3]=expiry in years, 1 month=12÷year←365.25 or 12÷year←12×21 (21=tradingdays per month)
[9] ⍝ ⍵[4]=annualized volatility, 35 percent =0.35
[10] ⍝ ⍵[5]=NUMBER of timesteps N.B. root=timestep zero, so tree with 6 end leaves has 5 timesteps
[11] ⍝ ⍵[6]=irate, 5%/yr=0.05
[12] ⍝ ⍵[7]=optional (for stock) annual dividend rate
[13] ⍝ MANDITORY THAT ⍵[6]=⍵[7] FOR FUTURES
[14]
[15] isAmer PutCall←⍺
[16] strike spot expiry vol timesteps irate divrate←7↑⍵
[17]
[18] ⎕IO←1 ⍝ I've 5 fingers, not 4 fingers and zeroeth thumb
[19]
[20] mask←(⍳1+timesteps)∘.≤⍳1+timesteps ⍝ mask has 1s for valid nodes, 0s for invalid below diagonal
[21]
[22] trees←crrtree2 ⍵ ⍝ treeS[1;;]=prices, [2;;]=prob 1 single path hits node, [3;;]=sum of prob each individual path h
its node
[23]
[24] ⍝ disc∆t←÷*irate×expiry÷timesteps ⍝ present val of $1 1∆t in future
[25] disc∆t←÷1+irate×expiry÷timesteps ⍝ should be EXACTLY same as above, but small diff
[26]
[27] Pu Pd←2↑trees[3;;2] ⍝ prob up and down jumps
[28] prctree←(↓[1]mask)/¨↓[1]trees[1;;] ⍝ trimmed nested VectorOfVectors of price tree
[29] intrinsic←0⌈PutCall×prctree-|strike ⍝ in the money amount at each node
[30]
[31] {(⍺×isAmer)⌈disc∆t×(Pu,Pd)+.×0 ¯1↓0 1⌽⍵,[0.5]⍵}/intrinsic ⍝ THE BIG FOLD FROM THE RIGHT
[32] ⍝ 0k, wrote the above as a joke to prove i can write as cryptic a line of APL as anyone else.
[33] ⍝ IN PRODUCTION CODE I'd write "foo/intrinsics" while defining "foo" as below
[34]
[35] ⍝ foo←{
[36] ⍝ ⍝ whats going on with that reduction above
[37] ⍝ ⍝ ⍺="current i.e " now's " intrinsics, ⍵=intrinscs 1∆t forward in time
[38]
[39] ⍝ intrinsics←0 ¯1↓ 0 1 ⌽ ⍵,[0.5]⍵ ⍝ intrinsic 1∆t ahead [1;]=intrinsic if upjump, [2;]=intrinsic if downjump
[40] ⍝ expval←(Pu,Pd)+.×intrinsics ⍝ expval=(ProbUpJump×upIntrinsics)+(ProbDownJump×downIntrinsics)
[41] ⍝ discval←disc∆t×expval ⍝ discval=discounted expval to "now" of intrinsics[1∆t ahead]
[42]
[43] ⍝ result← (⍺×isAmer)⌈discval ⍝ IsAmer×MAX(intrinsic "now" vs expval intrinsic 1∆t ahead)
[44] ⍝ ⍝ if isAmer=0, makes now's intrinsics=0, equivalent to European exercise
[45]
[46] ⍝ ⎕←result
[47] ⍝ }
[48] }