Search code examples
palindromeapl

Compressing Rather Large Table in APL


I am currently working on finding a palindrome of made from multiplying numbers of length 3 together (from 900 to 1000). I am able to generate a table of palindromes in binary (1/0). However, the compress function (/) is giving me an error regarding storage. I am not sure why compressing the given binary table would cause such an issue.

new_set ← (900 + ⍳100)
{(⊃⍵)≡⌽⊃⍵}¨ ⊂∘⍕¨ (new_set ∘.× new_set)
{(⊃⍵)≡⌽⊃⍵}¨ ⊂∘⍕¨ (new_set ∘.× new_set) / ∘⍕¨(new_set ∘.× new_set)
WS FULL: Maximum workspace is 512 kilobytes.

Edit: Changing new_set to (⍳10) produces the same solution on the third line as the line before it (binary).. Really need help with the compress function. Any help greatly appreciated.


Solution

  • Expanding on the answer by B. Wilson,

    So, the problem - We want to return the palindromes found in a multiplication table of the integers in the range of 900 to 1000.

    We can start with the range:

       n ← (900 + ⍳100)
    

    Straight-forward and as stated APL is right-associative, meaning functions apply to everything on the right, and one argument to the left. Given that, those parenthesis are superfluous and we can remove them.

    Next, to produce the table:

       n ∘.× n
    

    Great. Everyone loves outer product and as this problem is inherently O(n^2), there's not much we can do to avoid WS FULLs on larger arguments.

    Here's where a subtly is introduced - do we want the unique multiplications? For example, should we include 901×901, as well as both 902×901 and 901×902, if not - there are a few things we can do to reduce space.

       ⊃,/(1↓n)×,\¯1↓n
    

    This expression is one approach to avoid precisely those cases.

    Now for the palindromes. In APL, as identified, it's idiomatic to use boolean masks to filter elements.

    Your approach was

       {(⊃⍵)≡⌽⊃⍵}¨ ⊂∘⍕¨
    

    Works well! I'll note that the ⊂ is superfluous as we immediately perform the inverse operation upon function invocation.

    So, we can write:

       {⍵≡⌽⍵}∘⍕¨
    

    Finally, the filter. You noticed that each element of the mask isn't paired up with each element of the table. Right, For non-singleton masks / will filter along major cells. For example:

       1 0 1 / 3 3⍴⍳9
    1 3
    4 6
    7 9      
    

    So, to get around your issue, we can ravel (flatten) both sides beforehand:

       {(,{⍵≡⌽⍵}∘⍕¨⍵)/,⍵} n ∘.× n
    

    The complete solution! I'll posit some alternatives (minor changes) for investigation.

       {⍵/⍨(≡∘⌽⍨⍕)¨⍵}⊃,/(1↓n)×,\¯1↓n
    
       {⍵/⍨⍥,(≡∘⌽⍨⍕)¨⍵}∘.×⍨