-
Notifications
You must be signed in to change notification settings - Fork 3
feat: Add Elias-Fano encoding #235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -25,15 +25,29 @@ __SmallAntimagmaHelper.checkOrderId := function(order, id) | |||||||||||||||||||||||||
| __SmallAntimagmaHelper.checkOrder(id); | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| __SmallAntimagmaHelper.checkNonnegativeIntegerList := function(values) | ||||||||||||||||||||||||||
| if not IsList(values) then | ||||||||||||||||||||||||||
| ErrorNoReturn("smallantimagmas: ", "<values> must be a list"); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if not ForAll(values, value -> IsInt(value) and value >= 0) then | ||||||||||||||||||||||||||
| ErrorNoReturn("smallantimagmas: ", | ||||||||||||||||||||||||||
| "<values> must contain only nonnegative integers"); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| __SmallAntimagmaHelper.getSmallAntimagmaMetadataDirectory := function(order) | ||||||||||||||||||||||||||
| local result; | ||||||||||||||||||||||||||
| __SmallAntimagmaHelper.checkOrder(order); | ||||||||||||||||||||||||||
| result := DirectoriesPackageLibrary("smallantimagmas", Concatenation(["data", "/", "non-isomorphic", "/", String(order)])); | ||||||||||||||||||||||||||
| result := DirectoriesPackageLibrary("smallantimagmas", | ||||||||||||||||||||||||||
| Concatenation(["data", "/", "non-isomorphic", "/", | ||||||||||||||||||||||||||
| String(order)])); | ||||||||||||||||||||||||||
| if Size(result) = 0 then | ||||||||||||||||||||||||||
| ErrorNoReturn("smallantimagmas:", "<order> is not yet implemeneted"); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| if Size(result) > 1 then | ||||||||||||||||||||||||||
| ErrorNoReturn("smallantimagmas:", "metadata directory must not be ambigous"); | ||||||||||||||||||||||||||
| ErrorNoReturn("smallantimagmas:", | ||||||||||||||||||||||||||
| "metadata directory must not be ambiguous"); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| return First(result); | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
|
|
@@ -45,15 +59,18 @@ __SmallAntimagmaHelper.getSmallAntimagmaMetadata := function(order) | |||||||||||||||||||||||||
| return ReadAsFunction(First(files)); | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| __SmallAntimagmaHelper.getAllSmallAntimagmaMetadataDirectory := function(order) | ||||||||||||||||||||||||||
| __SmallAntimagmaHelper.getAllSmallAntimagmaMetadataDirectory := | ||||||||||||||||||||||||||
| function(order) | ||||||||||||||||||||||||||
| local result; | ||||||||||||||||||||||||||
| __SmallAntimagmaHelper.checkOrder(order); | ||||||||||||||||||||||||||
| result := DirectoriesPackageLibrary("smallantimagmas", Concatenation(["data", "/", "all", "/", String(order)])); | ||||||||||||||||||||||||||
| result := DirectoriesPackageLibrary("smallantimagmas", | ||||||||||||||||||||||||||
| Concatenation(["data", "/", "all", "/", String(order)])); | ||||||||||||||||||||||||||
| if Size(result) = 0 then | ||||||||||||||||||||||||||
| ErrorNoReturn("smallantimagmas:", "<order> is not yet implemeneted"); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| if Size(result) > 1 then | ||||||||||||||||||||||||||
| ErrorNoReturn("smallantimagmas:", "metadata directory must not be ambigous"); | ||||||||||||||||||||||||||
| ErrorNoReturn("smallantimagmas:", | ||||||||||||||||||||||||||
| "metadata directory must not be ambiguous"); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| return First(result); | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
|
|
@@ -65,14 +82,335 @@ __SmallAntimagmaHelper.getAllSmallAntimagmaMetadata := function(order) | |||||||||||||||||||||||||
| return ReadAsFunction(First(files)); | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| __SmallAntimagmaHelper.EnumeratorOfTuplesWithCache := | ||||||||||||||||||||||||||
| (function() | ||||||||||||||||||||||||||
| local enumerators; | ||||||||||||||||||||||||||
| enumerators := []; | ||||||||||||||||||||||||||
| return function(n) | ||||||||||||||||||||||||||
| if not IsBound(enumerators[n]) then | ||||||||||||||||||||||||||
| enumerators[n] := EnumeratorOfTuples([1 .. n], n); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| return enumerators[n]; | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
| end)(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| __SmallAntimagmaHelper.MultiplicationTableConvert := function(T) | ||||||||||||||||||||||||||
| local nrows; | ||||||||||||||||||||||||||
| local nrows, enum; | ||||||||||||||||||||||||||
| nrows := NrRows(T); | ||||||||||||||||||||||||||
| return List(T, row -> Position(EnumeratorOfTuples([1 .. nrows], nrows), row)); | ||||||||||||||||||||||||||
| enum := __SmallAntimagmaHelper.EnumeratorOfTuplesWithCache(nrows); | ||||||||||||||||||||||||||
| return List(T, row -> Position(enum, row)); | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| __SmallAntimagmaHelper.MultiplicationTableReverse := function(T) | ||||||||||||||||||||||||||
| local ncols; | ||||||||||||||||||||||||||
| local ncols, enum; | ||||||||||||||||||||||||||
| ncols := Size(T); | ||||||||||||||||||||||||||
| return List(T, col -> EnumeratorOfTuples([1 .. ncols], ncols)[col]); | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
| enum := __SmallAntimagmaHelper.EnumeratorOfTuplesWithCache(ncols); | ||||||||||||||||||||||||||
| return List(T, col -> enum[col]); | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # ==================================================================== | ||||||||||||||||||||||||||
| # Precomputed powers cache: n^0, n^1, ..., n^(n-1) | ||||||||||||||||||||||||||
| # ==================================================================== | ||||||||||||||||||||||||||
| __SmallAntimagmaHelper.PowersOfNWithCache := | ||||||||||||||||||||||||||
| (function() | ||||||||||||||||||||||||||
| local cache; | ||||||||||||||||||||||||||
| cache := []; | ||||||||||||||||||||||||||
| return function(n) | ||||||||||||||||||||||||||
| if not IsBound(cache[n]) then | ||||||||||||||||||||||||||
| cache[n] := List([1 .. n], c -> n ^ (c - 1)); | ||||||||||||||||||||||||||
| MakeImmutable(cache[n]); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| return cache[n]; | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
| end)(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # ==================================================================== | ||||||||||||||||||||||||||
| # Precomputed powers cache: (n^n)^0, (n^n)^1, ..., (n^n)^(n-1) | ||||||||||||||||||||||||||
| # ==================================================================== | ||||||||||||||||||||||||||
| __SmallAntimagmaHelper.PowersOfNNWithCache := | ||||||||||||||||||||||||||
| (function() | ||||||||||||||||||||||||||
| local cache; | ||||||||||||||||||||||||||
| cache := []; | ||||||||||||||||||||||||||
| return function(n) | ||||||||||||||||||||||||||
| local nn; | ||||||||||||||||||||||||||
| if not IsBound(cache[n]) then | ||||||||||||||||||||||||||
| nn := n ^ n; | ||||||||||||||||||||||||||
| cache[n] := List([1 .. n], r -> nn ^ (r - 1)); | ||||||||||||||||||||||||||
| MakeImmutable(cache[n]); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| return cache[n]; | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
| end)(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # ==================================================================== | ||||||||||||||||||||||||||
| # Row dictionary cache: all n^n possible rows for order n | ||||||||||||||||||||||||||
| # GAP arrays are 1-indexed, so row ID 0 is stored at index 1. | ||||||||||||||||||||||||||
| # ==================================================================== | ||||||||||||||||||||||||||
| __SmallAntimagmaHelper.RowDictWithCache := | ||||||||||||||||||||||||||
| (function() | ||||||||||||||||||||||||||
| local cache; | ||||||||||||||||||||||||||
| cache := []; | ||||||||||||||||||||||||||
| return function(n) | ||||||||||||||||||||||||||
| local nn, powers_n; | ||||||||||||||||||||||||||
| if not IsBound(cache[n]) then | ||||||||||||||||||||||||||
| nn := n ^ n; | ||||||||||||||||||||||||||
| powers_n := | ||||||||||||||||||||||||||
| __SmallAntimagmaHelper.PowersOfNWithCache(n); | ||||||||||||||||||||||||||
| cache[n] := List([0 .. nn - 1], i -> | ||||||||||||||||||||||||||
| List([1 .. n], | ||||||||||||||||||||||||||
| c -> (QuoInt(i, powers_n[c]) mod n) + 1)); | ||||||||||||||||||||||||||
| MakeImmutable(cache[n]); | ||||||||||||||||||||||||||
| fi; | ||||||||||||||||||||||||||
| return cache[n]; | ||||||||||||||||||||||||||
| end; | ||||||||||||||||||||||||||
| end)(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # ==================================================================== | ||||||||||||||||||||||||||
| # Encode a multiplication table (list of lists, entries 1..n) to a | ||||||||||||||||||||||||||
| # single immediate integer using base-n^n packing. | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| # single immediate integer using base-n^n packing. | |
| # single integer using base-n^n packing. |
Copilot
AI
Mar 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MultiplicationTableDecode currently uses ... mod nn, which silently maps any integer (including negative/out-of-range values) to some table. This is more permissive than the previous Reverse-based decoding and can mask corrupted/invalid metadata. Consider validating that encoded is a non-negative integer and within the expected range (0..(n^n)^n-1), or document explicitly that decoding is performed modulo (n^n)^n.
Copilot
AI
Mar 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MultiplicationTableGetEntry is described as O(1) access, but it forces construction of the full RowDictWithCache(n) (size n^n) before returning a single entry. If this is intended for true O(1) memory access, consider computing the digit directly from encoded (and avoid RowDictWithCache), or clarify in the comment that it’s O(1) only after the row dictionary cache is built.
| local row_id, powers_nn, nn, row_dict; | |
| powers_nn := __SmallAntimagmaHelper.PowersOfNNWithCache(n); | |
| nn := n ^ n; | |
| row_dict := __SmallAntimagmaHelper.RowDictWithCache(n); | |
| row_id := QuoInt(encoded, powers_nn[r]) mod nn; | |
| return row_dict[row_id + 1][c]; | |
| local row_id, powers_nn, powers_n, nn; | |
| powers_nn := __SmallAntimagmaHelper.PowersOfNNWithCache(n); | |
| powers_n := __SmallAntimagmaHelper.PowersOfNWithCache(n); | |
| nn := n ^ n; | |
| row_id := QuoInt(encoded, powers_nn[r]) mod nn; | |
| return QuoInt(row_id, powers_n[c]) mod n + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RowDictWithCache materializes and caches all n^n possible rows. For n even moderately large this grows extremely fast and can exhaust memory (e.g., n=8 creates 16,777,216 rows). Consider avoiding full precomputation (compute a row on demand from row_id), or guard/limit caching to small n where it’s known to be safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to apply changes based on this feedback