# This file gives reference implementations of BQN primitives assuming
# limited initial functionality. Implementations are designed to be
# simple and not fast.
# In some cases an operation is defined with limited functionality at
# first and later expanded. For convenience, rather than renaming these
# limited versions, every primitive use refers to the most recent
# definition in source code, as if redefinitions shadowed previous
# primitive definitions.
#⌜
# LAYER 0: Assumed functionality
# Arithmetic on the implementation-defined number system
# LIMITED to the stated cases and atomic arguments.
+ # Add
- # Negate Subtract
× # Multiply
÷ # Reciprocal Divide
⋆ # Exponential Power
⌊ # Floor
= # Equals
≤ # Less Than or Equal to
# Other basic functionality that we need to assume
Type # 0 if 𝕩 is an array, 1 if a number, >1 otherwise
! # 𝕩 is 0 or 1; throw an error if it's 0
≢ # LIMITED to monadic case
⥊ # LIMITED to array 𝕩 and (×´𝕨)≡≢𝕩
⊑ # LIMITED to natural number 𝕨 and list 𝕩
_amend # {𝕨˙⌾(𝕗⊸⊑)𝕩} for list 𝕩
↕ # LIMITED to number 𝕩
Identity # Left or right identity of function 𝕏
⁼ # Inverse of function 𝔽
Fill # Enclosed fill value for 𝕩
HasFill # Whether 𝕩 has a fill value
#⌜
# LAYER 1: Foundational operators and functions
# Combinators
◶ ← {𝕨((𝕨𝔽𝕩)⊑𝕘){𝔽}𝕩} # LIMITED to number left operand result
˙ ← {𝕩⋄𝕗}
⊘ ← {𝔽𝕩;𝕨𝔾𝕩}
⊢ ← {𝕩}
⊣ ← {𝕩;𝕨}
˜ ← {𝕩𝔽𝕨⊣𝕩}
∘ ← {𝔽𝕨𝔾𝕩}
○ ← {(𝔾𝕨)𝔽𝔾𝕩}
⊸ ← {(𝔽𝕨⊣𝕩)𝔾𝕩}
⟜ ← {(𝕨⊣𝕩)𝔽𝔾𝕩}
⍟ ← {𝔾◶⊢‿𝔽} # LIMITED to boolean right operand result
IsArray ← 0=Type
Int ← (1=Type)◶⟨0,⌊⊸=⟩ # Is an integer (including ¯∞ and ∞)
Nat ← (1=Type)◶⟨0,0⊸≤×⌊⊸=⟩ # Is a natural number
≢ ↩ IsArray◶⟨⟩‿≢ # LIMITED to monadic case
⋈ ← {⟨𝕩⟩;⟨𝕨,𝕩⟩}
# LIMITED to numeric arguments for arithmetic cases
√ ← ⋆⟜(÷2) ⊘ (⋆⟜÷˜) # Higher precision allowed; see spec
∧ ← ×
∨ ← +-×
¬ ← 1+-
| ← ×⟜× ⊘ {𝕩-𝕨×⌊𝕩÷𝕨} # Higher precision allowed; see spec
< ← {⟨⟩⥊⟨𝕩⟩} ⊘ (¬≤˜)
> ← (¬≤)
≥ ← !∘0 ⊘ (≤˜)
≠ ← Length ⊘ (¬=)
= ↩ Rank ⊘ =
× ↩ 0⊸(<->) ⊘ ×
# ⌊⌈ defined after pervasion below
¨ ← _eachm # LIMITED to monadic case and array 𝕩
´ ← _fold
Rank ← 0⊑≢∘≢
Length ← (0<Rank)◶⟨1,0⊑≢⟩
_eachm←{
# Set 𝕨⊑⥊𝕩 to 𝔽𝕨⊑⥊𝕩 for each index 𝕨
(≢𝕩) ⥊ 0 𝔽{𝕨 (+⟜1 𝕊 𝔽∘⊑ 𝕨_amend ⊢)⍟(<⟜≠) 𝕩} ⥊𝕩
}
_fold←{
! 1==𝕩
l←≠v←𝕩 ⋄ F←𝔽
# If 𝕨 isn't given, start with the last cell of 𝕩
r←𝕨 (0<l)◶{𝕩⋄Identity f}‿{l-↩1⋄l⊑𝕩}⊘⊣ 𝕩
# Apply r↩(𝕨⊑v)F r for 𝕨 from l to 0
l {𝕨 -⟜1⊸(⊣𝕊⊑⟜v⊸F)⍟(>⟜0) 𝕩} r
}
# Re-add identities for needed redefined functions
identity { f‿i←𝕨 ⋄ f˙⊸=◶𝕩‿i }´↩ ⟨ ×‿1, ∨‿0, ∧‿1 ⟩
#⌜
# LAYER 2: Pervasion
# _pervasive should be applied to all arithmetic as an IMPLICIT STEP:
# +-×÷⋆√⌊⌈|¬ and dyadic ∧∨<>≠=≤≥
# Join: elements 0…≠𝕨 come from 𝕨 and the rest from 𝕩
∾ ← {k←≠𝕨⋄k⊸≤◶⟨⊑⟜𝕨,-⟜k⊑𝕩˜⟩¨↕k+≠𝕩} # LIMITED to two list arguments
ToArray ← IsArray◶<‿⊢
_table←{
m←≠a←⥊𝕨 ⋄ n←≠b←⥊𝕩 ⋄ F←𝔽 ⋄ i←0
# 𝕩 is the result index; maintain index i in 𝕨 and compute 𝕩-n×i in 𝕩
(𝕨∾○≢𝕩)⥊{i+↩𝕩=n×i+1⋄(i⊑a)F(𝕩-n×i)⊑b}¨↕m×n
}
_eachd←{
_e←{ # 𝕨 has rank less than or equal to 𝕩
k←≠p←≢𝕨 ⋄ q←≢𝕩
! ∧´(⊑⟜p=⊑⟜q)¨↕k # p≡k↑q
l←×´(q⊑˜k⊸+)¨↕q≠⊸-k # ×´k↓q, size of a cell in 𝕩 (pairs with a unit)
a←⥊𝕨 ⋄ b←⥊𝕩
# In the inner function, 𝕨 indexes into a and (l×𝕨)+𝕩 into b
q⥊ (≠a) (⊑⟜a 𝔽 l⊸×⊸+⊑b˙)_table○↕ l
}
>○=◶⟨𝔽_e,𝔽˜_e˜⟩
}
⌜ ← {(𝔽_eachm)⊘(𝔽_table)○ToArray}
¨ ↩ {(𝔽_eachm)⊘(𝔽_eachd)○ToArray}
# Pervasion recurses whenever any argument is an array
_pervasive←{
⊢⊘∨○IsArray◶⟨𝔽, 𝔽{𝕨𝔽_pervasive𝕩}¨⟩
}
# The modifier _pervasive applies to all arithmetic.
# For practicality when testing, basic functions are made pervasive
# instead, which works for all arithmetic except dyadic ⌊⌈.
⌊ ↩ ⌊ ⊘ ({(𝕨>𝕩)⊑𝕨‿𝕩}_pervasive)
⌈ ← -∘⌊∘- ⊘ ({(𝕨<𝕩)⊑𝕨‿𝕩}_pervasive)
#⌜
# LAYER 3: Remove other limits
# After this all implementations are full except ∾; ↕ is monadic only
Deshape ← IsArray◶{⟨𝕩⟩}‿⥊
Reshape←{
! 1≥=𝕨
s←Deshape 𝕨
sp←+´p←¬Nat⌜s # Number of non-numeric elements
! 1≥sp # At most one allowed
n←≠d←Deshape 𝕩
l←sp◶(×´)‿{
# Handle computed shapes
lp←×´p 1⍟⊣¨𝕩 # Product of numeric elements
! 0<lp # Would imply division by zero
I←+´↕∘≠⊸× # Index from boolean list with a single 1 (⊑/)
e←⟨∘,⌊,⌽,↑⟩=p I⊸⊑s # Pick element and compare with possibilities
! +´e # Must be one of ∘⌊⌽↑
t←I e # Which one is it?
a←(2⌊t)◶⟨{!Nat𝕩⋄𝕩},⌊,⌈⟩n÷lp # Compute and round length
s↩p a⍟⊣¨s # Insert it back into the shape
# For element ↑, append fill elements to d if necessary
{d∾↩(Fill d)⌜↕𝕩-n⋄n↩𝕩}⍟(n⊸<)⍟(3=t)lp×a
} s
# Size of 𝕩 is n, so n|𝕨 is a cyclic index into d. Final size is l.
s ⥊ (↕l) {!0<n⋄⊑⟜𝕩¨n|𝕨}⍟(l≠n) d
}
Range←{
I ← {!Nat𝕩 ⋄ ↕𝕩} # 𝕩 is a number
M ← {!1==𝕩 ⋄ (<⟨⟩)⋈⊸∾⌜´I¨𝕩} # 𝕩 is a list
IsArray◶I‿M 𝕩
}
Pick1←{
! 1==𝕨 # Index must be a list
! 𝕨=○≠s←≢𝕩 # with length equal to rank of 𝕩
! ∧´Int¨𝕨 # consisting of integers
! ∧´𝕨(≥⟜-∧<)s # in the range [-l,l) where l is an axis length
𝕨 +↩ s×𝕨<0 # Wrap negatives
i ← 0(⊑⟜𝕨+⊑⟜s×⊢)´-↕⊸¬≠𝕨 # Compute index with a reverse fold
i ⊑ ⥊𝕩
}
# Recurse if depth is greater than 1
Pickd ← {∨´⥊IsArray¨𝕨}◶Pick1‿{Pickd⟜𝕩¨𝕨}
Pick ← IsArray◶⥊‿⊢⊸Pickd
First ← {!0<≠𝕩 ⋄ 0⊑𝕩} Deshape
# Two arrays match if all the following conditions hold:
match←{¬∘(0⊑𝕨)◶(1⊑𝕨)‿𝕩}´⟨
⟨≠○IsArray , 0⟩ # They are both arrays, or both not arrays
⟨¬IsArray∘⊢, =⟩ # They are equal atoms, OR
⟨≠○= , 0⟩ # They have equal ranks
⟨∨´≠○≢ , 0⟩ # And equal length along each axis
{∧´⥊𝕨Match¨𝕩} # And matching elements
⟩
Depth ← IsArray◶0‿{1+0⌈´Depth¨⥊𝕩}
⊑ ↩ First ⊘ Pick
⥊ ↩ Deshape ⊘ Reshape
↕ ↩ Range
◶ ↩ {𝕨((𝕨𝔽𝕩)⊑𝕘){𝔽}𝕩} # Same definition with updated Pick
≡ ← Depth ⊘ Match
≢ ↩ ≢ ⊘ (¬Match)
#⌜
# LAYER 4: Operators
> ↩ Merge⍟IsArray ⊘ >
≍ ← >∘⋈
⎉ ← _rankOp_
⚇ ← _depthOp_
⍟ ↩ _repeat_
˘ ← {𝔽⎉¯1}
˝ ← _insert
` ← _scan
Drop1 ← {⊑⟜𝕩¨𝕨+↕𝕨-˜≠𝕩} # Drop from list
Cell ← Drop1⟜≢ # (-𝕨)-cell shape of array 𝕩
# Merge: if empty, append fill shape to array shape to reshape fill
# Otherwise, run all element ravels together
Merge←(0<≠∘⥊)◶((∾○≢⥊⊢)⟜Fill⍟HasFill)‿{
c←≢⊑𝕩
! ∧´⥊(c≡≢)¨𝕩 # Shapes must match
𝕩⊑⟜ToArray˜⌜↕c # Shape is (≢𝕩)∾c, with corresponding axis structure
}
# Check if ranks/depths are valid: list of one to three integers
# Return ⥊𝕩
ValidateRanks←{
! 1≥=𝕩
𝕩⥊↩
! (1⊸≤∧≤⟜3)≠𝕩
! ∧´Int¨𝕩
𝕩
}
# Extract the appropriate ranks/depths for a call
# Use negative indexing and wrap with |
_ranks ← {⟨2⟩⊘⟨1,0⟩ ((⊣-1+|)˜⟜≠⊑¨<∘⊢) ValidateRanks∘𝔽}
_depthOp_←{
n ← 𝕨 𝔾_ranks 𝕩
neg←0>n ⋄ F←𝔽
_d←{
R←(𝕗+neg)_d # Increment
rec ← 2⥊(neg∧𝕗≥0)∨(0⌈𝕗)≥𝕨⋈○≡𝕩 # Whether to recurse into 𝕨⊣𝕩 and 𝕩
𝕨 rec◶(⟨R¨,R⟜(𝕩˙)¨∘⊣⟩≍⟨(𝕨{𝕏;𝕨˙⊸𝕏}r)¨∘⊢,F⟩) 𝕩
}
𝕨 n _d 𝕩
}
_rankOp_←{
k←𝕨(⋈○= 0⊸≤◶⟨⌊⟜-,0⌈-⟩¨ 𝔾_ranks)𝕩 # Effective frame length
# Enclose (-𝕨)-cells of 𝕩, that is, <⎉((=𝕩)-𝕨) 𝕩
EncK←{
f←⊑⟜(≢𝕩)¨↕𝕨 # 𝕨↑≢𝕩
c←×´s←𝕨Cell𝕩
f⥊⊑⟜(⥊𝕩)¨∘((s⥊↕c)+c×⊢)¨↕×´f
}
# Use <⊢ if k=0 (required to handle atoms correctly), and <⌜⊢ if k==𝕩
Enc←(>⟜0×1+≥⟜=)◶⟨<⊢,EncK,<⌜⊢⟩
> ((⊑k)Enc𝕨) 𝔽¨ ((1-˜≠)⊸⊑k)Enc𝕩
}
_insert←{
! 1≤=𝕩
𝕨 𝔽´ <˘𝕩
}
_scan←{
! IsArray 𝕩
! 1≤=𝕩
c←×´cs←1 Cell 𝕩
! (cs≡≢)𝕨
l←≠r←⥊𝕩 ⋄ F←𝔽
𝕨 (0<l)◶⊢‿{
# Initial cell: cs⥊𝕨F¨c↑𝕩 if 𝕨 is given
{r↩≥⟜c◶⟨⊑⟜(⥊𝕩)⊸F,⊢⟩⟜(⊑⟜r)¨↕l}𝕨
# For non-initial elements, apply F to index i-c and i
# Must be ordered to compute value i-c first
(≢𝕩) ⥊ r {((𝕨-c)F○(⊑⟜𝕩)𝕨)𝕨_amend𝕩}´ (l-1)-↕l-c
} 𝕩
}
_repeat_←{
n←𝕨𝔾𝕩 # Repetition numbers
l←u←0 # Min and max repetitions
{!Int𝕩⋄!∞>|𝕩⋄l⌊↩𝕩⋄u⌈↩𝕩}⚇0 n
b←𝕨{⊢;𝕨{𝕗˙⊸𝕏}}0 # Bind 𝕨 to 𝕏 if necessary
i←⟨𝕩⟩⋄P←{𝕏⊣}∘B⊸{𝕎`i∾↕𝕩} # P makes a list of repetition 0, 1, …
pos←𝕗 P u # Positive repetitions
neg←𝕗 0⊸<◶⟨i,{𝕏⁼}⊸P⟩ -l # Negative repetitions
(|⊑<⟜0⊑pos‿neg˙)⚇0 n
}
#⌜
# LAYER 5: Structural functions
⊏ ← 0⊸Select ⊘ Select
↑ ← Prefixes ⊘ Take
↓ ← Suffixes ⊘ Drop
↕ ↩ ↕ ⊘ Windows
» ← Nudge ⊘ ShiftBefore
« ← NudgeBack ⊘ ShiftAfter
⌽ ← Reverse ⊘ Rotate
/ ← Indices ⊘ Replicate
# Multi-axis primitive: 𝔾 is applied to 𝕨 and determines the maximum
# depth of the one-axis case
_onAxes_←{
F←𝔽
(𝔾<≡)∘⊣◶{ # One axis
! 1≤=𝕩
𝕨F𝕩
}‿{ # Multiple axes
! 1≥=𝕨
! (≠𝕨)≤=𝕩
R←{(⊑𝕨)F(1 Drop1 𝕨)⊸R˘𝕩}⍟{0<≠𝕨} # Recurse, then handle one axis
𝕨R𝕩
}⟜ToArray
}
SelSub←{
! IsArray 𝕨
! ∧´⥊Int¨ 𝕨 # All integers
! ∧´⥊ 𝕨 (≥⟜-∧<) ≠𝕩 # In range
𝕨 +↩ (≠𝕩)×𝕨<0 # Wrap negatives
c←×´s←1 Cell 𝕩
⊑⟜(⥊𝕩)¨(c×𝕨)+⌜s⥊↕c # Extend each index to a whole cell
}
Select←ToArray⊸(SelSub _onAxes_ 1)
JoinTo←{
s←𝕨⋈○≢𝕩
a←1⌈´k←≠¨s # Argument ranks k and result rank a
! ∧´1≥a-k # Can add at most one axis
c←(k¬a)+⟜(↕a-1)⊸⊏¨s # Cell shapes
! ≡´c
l←+´(a=k)⊣◶1‿(⊑⊢)¨s # Total length
(⟨l⟩∾⊑c)⥊𝕨∾○⥊𝕩
}
Take←{
T←{
! Int 𝕨
l←≠𝕩
# Indices, with clamp and modulus so that fills are all l
i←(l+1)|¯1⌈l⌊((𝕨<0)×𝕨+l)+↕|𝕨
# Don't get the fill if not needed, as it can error
i⊏JoinTo⟜(1⊸Cell⥊Fill)⍟(∨´l=i)𝕩
}
# Add leading 1s to shape of 𝕩 first if necessary
𝕨 T _onAxes_ 0 (⟨1⟩⥊˜0⌈𝕨-○≠⊢)⊸∾∘≢⊸⥊𝕩
}
Drop←{
s←(≠𝕨)(⊣↑⊢∾˜1⥊˜0⌈-⟜≠)≢𝕩 # Padded shape
((s׬⊸-𝕨>0)+(-s)⌈s⌊𝕨)↑𝕩 # Clamp and complement, then use Take
}
Prefixes ← {!1≤=𝕩 ⋄ (↕1+≠𝕩)Take¨<𝕩}
Suffixes ← {!1≤=𝕩 ⋄ (↕1+≠𝕩)Drop¨<𝕩}
ShiftBefore ← {!𝕨1⊸⌈⊸≤○=𝕩 ⋄ ( ≠𝕩) ↑ 𝕨 JoinTo 𝕩}
ShiftAfter ← {!𝕨1⊸⌈⊸≤○=𝕩 ⋄ (-≠𝕩) ↑ 𝕩 JoinTo 𝕨}
Nudge ← (1↑0↑⊢)⊸ShiftBefore
NudgeBack ← (1↑0↑⊢)⊸ShiftAfter
Windows←{
! 1≥=𝕨
! (≠𝕨)≤=𝕩
! ∧´Nat¨⥊𝕨
s←𝕨≠⊸↑≢𝕩
! ∧´𝕨≤1+s
𝕨{
i ← s(¬+⌜○↕⊢)⥊𝕨 # Cell indices in 𝕩: add leading and trailing axes
c ← ><¨⊸⊏⟜𝕩¨i # Select the cells
((≢i)∾𝕨≠⊸↓≢𝕩)⥊c # Reshape in case it's empty
}⍟(0<≠𝕨)𝕩
}⟜ToArray
Reverse ← {!1≤=𝕩 ⋄ (-↕⊸¬≠𝕩)⊏𝕩}
Rotate ← {!Int𝕨 ⋄ l←≠𝕩⋄(l|𝕨+↕l)⊏𝕩} _onAxes_ 0
Indices←{
! 1==𝕩
! ∧´Nat¨𝕩
⟨⟩∾´𝕩⥊¨↕≠𝕩
}
Rep ← Indices⊸⊏
# Expand unit 𝕨 to length of 𝕩, and check length match for a list
Replicate ← ({0<=𝕨}◶(⊣˘)‿{!𝕨=○≠𝕩⋄𝕨}Rep⊢) _onAxes_ (1-0=≠)
#⌜
# LAYER 6: Everything else
∾ ↩ Join ⊘ JoinTo
⊔ ← GroupInds ⊘ Group
⍉ ← Transpose ⊘ ReorderAxes
∊ ← MarkFirst ⊘ (IndexOf˜<≠∘⊢)
⍷ ← ∊⊸/ ⊘ Find
⊐ ← ⍷⊸IndexOf ⊘ IndexOf
⍋ ← Cmp _grade ⊘ ( Cmp _bins)
⍒ ← -∘Cmp _grade ⊘ (-∘Cmp _bins)
∧ ↩ ⍋⊸⊏ ⊘ ∧
∨ ↩ ⍒⊸⊏ ⊘ ∨
⊒ ← OccurrenceCount⊘ ProgressiveIndexOf
identity { f‿i←𝕨 ⋄ f˙⊸=◶𝕩‿i }´↩ ⟨ ∨‿0, ∧‿1 ⟩
# Join of empty: multiply shape by (leading) fill shape
JoinEmpty ← ({!𝕨≤○≠𝕩⋄𝕨≠⊸((𝕨×↑)∾↓)𝕩}○≢⥊⊢)⟜Fill⍟HasFill
Join←(0<≠∘⥊)◶⟨JoinEmpty, (0<=)◶{!IsArray𝕩⋄>𝕩}‿{
! IsArray 𝕩
s←≢¨𝕩
a←(≢𝕩){(s⊑˜(j=𝕩)⊸×)¨↕𝕨}¨j←↕r←=𝕩 # Skeleton: elements 0,0,…k,…0 along each axis
h←(¬⟜(⌈´)≠¨)¨a # Which positions have the axis
! ∧´∧´¨0≤h # Rank can only change by 1 along a line
o←+`⊑¨h # Starting position of each axis in ⊑𝕩
t←(¯1⊑o)↓⊑s # Trailing axes
l←h{𝕎𝕩}¨˜(»o){⊣◶⟨1,𝕨⊸⊑⟩¨⟜𝕩}¨a # Length of each position on each axis
! s≡(<t)∾⌜´h⥊¨¨l # Shape agreement
i←(<⟨⟩)∾⌜´h{((↕¯1⊸⊑)-𝕩/𝕨⥊¨»)+`𝕩}¨l # Indices: ∾↕∘≢¨𝕩 if no trailing axes
>i<¨⊸⊏⍟(0<≠∘⊣)¨l/𝕩
}⟩
Group←{
! IsArray 𝕩
𝕨 ⋈∘ToArray⍟(2>≡)↩
! 1==𝕨
{!∧´Int¨𝕩⋄!∧´¯1≤𝕩}∘⥊¨𝕨 # Atoms in 𝕨 must be integers ≥¯1
n←+´r←=¨𝕨 # Number of ranks grouped for each result axis (r); total (n)
! n≤=𝕩
ld←(∾≢⌜𝕨)-n↑≢𝕩 # Extra elements
! ∧´(0⊸≤∧≤⟜(r/1=r))ld # Must be 0 extra, or possibly 1 for rank 1 components
dr←r⌊(0»+`r)⊏ld∾⟨0⟩ # Whether each result axis has a minimum length
s←dr⊣◶⟨0,¯1⊸⊑⟩¨𝕨 # Minimum shape required by extra elements
𝕨↩dr(⥊¯1⊸↓⍟⊣)¨𝕨 # Remove extra elements; deshape components
s⌈↩1+¯1⌈´¨𝕨 # Result shape
𝕩↩((≠¨𝕨)∾n↓≢𝕩)⥊𝕩 # Merge axes of 𝕩 that are handled together in 𝕨
(𝕨⊸=/𝕩˙)¨↕s # Construct each result group by filtering
}
GroupInds←{
! 1==𝕩
𝕩 ⊔ ↕ (1<≡)◶≠‿(∾≢¨) 𝕩
}
# Searching: use all-pairs comparisons
IndexOf←{
c←1-˜=𝕨
! 0≤c
! c≤=𝕩
𝕨 ∧○(0<≠)⟜⥊◶⟨0⥊˜c-⊸↓≢∘⊢, (+˝∧`)≢⎉c⎉c‿∞⟩ ToArray 𝕩
}
MarkFirst←{
! 1≤=𝕩
u←0↑𝕩
(0<≠)◶⟨⟨⟩,{⊑𝕩∊u}◶{u∾↩𝕩⋄1}‿0˘⟩𝕩
}
Find←{
r←=𝕨
! r≤=𝕩
𝕨 ≡⎉r ((1+r-⊸↑≢𝕩)⌊≢𝕨)⊸↕⎉r 𝕩
}○ToArray
ReorderAxes←{
𝕩<⍟(0=≡)↩
! 1≥=𝕨
𝕨⥊↩
! (≠𝕨)≤=𝕩
! ∧´Nat¨𝕨
r←(=𝕩)-+´¬∊𝕨 # Result rank: duplicates in 𝕨 reduce it
! ∧´𝕨<r
𝕨∾↩𝕨(¬∘∊˜/⊢)↕r # Add unused axes to the end
(𝕨⊸⊏⊑𝕩˙)¨↕⌊´¨𝕨⊔≢𝕩 # Reorder indices to select result elements
}
Transpose←(0<=)◶⟨ToArray,(=-1˙)⊸ReorderAxes⟩
# Sorting
Cmp ← ⌈○IsArray◶{ # No arrays
𝕨(>-<)𝕩
}‿{ # At least one array
e←𝕨-˜○(∨´0=≢)𝕩
𝕨(e=0)◶e‿{
# Backup ordering by rank
c←𝕨×∘-○(IsArray+=)𝕩
# l is the number of elements to compare
# Also update backup ordering c if lengths differ
s←≢𝕨 ⋄ t←≢𝕩 ⋄ r←𝕨⌊○=𝕩
l←s{i←+´∧`𝕨=𝕩⋄m←×´i↑𝕨⋄{c↩×-´𝕩⋄m×↩⌊´𝕩}∘(⊑¨⟜𝕨‿𝕩)⍟(r⊸>)i⋄m}○(r↑⌽)t
# Compare elements, stopping at the first difference
a←⥊𝕨⋄b←⥊𝕩
Trav←(=⟜l)◶{Trav∘(1+𝕩)⍟(0⊸=)a Cmp○(𝕩⊸⊑)b}‿c
Trav 0
}𝕩
}
_grade←{
! 1≤=𝕩
# Compare all cells and break ties with indices
# Then sum and invert as a permutation
i⊐˜+´˘(𝔽⎉∞‿¯1⎉¯1‿∞˜𝕩)(⌈⟜0+=⟜0⊸×)>⌜˜i←↕≠𝕩
}
_bins←{
c←1-˜=𝕨 # Rank of compared cells
! 0≤c
! c≤=𝕩
LE←𝔽⎉c≤0˙ # Does 𝕨 precede 𝕩?
! (0<≠)◶⟨1,∧´·LE˝˘2↕⊢⟩𝕨 # 𝕨 must be ordered
𝕨 (0<≠𝕨)◶⟨0⎉c∘⊢,+˝LE⎉¯1‿∞⟩ 𝕩 # Number of 𝕨 cells preceding or matching each 𝕩 cell
}
# ⊐˜ ranks without breaking ties and ⍋∘⍋ breaks ties, so the
# difference after adjusting ⊐˜ is the occurrence count
OccurrenceCount ← ⊐˜(⊢-⊏)⍋∘⍋
# Tag each cell with an occurrence count, then search
ProgressiveIndexOf ← {𝕨⊐○(((≢∾2˙)⥊≍˘⟜OccurrenceCount∘⥊)𝕨⊸⊐)𝕩}