Solve problem 5 task 1 in linear time
This commit is contained in:
parent
fb28ee869f
commit
324122088b
1 changed files with 24 additions and 21 deletions
|
@ -60,28 +60,31 @@
|
||||||
|
|
||||||
⍝ 2020 APL Problem Solving Competition Phase II
|
⍝ 2020 APL Problem Solving Competition Phase II
|
||||||
⍝ Problem 5, Task 1 - rr
|
⍝ Problem 5, Task 1 - rr
|
||||||
⍝ ((1+⊢)⊥⊣) computes the total return for a vector of
|
|
||||||
⍝ amounts ⍺ and a vector of rates ⍵. It is applied to
|
|
||||||
⍝ every prefix subarray of amounts and rates to get
|
|
||||||
⍝ all intermediate values. Quadratic complexity.
|
|
||||||
rr←(,\⊣)((1+⊢)⊥⊣)¨(,\⊢)
|
|
||||||
|
|
||||||
∇ r←amounts rr2 rates;recur
|
⍝ First solution: ((1+⊢)⊥⊣) computes the total return
|
||||||
⍝ Second solution
|
⍝ for a vector of amounts ⍺ and a vector of rates
|
||||||
⍝ The recurrence relation (⍺ is the previous value,
|
⍝ ⍵. It is applied to every prefix subarray of amounts
|
||||||
⍝ ⍵[1] is the current amount, and ⍵[2] is the
|
⍝ and rates to get all intermediate values. However,
|
||||||
⍝ current rate).
|
⍝ this has quadratic complexity.
|
||||||
recur←{⍵[1]+⍺×1+⍵[2]}
|
⍝ rr←(,\⊣)((1+⊢)⊥⊣)¨(,\⊢)
|
||||||
⍝ Because APL evaluates from right to left, we can't
|
|
||||||
⍝ use Scan directly, as recur is not associative. We
|
⍝ Second solution: We want to be able to use the
|
||||||
⍝ need something like Haskell's scanl, that will
|
⍝ recurrence relation (recur) and scan through the
|
||||||
⍝ accumulate left-to-right and accumulate
|
⍝ vectors of amounts and rates, accumulating the total
|
||||||
⍝ left-to-right. Scan accumulates left-to-right but
|
⍝ value at every time step. However, APL evaluation is
|
||||||
⍝ evaluates right-to-left. This solution therefore
|
⍝ right-associative, so a simple Scan
|
||||||
⍝ folds for all subarrays, but it is not good in
|
⍝ (recur\amounts,¨values) would not give the correct
|
||||||
⍝ terms of performance.
|
⍝ result, since recur is not associative and we need
|
||||||
r←{⊃⊃f⍨/(⌽⍵↑amounts,¨rates),⊂0 0}¨⍳⍴amounts
|
⍝ to evaluate it left-to-right. (In any case, in this
|
||||||
∇
|
⍝ case, Scan would have quadratic complexity, so would
|
||||||
|
⍝ not bring any benefit over the previous solution.)
|
||||||
|
⍝ What we need is something akin to Haskell's scanl
|
||||||
|
⍝ function, which would evaluate left to right in O(n)
|
||||||
|
⍝ time. This is what we do here, accumulating values
|
||||||
|
⍝ from left to right. (This is inspired from
|
||||||
|
⍝ https://dfns.dyalog.com/c_ascan.htm, although
|
||||||
|
⍝ heavily simplified.)
|
||||||
|
rr←{recur←{⍵[1]+⍺×1+⍵[2]} ⋄ 1↓⌽⊃{(⊂(⊃⍵)recur⍺),⍵}/⌽⍺,¨⍵}
|
||||||
|
|
||||||
∇ r←cashFlow pv rates
|
∇ r←cashFlow pv rates
|
||||||
⍝ 2020 APL Problem Solving Competition Phase II
|
⍝ 2020 APL Problem Solving Competition Phase II
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue