Skip to content

Instantly share code, notes, and snippets.

@adregan
Created June 8, 2023 15:58
Show Gist options
  • Save adregan/02a3c3b2114604e5c4a2fcc0f8aaf4d4 to your computer and use it in GitHub Desktop.
Save adregan/02a3c3b2114604e5c4a2fcc0f8aaf4d4 to your computer and use it in GitHub Desktop.
optimalChargeDischarge←{
⍝ ⍵ is a list of numbers
⍝ returns an array of 3 values (charge, discharge, revenue)
⎕IO←0 ⍝ zero based indexing is required
⍝ create table of differences between values
diffs←∘.(-⍨)⍨⍵ ⍝ flip subtraction as we are interested in the difference from left to right
mask←∘.<⍨⍳≢⍵ ⍝ Create a mask including only the upper right corner (excluding diagonal)
⍝ The upper right corner represents the differences that move forward in time
revs←diffs×mask ⍝ Revenues are obtained by multiplying the differences by the mask
max←⌈/⍣2⊢revs ⍝ 2 maximum reductions produces the maximum overall value
(⊃⍸max⍷revs),max ⍝ Return the location of the maximum spread and the maximum value
}
@adregan
Copy link
Author

adregan commented Jun 8, 2023

This is an example of a possible solution in an array language.

Given an input like 7 1 5 3 6 4, you can perform the outer product ∘.- with subtraction to find the differences between the values of the array as a table (where omega, ⍵, represents the input array)

.-0 6  2  4  1  3
¯6 0 ¯4 ¯2 ¯5 ¯3
¯2 4  0  2 ¯1  1
¯4 2 ¯2  0 ¯3 ¯1
¯1 5  1  3  0  2
¯3 3 ¯1  1 ¯2  0

Because we are interested in the difference from right to left (later time minus earlier time) we could negate the table or we could apply the C combinator—also known as flip—to subtraction to achieve this:

.(-)⍵

0 ¯6 ¯2 ¯4 ¯1 ¯3
6  0  4  2  5  3
2 ¯4  0 ¯2  1 ¯1
4 ¯2  2  0  3  1
1 ¯5 ¯1 ¯3  0 ¯2
3 ¯3  1 ¯1  2  0

One thing that we can observe is that the diagonal from upper left to bottom right represents a value diffed from itself and anything below that represents impossible states (differences between the past and future), so we'll mask those values. The following creates the boolean mask. We generate an array from 0 to the length of the input (≢⍵) using iota and perform the outer product with less than <.

.<0 1 1 1 1 1
0 0 1 1 1 1
0 0 0 1 1 1
0 0 0 0 1 1
0 0 0 0 0 1
0 0 0 0 0 0

and we can apply the mask to the diffs using multiplication × (effectively filling in the area we don't care about with zeros:

0 ¯6 ¯2 ¯4 ¯1 ¯3
0  0  4  2  5  3
0  0  0 ¯2  1 ¯1
0  0  0  0  3  1
0  0  0  0  0 ¯2
0  0  0  0  0  0

Now we just need to find the maximum value of the rows and columns with 2 max reductions ⌈/ (the first tells us the maximum of each row 0 5 1 3 0 0 and the second the max of those: 5. Now we can find the max in the table:

maxrevs

0 0 0 0 0 0
0 0 0 0 1 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

and get the indexes of the first maximum with find : 1 4 and return the values as the solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment