#] #] ********************* #] loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' # www.BillHowell.ca 14Apr2020 initial # view this file in a text editor, with [constant width font, tab = 3 spaces], no line-wrap f_mathHandy := 'math - [quick, handy] stuff.ndf' ; loaddefs_start f_mathHandy ; #**************************** # Table of Contents, generated with : # $ grep "^#]" "$d_Qndfs""math - [quick, handy] stuff.ndf" | sed 's/^#\]/ /' # ********************* loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' Predefine local ops to avoid sequencing problems with initial qnial loaddefs +-----+ Handy mathematical stuff : average IS / [sum, tally] - square IS prod [pass, pass] - floor_mod IS OP a b - convenient return of BOTH floor and mod! int_is_oddNum IS OP int - true if int is an odd number int_is_evenNum IS OP int - true if int is an even number fibonacci IS OP nTerms - generate the Fibonacci series to the nth term (beyond (0 1)) 14Apr2023 - crashes! need to fix fibonacciRatio IS OP nTerms - generate the Fibonacci ratio series to the nth term 14Apr2023 - WRONG!! need to fix sub_ary_axs_progression IS OP sub ary axs - simply shift sub through ary along one axis normally USE : ary_shapeChk_sub_apply_optrPhr ary sub "sub_ary_axs_progression subr is sub "boosted" so (= EACH valence sub ary) (i.e. same dimensionality) new subr axis added to higher dimensionality by default for specific results, user should pre-shape sub or do combinations (eg sub_ary_axs_progression) factorial IS OP int - res ipsa loquitor ary_nComb_itmCombinationLL IS OP ary n_combo - Howell? algorithm for combinations of a list ary_nComb_itmPermuteHeapLL IS OP ary nCombos - Heap algorithm for permutations of a list ary_nComb_itmPermutationLLTo_idxL IS OP ary nCombos - Heap algorithm for permutations of a list won't run if > 1k permutations, but should add file output [option, version] +-----+ Matrix ops - symbolic through semi-symbolic through numeric vector_from_list IS OP c_r lista - creates a vector from a list (legacy - don't use this for new code!) lst_convertTo_vector IS OP lista c_r - creates a vector from a list +-----+ Investments PEratio_calc IS OP earnGrwth discRate Treasury10yrRate TreasuryDiscRate - estimate PE now ~ #*********** # Setup (kind of like header info) #] Predefine local ops to avoid sequencing problems with initial qnial loaddefs #g floor_mod IS OP a b { fault '?floor_mod undefined (QNial setup header.ndf)' } #g int_is_oddNum IS OP int { fault '?int_is_oddNum undefined (QNial setup header.ndf)' } #l vector_from_list IS OP c_r lista { fault '?vector_from_list undefined (QNial setup header.ndf)' } #] +-----+ #] Handy mathematical stuff : IF flag_debug THEN write '+-----+' ; write 'loading Handy mathematical stuff' ; ENDIF ; IF flag_debug THEN write 'loading average' ; ENDIF ; #] average IS / [sum, tally] - average IS / [sum, tally] IF flag_debug THEN write 'loading square' ; ENDIF ; #] square IS prod [pass, pass] - square IS prod [pass, pass] IF flag_debug THEN write 'loading floor_mod' ; ENDIF ; #] floor_mod IS OP a b - convenient return of BOTH floor and mod! # NOTE : the offset 1e-6 is used to avoid excessive "down-rounding" # hopefully this will NOT introduce errors to mod!!??!! floor_mod IS OP a b { LOCAL divident div_flr div_mod ; dividend := a / b ; div_flr := floor dividend ; div_mod := floor ((dividend - div_flr) * b + 1e-6) ; div_flr div_mod } IF flag_debug THEN write 'loading int_is_oddNum' ; ENDIF ; #] int_is_oddNum IS OP int - true if int is an odd number int_is_oddNum IS OP int { 1 = (int mod 2) } # a := 0 2 1 5 936 # a EACHLEFT / 2 # a EACHLEFT mod 2 # EACH int_is_oddNum a IF flag_debug THEN write 'loading int_is_evenNum' ; ENDIF ; #] int_is_evenNum IS OP int - true if int is an even number int_is_evenNum IS OP int { 0 = (int mod 2) } # a := 0 2 1 5 936 # a EACHLEFT / 2 # a EACHLEFT mod 2 # EACH int_is_evenNum a # loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' IF flag_debug THEN write 'loading fibonacci' ; ENDIF ; #] fibonacci IS OP nTerms - generate the Fibonacci series to the nth term (beyond (0 1)) #] 17Apr2023 need to do recursive definition (for fun) # eg 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 ... https://byjus.com/maths/fibonacci-sequence/ fibonacci IS OP nTerms { fibOld fibNew := (fibL := 0 1) ; FOR i WITH (tell (nTerms - 2)) DO fib := + fibOld fibNew ; fibOld fibNew := fibNew fib ; fibL := link fibL fib ; ENDFOR ; fibL } # 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 # Fibonacci [0.000 0.146 0.236 0.382 0.500 0.618 0.764 1.000] Puetz mix [0.000 0.133 0.222 0.333 0.500 0.667 0.778 1.000] [Fibonacci, Puetz UWS] do NOT have 0.500, but traders like it, Puetz half-series has it Puetz full [0.000 0.133 0.167 0.222 0.333 0.444 0.555 0.667 0.778 0.889 1.000] # loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' IF flag_debug THEN write 'loading fibonacciRatio' ; ENDIF ; #] fibonacciRatio IS OP nTerms - generate a Fibonacci retracement series (0.05 to 22.) # IF flag_break THEN BREAK ; ENDIF ; fibonacciRatio IS { fibL := fibonacci 100 / 1.000 ; ratios := (front fibL) / fibL@70 ; 0 link ((AND (0.05 EACHRIGHT < ratios) (22 EACHRIGHT > ratios)) sublist ratios) } # 0 0.0557281 0.0901699 0.145898 0.236068 0.381966 0.618034 1. 1.61803 2.61803 4.23607 6.8541 11.0902 17.9443 # loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' IF flag_debug THEN write 'loading sub_ary_axs_progression' ; ENDIF ; #] sub_ary_axs_progression IS OP sub ary axs - simply shift sub through ary along one axis #] normally USE : ary_shapeChk_sub_apply_optrPhr ary sub "sub_ary_axs_progression #] subr is sub "boosted" so (= EACH valence sub ary) (i.e. same dimensionality) #] new subr axis added to higher dimensionality by default #] for specific results, user should pre-shape sub or do combinations (eg sub_ary_axs_progression) # 29Apr2022 initial, no fault codes yet # 29Apr2022 why am I even doing this? It's useless as I first get sub_posnA1stItmInTop_ary?? # nyet - still good, ary_idx_getAllAxes_slcA is the reason I started this # 29Apr2022 ary_idx_getAllAxes_slcA now incorporates a simplified idea, so sub_ary_axs_progression not used # may come in handy in the future? # IF flag_break THEN BREAK ; ENDIF ; sub_ary_axs_progression IS OP sub ary axs { LOCAL i n_shifts resFltL subr ; % ; resFltL := null ; subr := sub_makeVlcSameAs_ary sub ary ; IF (NOT ary_hasFaults subr) THEN n_shifts := - EACH (gage shape) ary sub ; % must get simple int ; IF (0 < (valence n_shifts)) THEN n_shifts := axs pick n_shifts ; ENDIF ; IF flag_break THEN BREAK ; ENDIF ; FOR i WITH (tell (n_shifts + 1)) DO resFltL := link resFltL [link ((i reshape [null]) [sub] ((n_shifts - i) reshape [null])) ] ; ENDFOR ; ENDIF ; resFltL } # 29Apr2022 tests qnial> sub_ary_axs_progression (3 4 5) (tell 10) 1 +--------------+--------------+--------------+--------------+--------------+--------------+--------------+---- |+-+-+-++++++++|++-+-+-+++++++|+++-+-+-++++++|++++-+-+-+++++|+++++-+-+-++++|++++++-+-+-+++|+++++++-+-+-++|++++ ||3|4|5|||||||||||3|4|5|||||||||||3|4|5|||||||||||3|4|5|||||||||||3|4|5|||||||||||3|4|5|||||||||||3|4|5||||||| |+-+-+-++++++++|++-+-+-+++++++|+++-+-+-++++++|++++-+-+-+++++|+++++-+-+-++++|++++++-+-+-+++|+++++++-+-+-++|++++ +--------------+--------------+--------------+--------------+--------------+--------------+--------------+---- ~:~ ----------+ ++++-+-+-+| ||||3|4|5|| ++++-+-+-+| ----------+ sub_ary_axs_progression (3 4 5) (2 3 4 3 reshape (tell 100)) 1 hasn't been tested on valance ary > 1 # loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' IF flag_debug THEN write 'loading factorial' ; ENDIF ; #] factorial IS OP int - res ipsa loquitor # 28Apr2022 initial factorial IS OP int { IF (= 1 int) THEN 1 ELSE int * (factorial (int - 1)) ENDIF } # loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' IF flag_debug THEN write 'loading ary_nComb_itmCombinationLL' ; ENDIF ; #] ary_nComb_itmCombinationLL IS OP ary n_combo - Howell? algorithm for combinations of a list # 28Apr2022 nothing done - placeholder, Smillie 1986 code has convoluted version # IF flag_break THEN BREAK ; ENDIF ; ary_nComb_itmCombinationLL IS OP ary n_combo { LOCAL teller ; IF flag_break THEN BREAK ; ENDIF ; aryShape := * (gage shape ary) ; n_combos := (/ EACH factorial aryShape (aryShape - n_combo)) / (factorial n_combo) ; IF (1000 < n_combos) THEN aryIdxA := ary_get_idxAll ary ; idxL := null ; FOR i WITH ( tell n_combo) DO FOR j WITH ((tell (n_combo - i)) + i) DO idxL := link idxL [i j] ; ENDFOR ; ENDFOR ; ELSE idxL := fault '?acombi01' ; ENDIF ; idxL } # fault codes : #? ary_combinationsTo_idxL ?acombi01 n_combinations > 1k, limited to avoid combinatorial explosions # 28Apr2022 tests ary := `a `b `c `d ary_nComb_itmCombinationLL (tell 4) ary_nComb_itmCombinationLL (tell 18) 4 # ary_permuteSlc IS OP ary - to generate permutations, see : # "$d_Qndfs"'Smillie UAlberta - statistics 1987/Smillie003 - permutations & combination.ndf' # - cute, but lousy [transparency, debug] # loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' IF flag_debug THEN write 'loading ary_nComb_itmPermuteHeapLL' ; ENDIF ; #] ary_nComb_itmPermuteHeapLL IS OP ary nCombos - Heap algorithm for permutations of a list # 29Nov2021 initial # 28Apr2022 converted to QNial, recursive, revamped # IF flag_break THEN BREAK ; ENDIF ; ary_nComb_itmPermuteHeapLL IS OP ary nCombos { LOCAL a aryShape factorialL i shaper ; IF flag_break THEN BREAK ; ENDIF ; shaper := gage shape ary ; IF (= 1 shaper) THEN ary ELSE FOR i WITH (tell shaper) DO a := ary_nComb_itmPermuteHeapLL (front ary) nCombos ; IF (1 = (mod shaper 2)) THEN % if shaper is odd, swap 0th i.e (first) and (shaper-1)th i.e (last) element ; tmp := a@[0] ; a@(0) := a@[shaper - 1] ; a@[shaper - 1] := tmp ; ELSE % If shaper is even, swap ith and (shaper-1)th i.e (last) element ; tmp := a@[i] ; a@(i) := a@[shaper - 1] ; a@[shaper - 1] := tmp ; ENDIF ; ENDFOR ; a ENDIF } # 28Apr2022 tests ary_nComb_itmPermuteHeapLL (1 2 3) 3 ary_permuteHeap ary ary_permuteHeap (3 4 reshape (tell 12)) # I used : https://www.geeksforgeeks.org/heaps-algorithm-for-generating-permutations/ https://medium.com/@rwillt/two-very-different-algorithms-for-generating-permutations-412e8cc0039c https://www.cs.utexas.edu/users/djimenez/utsa/cs3343/lecture25.html permutations blow up fast (exponentially?) - n=10 is slow for simple number lists HeapPermute_lst lst { % if size becomes 1 then prints the obtained permutation ; IF (size = 1) THEN write a ; ENDIF ; for (int i = 0; i < size; i++) { heapPermutation(a, size - 1, n); % if size is odd, swap 0th i.e (first) and (size-1)th i.e (last) element ; if (size % 2 == 1) swap(a[0], a[size - 1]); % If size is even, swap ith and (size-1)th i.e (last) element ; else swap(a[i], a[size - 1]); } } # loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' IF flag_debug THEN write 'loading ary_nComb_itmPermutationLLTo_idxL' ; ENDIF ; #] ary_nComb_itmPermutationLLTo_idxL IS OP ary nCombos - Heap algorithm for permutations of a list #] won't run if > 1k permutations, but should add file output [option, version] # 28Apr2022 wrapper for core optr ary_nComb_itmPermutationLL ary_nComb_itmPermutationLLTo_idxL IS OP ary nCombos { LOCAL aryShape factorialL i n_permis size ; IF flag_break THEN BREAK ; ENDIF ; aryShape := * (gage shape ary) ; factorialL := nCombos take (reverse count nCombos) ; n_permis := * EACH factorial factorialL ; IF (1000 < n_permis) THEN idxL := list ary_get_idxAll ary ; idxL := ary_nComb_itmPermuteHeapLL idxL nCombos ; ELSE idxL := fault '?acpermi01' ; ENDIF ; idxL } # fault codes : #? ary_nCombos_permutationsHeapTo_idxL ?acpermi01 n_permutations > 1k, limited to avoid combinatorial explosions # 28Apr2022 tests ary := tell 10 ary_permuteHeap ary ary_permuteHeap (3 4 reshape (tell 12)) #] +-----+ #] Matrix ops - symbolic through semi-symbolic through numeric IF flag_debug THEN write 'loading vector_from_list' ; ENDIF ; #] vector_from_list IS OP c_r lista - creates a vector from a list (legacy - don't use this for new code!) # needed for strings.ndf # I'm not sure when this optr was created - 09Feb2013 <= date <= 2018? # 06Sep2021 vector_from_list : must convert any lista solitaries to a (1 1) array?? (nyet - not desirable!) # 07Sep2021 moved here from 'matrix operations ...ndf' # 10Sep2021 legacy - wrong optr naming # should check that a list is input, not higher dimension vector_from_list IS OP c_r lista { listv := lista ; IF c_r = 'row' THEN 1 (gage shape lista) reshape listv ELSEIF c_r = 'col' THEN (gage shape lista) 1 reshape listv ELSE '?vector_from_list - improper column/row specification' ENDIF } # olde code - may be required in some calling optrs (eg str_findPositionsOf_subStrL) # example from str_findPositionsOf_subStrL : is_solitary := = null (EACH (gage shape) listv) ; IF (OR is_solitary) THEN indxs := is_solitary sublist (tell (gage shape) listv) ; listv#(indxs) := EH solitary listv#(indxs) ; ENDIF ; IF flag_debug THEN write 'loading lst_convertTo_vector' ; ENDIF ; #] lst_convertTo_vector IS OP lista c_r - creates a vector from a list # needed for strings.ndf # I'm not sure when this optr was created - 09Feb2013 <= date <= 2018?, adapted from vector_from_list # 06Sep2021 lst_convertTo_vector : must convert any lista solitaries to a (1 1) array?? (nyet - not desirable!) # 07Sep2021 moved here from 'matrix operations ...ndf' # should check that a list is input, not higher dimension lst_convertTo_vector IS OP lista c_r { listv := lista ; IF c_r = 'row' THEN 1 (gage shape lista) reshape listv ELSEIF c_r = 'col' THEN (gage shape lista) 1 reshape listv ELSE '?lst_convertTo_vector - improper column/row specification' ENDIF } #] +-----+ #] Investments # loaddefs link d_Qndfs 'math - [quick, handy] stuff.ndf' IF flag_debug THEN write 'loading vector_from_list' ; ENDIF ; #] PEratio_calc IS OP earnGrwth discRate Treasury10yrRate TreasuryDiscRate - estimate PE now # 01Nov2022 initial # Missing [CPI, PPI, financial asset] inflations PEratio_calc IS OP n_years earnGrwth discRate Treas_10yrRate Treas_disRate { {1 - (power ((1 + earnGrwth)/(1 + discRate)) n_years)} / {1 - ((1 + Treas_10yrRate) / (1 + Treas_disRate)) } } # 01Nov2022 usage for Eli Lilly earnGrwth 20%/y for 10 years (1.2^10 = 6.19); 50% -> 57.7; 100% -> 1024 discRate 7%/y Treas_10yrRate 4.5%/y Treas_disRate 0%/y # qnial> PEratio_calc 10 0.2 0.07 4.5 0.0 0.477237 >> WOW!! PE_now = 350/7.85 = 44.87 Eli Lilly : what portion will be incretin sales? #**************************** # Instructions # loaddefs_ended f_mathHandy ; # enddoc