High-performance absent-aware n-dimensional arrays powered by NumPy and PhantomTrace.
Project description
PhantomOperator
High-performance absent-aware n-dimensional arrays powered by NumPy and PhantomTrace.
Installation
pip install phantomoperator
This automatically installs NumPy and PhantomTrace as dependencies.
What It Does
PhantomOperator brings NumPy-level performance to PhantomTrace's absence calculus. Instead of looping through Python lists of individual AbsentNumber objects, operations run on compact NumPy arrays — two arrays side by side: one for present values, one for absent values.
Important: Void Is Not a State
Void is not a state. Present is a state. Absent is a state. Void is absolute nothingness — it means there is nothing at that position. No number, no state, no calculation, no meaning. It is the complete absence of anything to talk about.
When you subtract 5 by 5, nothing is left. That is not zero — zero is a real number (1(0), one unit of absence). That is void. Subtraction removes the value and forgets it — there is simply nothing there anymore. Erasure is different: erasing 5 by 5 gives 5(0) (calculable absence). The value is still there, just flipped to the other state. Erasure remembers what it removed.
PhantomOperator allows void inside arrays and handles it in operations so that everything works without errors. But void carrying through an operation does not mean anything is being computed. It means: "there was nothing here, so there is still nothing here."
void + 5 = 5— Adding nothing to 5 is just 5. Void did not contribute anything.void × 5 = void— Multiplying by nothing produces nothing. There was no quantity to scale.void - void = void— Nothing minus nothing is still nothing.
Void vs Zero vs Absence
| What it is | Example | Has a state? | Has magnitude? | |
|---|---|---|---|---|
| Void | Absolute nothingness. No number exists here. | Result of subtracting 5 by 5 | No | No |
Zero (0) |
One unit of absence. A real number: 1(0) |
The number zero on a number line | Yes (absent) | Yes (1) |
3(0) |
Three units of absence. A real quantity in the absent state. | Three absent things | Yes (absent) | Yes (3) |
Zero is not void. Zero is a real, meaningful number with a state and a magnitude. Void is nothing at all.
Imports
from phantomoperator import AbsentArray, absent_array, arange, ones
from phantomoperator import arr_add, arr_subtract, arr_multiply, arr_divide
from phantomoperator import arr_erase, arr_join, arr_toggle
from phantomoperator import arr_combine, arr_compare, arr_trace
The phantom_operator module name is also supported for backward compatibility:
from phantom_operator import AbsentArray, arr_add
Function Naming
PhantomOperator uses arr_ prefixed function names so they do not collide with PhantomTrace's scalar operations. This lets you use both libraries together without conflicts:
from phantomtrace import add, multiply, n # scalar operations
from phantomoperator import arr_add, arr_multiply # array operations
scalar_result = add(n(5), n(3)) # → 8
array_result = arr_add(absent_array([5, 3]), absent_array([2, 4])) # → [7, 7]
Quick Start
from phantomoperator import AbsentArray, absent_array, arange, ones
a = absent_array([1, 2, 3, 4, 5]) # all present
b = absent_array([1, 2, 3, 4, 5], states=[0, 1, 0, 1, 0]) # mixed states
c = arange(1, 10) # [1, 2, 3, ..., 10] all present
d = arange(1, 10, state=1) # [1, 2, 3, ..., 10] all absent
e = ones(1000) # 1000 ones, all present
Operations
All five PhantomTrace operations work element-wise on arrays. Void is handled in every operation so nothing breaks — operations involving void propagate nothingness without raising errors.
Addition & Subtraction
Same-state elements combine magnitudes. Cross-state elements produce an unresolved sum (both components preserved). Void acts as an identity for addition:
from phantomoperator import absent_array, arr_add, arr_subtract
a = absent_array([5, 3, 7], states=[0, 0, 1])
b = absent_array([2, 3, 3], states=[0, 0, 1])
arr_add(a, b) # → [7, 6, 10(0)]
arr_subtract(a, b) # → [3, void, 4(0)] (3 - 3: nothing left = void)
Multiplication & Division
State combination rule: present × present = present, present × absent = absent, absent × absent = present.
from phantomoperator import absent_array, arr_multiply, arr_divide
a = absent_array([5, 4, 6], states=[0, 1, 1])
b = absent_array([3, 3, 2], states=[0, 0, 1])
arr_multiply(a, b) # → [15, 12(0), 12] (absent × absent = present)
arr_divide(a, b) # → [1, 1(0), 3]
Erasure
Erasure flips the state of the erased portion. Returns a single combined AbsentArray where the remainder is stored in the present component and the erased portion in the absent component. Over-erasure debt is stored as erased excess.
Unlike subtraction, erasure does not produce void when values are equal. Erasing 5 by 5 gives 5(0) — the value flips state but is still there.
from phantomoperator import absent_array, arr_erase
a = absent_array([7, 5, 3])
b = absent_array([3, 5, 1])
result = arr_erase(a, b)
# → AbsentArray([4 + 3(0), 5(0), 2 + 0])
# Position 0: 4 remains, 3 was erased (now absent)
# Position 1: fully erased — 5(0)
# Position 2: 2 remains, 1 was erased
# Over-erasure — excess becomes erased debt
a2 = absent_array([3, 10])
b2 = absent_array([5, 4])
result2 = arr_erase(a2, b2)
# → AbsentArray([erased 2 + 3(0), 6 + 4(0)])
# Position 0: 3 flipped (3(0)), 2 extra erasure carried as erased excess
# Position 1: 6 remains, 4 was erased
Join
arr_join() concatenates two AbsentArrays into one, preserving all elements, states, and erased excesses:
from phantomtrace import n, VOID
from phantomoperator import absent_array, arr_join
a = absent_array([n(5)(0), n(7), VOID, n(9)])
b = absent_array([n(6), n(7)(0), n(4)])
arr_join(a, b)
# → AbsentArray([5(0), 7, void, 9, 6, 7(0), 4])
Toggle
arr_toggle() flips the state of every element. Void elements stay void:
from phantomoperator import absent_array, arr_toggle
a = absent_array([1, 2, 3], states=[0, 1, 0])
arr_toggle(a) # → [1(0), 2, 3(0)]
Toggle is equivalent to fully erasing an element by its own value. Toggling 5 gives 5(0) — same value, opposite state. This is why erasure and subtraction are different: subtraction would give void (forgotten), but erasure gives calculable absence (remembered in the other state).
Combine
arr_combine() analyzes the state relationship between two arrays element-wise. Each position contributes a state indicator (1 for present, 1(0) for absent) and those are added together:
from phantomtrace import n, VOID
from phantomoperator import absent_array, arr_combine
a = absent_array([n(1), n(2)], states=[0, 0])
b = absent_array([n(3), n(4)(0)], states=[0, 1])
arr_combine(a, b)
# → [2, 1 + 1(0)]
# Position 0: both present → 2
# Position 1: present + absent → 1 + 1(0)
# Same state, both absent
arr_combine(absent_array([n(3)(0), n(5)(0)]), absent_array([n(7)(0), n(2)(0)]))
# → [2(0), 2(0)]
# With void — counts only the non-void side
arr_combine(absent_array([n(5), n(4)(0)]), absent_array([VOID, VOID]))
# → [1, 1(0)]
Compare
arr_compare() compares how magnitude is distributed between present and absent states. It only works on two arrays that have the same total magnitude at each position. Mismatched magnitudes or void vs number positions raise an error.
When magnitudes match, compare returns:
- The difference as present when y has more present content
- The difference as absent when x has more present content
- Void when the present content is equal
from phantomoperator import absent_array, arr_compare
a = absent_array([5, 3, 7], states=[0, 1, 0])
b = absent_array([5, 3, 7], states=[1, 0, 0])
arr_compare(a, b)
# → [5(0), 3, void]
# Position 0: same magnitude, x present → y absent → x has more present → 5(0)
# Position 1: same magnitude, x absent → y present → y has more present → 3
# Position 2: both present with same value → no difference → void
Mismatched magnitudes are rejected:
arr_compare(absent_array([5]), absent_array([3]))
# → ValueError: total magnitudes differ (5 vs 3)
Trace
arr_trace() evaluates a function over a range of AbsentNumbers and builds the results directly into an AbsentArray. Same-state ranges iterate by magnitude. Cross-state ranges require an explicit ordering.
from phantomtrace import n, present, absent, largest, ordering
from phantomoperator import arr_trace
result = arr_trace(lambda x: x, n(1), n(5))
# → AbsentArray([1, 2, 3, 4, 5])
result = arr_trace(lambda x: x, n(3)(0), n(1)(0))
# → AbsentArray([3(0), 2(0), 1(0)])
order = ordering(largest(present()), largest(absent()))
result = arr_trace(lambda x: x, n(3), n(3)(0), order=order)
# → AbsentArray([3, 2, 1, 1(0), 2(0), 3(0)])
Array Features
Shapes & Dimensions
from phantomoperator import absent_array
a = absent_array([[1, 2, 3], [4, 5, 6]])
a.shape # (2, 3)
a.ndim # 2
a.size # 6
Indexing
from phantomoperator import absent_array
a = absent_array([10, 20, 30, 40, 50])
a[0] # AbsentNumber: 10
a[1:3] # AbsentArray([20, 30])
Indexing a void position returns PhantomTrace's Void object:
from phantomoperator import absent_array, arr_subtract
result = arr_subtract(absent_array([5]), absent_array([5]))
result[0] # Void — subtraction forgot the value entirely
Conversion
from phantomtrace import n
from phantomoperator import absent_array
a = absent_array([n(5), n(3)(0), n(7)])
a.to_list() # → [AbsentNumber(5), AbsentNumber(3, 1), AbsentNumber(7)]
Void positions in to_list() return PhantomTrace's Void object.
Querying State
from phantomtrace import n, VOID
from phantomoperator import absent_array, arr_count_present, arr_present_mask, arr_absent_mask, arr_void_mask
a = absent_array([n(1), n(2)(0), VOID, n(4), n(5)(0)])
arr_count_present(a) # 2
arr_present_mask(a) # [True, False, False, True, False]
arr_absent_mask(a) # [False, True, False, False, True]
arr_void_mask(a) # [False, False, True, False, False]
Performance
PhantomOperator is built on NumPy's C arrays, so operations on large arrays are orders of magnitude faster than looping through individual AbsentNumbers:
from phantomoperator import arange, arr_multiply
import time
a = arange(1, 100000)
b = arange(1, 100000)
start = time.time()
result = arr_multiply(a, b)
elapsed = time.time() - start
# Typically < 2ms vs seconds with plain Python lists
Dependencies
- NumPy — array computation engine
- PhantomTrace — absence calculus framework
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file phantomoperator-0.4.1.tar.gz.
File metadata
- Download URL: phantomoperator-0.4.1.tar.gz
- Upload date:
- Size: 11.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
000d432bab04a398108cbc5504a90154806428ffb4c3f521fc23b82e36de14f8
|
|
| MD5 |
20ec35cb355649764bd780fc6f3aa753
|
|
| BLAKE2b-256 |
0ce6855444651aabfdc3d8d869a683991cc074bb462f8bfe7f28282db80f9e70
|
File details
Details for the file phantomoperator-0.4.1-py3-none-any.whl.
File metadata
- Download URL: phantomoperator-0.4.1-py3-none-any.whl
- Upload date:
- Size: 12.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0db340f2957cf15f7dac61d0ed3f460cd7da849b5db15057d8d4245a2ca758a4
|
|
| MD5 |
8ebf655bdfeede304b91cacb83741bcb
|
|
| BLAKE2b-256 |
680e766e5469b4a15fbf680d1e9fbbdbcfc633e348df4b6ef3d7a8f7bb49f2ff
|