Combinatorial decision algorithms as SQL — bin packing, knapsack, wave batching, sequencing, scheduling, assortment and portfolio selection
Installing and Loading
INSTALL anofox_optimize FROM community;
LOAD anofox_optimize;
Example
-- Cartons waiting to ship, and a container that holds 1000 units.
CREATE TABLE cartons AS SELECT * FROM VALUES
(1, 420.0), (2, 380.0), (3, 260.0), (4, 240.0),
(5, 190.0), (6, 180.0), (7, 150.0), (8, 130.0)
AS t(carton_id, size);
-- How few containers hold everything? `best_of` runs every packing
-- algorithm in the family and returns whichever used the fewest bins.
SELECT opt_pack_best_of(list(size ORDER BY carton_id), 1000.0).bins_used AS containers
FROM cartons;
-- Which shipments go on a cheaper carrier that only takes 1000 units?
-- Value == weight, so this is subset-sum, and `exact` finds the perfect
-- fill that greedy rules miss.
SELECT opt_knapsack_exact(
list(weight ORDER BY shipment_id),
list(weight ORDER BY shipment_id),
1000.0
).total_weight AS loaded_on_cheap_carrier
FROM (VALUES (1, 505.0), (2, 380.0), (3, 260.0), (4, 240.0), (5, 115.0))
AS s(shipment_id, weight);
About anofox_optimize
anofox_optimize puts combinatorial decision algorithms behind DuckDB functions. Pack containers, choose an assortment, sequence a machine, allocate a portfolio — in SQL, against the tables the data already lives in. No solver process, no external service, no modelling language.
Eight families, one signature each
Every member of a family takes identical arguments, so swapping one identifier swaps the algorithm and nothing else:
| Family | Decision | Example |
|---|---|---|
pack_* |
fit items into the fewest containers | opt_pack_best_of |
knapsack_* |
pick a subset under one capacity | opt_knapsack_exact |
wave_* |
group orders into capacity-limited waves | opt_wave_best_of |
sequence_* |
order jobs to cut changeover cost | opt_sequence_two_opt |
schedule_* |
order jobs against due dates with setups | opt_schedule_best_of |
assortment_* |
choose what to stock when products interact | opt_assortment_best_of |
portfolio_* |
choose assets and weights under a holding limit | opt_portfolio_best_of |
matrix_from_triples |
build a matrix from (from, to, value) rows |
— |
Every function has a canonical anofox_optimize_* name and a short opt_*
alias — they are the same function. opt_*_best_of runs every algorithm in
its family and returns the winner; that is the place to start.
Honesty about guarantees
Two functions return a proven optimum and say so in their names:
knapsack_exact and schedule_exact. Everything else is heuristic and
carries no guarantee. Functions that would blow up refuse rather than hang —
schedule_exact rejects more than 14 jobs with an error naming the
heuristic to use instead.
Each family also ships a deliberately weak member (pack_next_fit,
portfolio_top_return, assortment_top_margin, sequence_as_given),
because you need an honest baseline to know whether optimizing bought you
anything — and "what we do today" is usually a greedy rule.
Two ways to pick the wrong function
Both are silent, so they are worth knowing up front. assortment_* and
assortment_recapture_* take identical arguments and model opposite
economics — products cannibalising each other, versus demand flowing to the
survivors when you delist. And sequence_* and schedule_* both order
jobs, but only schedule_* knows about due dates.
Testing
The suite asserts against optima computed outside the extension: Falkenauer triplets whose optimum is fixed by construction, subset-sum solved by DP, Held-Karp scheduling, and portfolio enumeration over all 15,504 subsets. That standard has already paid for itself — it caught a local search returning 168 against a proven optimum of 60, and an "exact" scheduler that was not exact.
The extension collects anonymous usage telemetry, switched off with
SET anofox_telemetry_enabled = false. See the
project repository for
guides, the theory notes, and an API reference generated from
duckdb_functions() of the built extension.
Added Functions
| function_name | function_type | description | comment | examples |
|---|---|---|---|---|
| anofox_optimize_assortment_best_of | scalar | Runs every assortment algorithm in this family and returns whichever captured the most margin. MODEL: CANNIBALISATION — each listed product earns margin * (base_demand minus the demand the OTHER LISTED products take from it). Listing near-duplicates destroys value here. If instead you are DELISTING and want the demand of dropped products to flow to the survivors, use the anofox_optimize_assortment_recapture_* family: it answers a different question and the two disagree. Takes margins and base_demands (one per product) plus the substitution matrix flattened ROW-MAJOR — substitution[j*n+i] is the fraction of product j's demand that moves to product i — and a shelf limit. Returns a boolean per product and the resulting captured margin. | NULL | [anofox_optimize_assortment_best_of([5.0,4.0],[100.0,90.0],[0.0,0.6,0.6,0.0], 2)] |
| anofox_optimize_assortment_greedy_marginal | scalar | Lists products one at a time, each time adding whichever raises TOTAL captured margin most given what it takes from the products already listed. Stops early when no addition helps, even below the shelf limit: listing a pure cannibaliser loses money. MODEL: CANNIBALISATION — each listed product earns margin * (base_demand minus the demand the OTHER LISTED products take from it). Listing near-duplicates destroys value here. If instead you are DELISTING and want the demand of dropped products to flow to the survivors, use the anofox_optimize_assortment_recapture_* family: it answers a different question and the two disagree. Takes margins and base_demands (one per product) plus the substitution matrix flattened ROW-MAJOR — substitution[j*n+i] is the fraction of product j's demand that moves to product i — and a shelf limit. Returns a boolean per product and the resulting captured margin. | NULL | [anofox_optimize_assortment_greedy_marginal([5.0,4.0],[100.0,90.0],[0.0,0.6,0.6,0.0], 2)] |
| anofox_optimize_assortment_local_search | scalar | Greedy marginal, then swaps a listed product for an unlisted one while that raises captured margin. Escapes the greedy ordering, at O(n^2) evaluations per improving pass. MODEL: CANNIBALISATION — each listed product earns margin * (base_demand minus the demand the OTHER LISTED products take from it). Listing near-duplicates destroys value here. If instead you are DELISTING and want the demand of dropped products to flow to the survivors, use the anofox_optimize_assortment_recapture_* family: it answers a different question and the two disagree. Takes margins and base_demands (one per product) plus the substitution matrix flattened ROW-MAJOR — substitution[j*n+i] is the fraction of product j's demand that moves to product i — and a shelf limit. Returns a boolean per product and the resulting captured margin. | NULL | [anofox_optimize_assortment_local_search([5.0,4.0],[100.0,90.0],[0.0,0.6,0.6,0.0], 2)] |
| anofox_optimize_assortment_recapture_best_of | scalar | Runs every recapture algorithm in this family and returns whichever recaptured the most margin. MODEL: RECAPTURE — each listed product keeps margin * base_demand IN FULL, and additionally earns the demand handed to it by DELISTED products, valued at the LISTED product's own margin. A high-margin, low-demand product can be worth listing purely as a recapture sink, which a margindemand ranking never selects. If instead listed products erode each other, use the anofox_optimize_assortment_ family: it answers a different question and the two disagree. Takes margins and base_demands (one per product) plus the substitution matrix flattened ROW-MAJOR — substitution[j*n+i] is the fraction of product j's demand that moves to product i — and a shelf limit. Returns a boolean per product and the resulting captured margin. | NULL | [anofox_optimize_assortment_recapture_best_of([5.0,4.0],[100.0,90.0],[0.0,0.6,0.6,0.0], 2)] |
| anofox_optimize_assortment_recapture_greedy_marginal | scalar | Lists products one at a time, each time adding whichever raises TOTAL recaptured margin most — which accounts for the demand that product stops donating to others once it is listed itself. Stops early when no addition helps, even below the shelf limit. MODEL: RECAPTURE — each listed product keeps margin * base_demand IN FULL, and additionally earns the demand handed to it by DELISTED products, valued at the LISTED product's own margin. A high-margin, low-demand product can be worth listing purely as a recapture sink, which a margindemand ranking never selects. If instead listed products erode each other, use the anofox_optimize_assortment_ family: it answers a different question and the two disagree. Takes margins and base_demands (one per product) plus the substitution matrix flattened ROW-MAJOR — substitution[j*n+i] is the fraction of product j's demand that moves to product i — and a shelf limit. Returns a boolean per product and the resulting captured margin. | NULL | [anofox_optimize_assortment_recapture_greedy_marginal([5.0,4.0],[100.0,90.0],[0.0,0.6,0.6,0.0], 2)] |
| anofox_optimize_assortment_recapture_local_search | scalar | Recapture greedy, then swaps a listed product for an unlisted one while that raises recaptured margin. Escapes the greedy ordering, at O(n^2) evaluations per improving pass. MODEL: RECAPTURE — each listed product keeps margin * base_demand IN FULL, and additionally earns the demand handed to it by DELISTED products, valued at the LISTED product's own margin. A high-margin, low-demand product can be worth listing purely as a recapture sink, which a margindemand ranking never selects. If instead listed products erode each other, use the anofox_optimize_assortment_ family: it answers a different question and the two disagree. Takes margins and base_demands (one per product) plus the substitution matrix flattened ROW-MAJOR — substitution[j*n+i] is the fraction of product j's demand that moves to product i — and a shelf limit. Returns a boolean per product and the resulting captured margin. | NULL | [anofox_optimize_assortment_recapture_local_search([5.0,4.0],[100.0,90.0],[0.0,0.6,0.6,0.0], 2)] |
| anofox_optimize_assortment_recapture_top_margin | scalar | Lists the top products by standalone marginbase_demand, IGNORING where delisted demand would go. The obvious rule, and a poor one here: it never lists a small-demand product that would soak up a lot of orphaned demand at a high margin. Included so a search has something to beat. MODEL: RECAPTURE — each listed product keeps margin * base_demand IN FULL, and additionally earns the demand handed to it by DELISTED products, valued at the LISTED product's own margin. A high-margin, low-demand product can be worth listing purely as a recapture sink, which a margindemand ranking never selects. If instead listed products erode each other, use the anofox_optimize_assortment_* family: it answers a different question and the two disagree. Takes margins and base_demands (one per product) plus the substitution matrix flattened ROW-MAJOR — substitution[j*n+i] is the fraction of product j's demand that moves to product i — and a shelf limit. Returns a boolean per product and the resulting captured margin. | NULL | [anofox_optimize_assortment_recapture_top_margin([5.0,4.0],[100.0,90.0],[0.0,0.6,0.6,0.0], 2)] |
| anofox_optimize_assortment_top_margin | scalar | Lists the top products by standalone margindemand, IGNORING cannibalisation. The obvious rule, and the one that overstates its own result whenever listed products substitute for each other — included so a search has something to beat. MODEL: CANNIBALISATION — each listed product earns margin * (base_demand minus the demand the OTHER LISTED products take from it). Listing near-duplicates destroys value here. If instead you are DELISTING and want the demand of dropped products to flow to the survivors, use the anofox_optimize_assortment_recapture_ family: it answers a different question and the two disagree. Takes margins and base_demands (one per product) plus the substitution matrix flattened ROW-MAJOR — substitution[j*n+i] is the fraction of product j's demand that moves to product i — and a shelf limit. Returns a boolean per product and the resulting captured margin. | NULL | [anofox_optimize_assortment_top_margin([5.0,4.0],[100.0,90.0],[0.0,0.6,0.6,0.0], 2)] |
| anofox_optimize_knapsack_best_of | scalar | Runs the greedy knapsack members and returns whichever captured more value. Cheap and never loses to any single greedy member, but it is NOT exact — use knapsack_exact when the instance is small enough. Same signature as the other knapsack functions. | NULL | [anofox_optimize_knapsack_best_of([10.0, 6.0], [5.0, 4.0], 6.0)] |
| anofox_optimize_knapsack_exact | scalar | 0/1 knapsack solved EXACTLY by dynamic programming over integer-scaled weights. Returns the true optimum, unlike the greedy members. RAISES rather than degrading when the instance needs too large a table (many items, large capacity, or weights needing fine scaling) — a caller who asked for the exact answer and silently received a heuristic one could not tell its result is no longer a bound. Same signature as the other knapsack functions. | NULL | [anofox_optimize_knapsack_exact([10.0, 6.0], [5.0, 4.0], 6.0)] |
| anofox_optimize_knapsack_greedy_ratio | scalar | 0/1 knapsack by descending value-per-weight: takes each item that still fits. Optimal for the FRACTIONAL problem and usually good for 0/1, but can be arbitrarily bad — one heavy high-ratio item can crowd out a better combination. Returns a boolean per input item plus the selected total value and weight. | NULL | [anofox_optimize_knapsack_greedy_ratio([10.0, 6.0], [5.0, 4.0], 6.0)] |
| anofox_optimize_knapsack_greedy_value | scalar | 0/1 knapsack by descending VALUE, ignoring weight: takes each item that still fits. The weakest member of the family — it loses to by-ratio whenever value and weight are correlated — and included so a search has a poor-but-valid option to move away from. Same signature as the other knapsack functions. | NULL | [anofox_optimize_knapsack_greedy_value([10.0, 6.0], [5.0, 4.0], 6.0)] |
| anofox_optimize_matrix_from_triples | scalar | Builds the flattened ROW-MAJOR matrix the sequencing, scheduling, assortment and portfolio functions expect, from (from, to, value) TRIPLES — which is how the data is usually stored. Missing cells are 0; duplicate cells RAISE rather than silently keeping the last one. index_base is subtracted from the ids, so pass 1 for 1-based ids and 0 for 0-based. Use with list aggregation, e.g. SELECT anofox_optimize_matrix_from_triples(list(a), list(b), list(v), 8, 1) FROM t. |
NULL | [anofox_optimize_matrix_from_triples([1,2], [2,1], [0.5, 0.5], 2, 1)] |
| anofox_optimize_pack_best_fit_decreasing | scalar | Packs items into bins by best-fit-decreasing: sorts items largest first and puts each into the FULLEST bin it still fits, leaving emptier bins for larger items later. Same signature as the other packing functions. | NULL | [anofox_optimize_pack_best_fit_decreasing([4.0, 8.0, 1.0], 10.0)] |
| anofox_optimize_pack_best_of | scalar | Runs every packing algorithm in this family and returns whichever used the fewest bins. Costs the sum of the parts and never loses to any single member; use it when you do not want to choose. Same signature as the other packing functions. | NULL | [anofox_optimize_pack_best_of([4.0, 8.0, 1.0], 10.0)] |
| anofox_optimize_pack_bin_completion | scalar | Packs items by BOUNDED BIN COMPLETION: seeds each bin with the largest unplaced item, searches all PAIRS of companions exhaustively for the combination that fills the bin fullest, then tops up greedily with anything that still fits. Not exhaustive over arbitrary subsets and not optimal, but it recovers the exact three-per-bin fills that make every greedy member stall together on triplet-style instances. Costs O(n^2) per bin. Same signature as the other packing functions. | NULL | [anofox_optimize_pack_bin_completion([4.0, 8.0, 1.0], 10.0)] |
| anofox_optimize_pack_first_fit_decreasing | scalar | Packs items into bins by first-fit-decreasing: sorts items largest first and puts each into the first bin it fits. Fast and near-optimal on typical instances, but provably up to 11/9 of optimal and weak on triplet-style instances. Returns bins_used and a 0-based bin index per input item. An empty item list uses 0 bins; a non-empty list of zero-size items uses 1. | NULL | [anofox_optimize_pack_first_fit_decreasing([4.0, 8.0, 1.0], 10.0)] |
| anofox_optimize_pack_local_search | scalar | Packs items by first-fit-decreasing and then IMPROVES the result: tries to dissolve bins one at a time, from least-loaded upward, by relocating their items into other bins — including a swap that displaces a smaller item to a third bin to make room. Repeats until no bin can be emptied. Slower than the greedy members; on triplet-style instances it does not beat them (use bin_completion there). Same signature as the other packing functions. | NULL | [anofox_optimize_pack_local_search([4.0, 8.0, 1.0], 10.0)] |
| anofox_optimize_pack_next_fit | scalar | Packs items into bins by next-fit, in the given order, only ever using the most recently opened bin. The weakest member of the family and the cheapest; included so a search has a poor-but-valid baseline to move away from. | NULL | [anofox_optimize_pack_next_fit([4.0, 8.0, 1.0], 10.0)] |
| anofox_optimize_pack_worst_fit_decreasing | scalar | Packs items into bins by worst-fit-decreasing: puts each item into the EMPTIEST bin it fits, spreading load evenly. Usually uses more bins than best-fit but produces balanced loads. Same signature as the other packing functions. | NULL | [anofox_optimize_pack_worst_fit_decreasing([4.0, 8.0, 1.0], 10.0)] |
| anofox_optimize_portfolio_best_of | scalar | Runs every portfolio algorithm in this family and returns whichever achieved the highest Sharpe ratio. Takes expected_returns (one per asset) and the covariance matrix flattened ROW-MAJOR, a maximum number of holdings, and a per-asset weight cap. Weights sum to 1 over the chosen assets. Returns the weight vector, expected return, volatility and Sharpe ratio (return/volatility). | NULL | [anofox_optimize_portfolio_best_of([0.12,0.10,0.10],[0.04,0.036,-0.01,0.036,0.04,-0.01,-0.01,-0.01,0.04], 2, 0.6)] |
| anofox_optimize_portfolio_greedy_sharpe | scalar | Grows the holding set one asset at a time, each time adding whichever most improves Sharpe AFTER re-optimizing the weights — so it can pick a lower-return asset because it diversifies — then SWAPS held assets for unheld ones while that improves Sharpe, which is what lets it choose a different set when the holding limit leaves no room to grow. The member that actually uses the covariance to choose WHICH assets, not just how much of them. Takes expected_returns (one per asset) and the covariance matrix flattened ROW-MAJOR, a maximum number of holdings, and a per-asset weight cap. Weights sum to 1 over the chosen assets. Returns the weight vector, expected return, volatility and Sharpe ratio (return/volatility). | NULL | [anofox_optimize_portfolio_greedy_sharpe([0.12,0.10,0.10],[0.04,0.036,-0.01,0.036,0.04,-0.01,-0.01,-0.01,0.04], 2, 0.6)] |
| anofox_optimize_portfolio_top_return | scalar | Picks the highest-expected-return assets up to the holding limit and weights them EQUALLY, ignoring covariance entirely — so it will happily buy assets that all move together. The naive rule, included so a search has something to beat. Takes expected_returns (one per asset) and the covariance matrix flattened ROW-MAJOR, a maximum number of holdings, and a per-asset weight cap. Weights sum to 1 over the chosen assets. Returns the weight vector, expected return, volatility and Sharpe ratio (return/volatility). | NULL | [anofox_optimize_portfolio_top_return([0.12,0.10,0.10],[0.04,0.036,-0.01,0.036,0.04,-0.01,-0.01,-0.01,0.04], 2, 0.6)] |
| anofox_optimize_portfolio_top_return_optimized | scalar | Picks the highest-expected-return assets up to the holding limit, then OPTIMISES THE WEIGHTS on that fixed set by projected gradient ascent on Sharpe. Better than equal weighting, but still cannot choose a lower-return asset that would diversify. Takes expected_returns (one per asset) and the covariance matrix flattened ROW-MAJOR, a maximum number of holdings, and a per-asset weight cap. Weights sum to 1 over the chosen assets. Returns the weight vector, expected return, volatility and Sharpe ratio (return/volatility). | NULL | [anofox_optimize_portfolio_top_return_optimized([0.12,0.10,0.10],[0.04,0.036,-0.01,0.036,0.04,-0.01,-0.01,-0.01,0.04], 2, 0.6)] |
| anofox_optimize_schedule_atcs | scalar | Sequences jobs by APPARENT TARDINESS COST WITH SETUPS: at each step picks the job maximising priority/processing, discounted by its slack and by the setup needed to switch to it. Unlike EDD and WSPT it weighs due dates, priorities AND setups together, which is what this objective actually trades off. Takes processing_times, due_dates and priorities (one per job) plus the setup matrix flattened ROW-MAJOR over n+1 rows, where index 0 is the VIRTUAL START: setup[i*(n+1)+j] is the cost of running job j-1 after job i-1, and row 0 is the cost of running a job first. Returns a 0-based job order, the total priority-weighted tardiness of that order, and its makespan. | NULL | [anofox_optimize_schedule_atcs([10.0,10.0],[20.0,5.0],[1.0,3.0],[5.0,5.0,5.0,0.0,2.0,2.0,0.0,2.0,2.0], 2)] |
| anofox_optimize_schedule_best_of | scalar | Runs every scheduling algorithm in this family and returns whichever had the lowest total weighted tardiness. Costs the sum of the parts and never loses to any single member. Takes processing_times, due_dates and priorities (one per job) plus the setup matrix flattened ROW-MAJOR over n+1 rows, where index 0 is the VIRTUAL START: setup[i*(n+1)+j] is the cost of running job j-1 after job i-1, and row 0 is the cost of running a job first. Returns a 0-based job order, the total priority-weighted tardiness of that order, and its makespan. | NULL | [anofox_optimize_schedule_best_of([10.0,10.0],[20.0,5.0],[1.0,3.0],[5.0,5.0,5.0,0.0,2.0,2.0,0.0,2.0,2.0], 2)] |
| anofox_optimize_schedule_edd | scalar | Sequences jobs by EARLIEST DUE DATE. The textbook rule and optimal for maximum lateness without setups, but it ignores priorities and setup costs entirely, so it can be poor on weighted tardiness. Takes processing_times, due_dates and priorities (one per job) plus the setup matrix flattened ROW-MAJOR over n+1 rows, where index 0 is the VIRTUAL START: setup[i*(n+1)+j] is the cost of running job j-1 after job i-1, and row 0 is the cost of running a job first. Returns a 0-based job order, the total priority-weighted tardiness of that order, and its makespan. | NULL | [anofox_optimize_schedule_edd([10.0,10.0],[20.0,5.0],[1.0,3.0],[5.0,5.0,5.0,0.0,2.0,2.0,0.0,2.0,2.0], 2)] |
| anofox_optimize_schedule_exact | scalar | The PROVEN OPTIMUM by Held-Karp dynamic programming over (scheduled set, last job). Weighted tardiness with sequence-dependent setups is NP-hard, so this is exponential: it REFUSES more than 16 jobs with an error naming the heuristic to use instead, rather than running for hours. Use it to check how far a heuristic really is on a small instance. Takes processing_times, due_dates and priorities (one per job) plus the setup matrix flattened ROW-MAJOR over n+1 rows, where index 0 is the VIRTUAL START: setup[i*(n+1)+j] is the cost of running job j-1 after job i-1, and row 0 is the cost of running a job first. Returns a 0-based job order, the total priority-weighted tardiness of that order, and its makespan. | NULL | [anofox_optimize_schedule_exact([10.0,10.0],[20.0,5.0],[1.0,3.0],[5.0,5.0,5.0,0.0,2.0,2.0,0.0,2.0,2.0], 2)] |
| anofox_optimize_schedule_local_search | scalar | Sequences by ATCS and then improves with adjacent-pair swaps while they reduce weighted tardiness. Slower than the dispatch rules and usually better than any of them alone. Takes processing_times, due_dates and priorities (one per job) plus the setup matrix flattened ROW-MAJOR over n+1 rows, where index 0 is the VIRTUAL START: setup[i*(n+1)+j] is the cost of running job j-1 after job i-1, and row 0 is the cost of running a job first. Returns a 0-based job order, the total priority-weighted tardiness of that order, and its makespan. | NULL | [anofox_optimize_schedule_local_search([10.0,10.0],[20.0,5.0],[1.0,3.0],[5.0,5.0,5.0,0.0,2.0,2.0,0.0,2.0,2.0], 2)] |
| anofox_optimize_schedule_wspt | scalar | Sequences jobs by WEIGHTED SHORTEST PROCESSING TIME (priority/processing, descending). Strong when nearly everything will be late, weak when only a few jobs are, because it ignores due dates and setups. Takes processing_times, due_dates and priorities (one per job) plus the setup matrix flattened ROW-MAJOR over n+1 rows, where index 0 is the VIRTUAL START: setup[i*(n+1)+j] is the cost of running job j-1 after job i-1, and row 0 is the cost of running a job first. Returns a 0-based job order, the total priority-weighted tardiness of that order, and its makespan. | NULL | [anofox_optimize_schedule_wspt([10.0,10.0],[20.0,5.0],[1.0,3.0],[5.0,5.0,5.0,0.0,2.0,2.0,0.0,2.0,2.0], 2)] |
| anofox_optimize_sequence_as_given | scalar | Sequences jobs in the order given, changing nothing. The do-nothing baseline and usually poor; included so a search has a valid option to move away from rather than seeing every member look equally good. setup is the nn matrix flattened ROW-MAJOR: setup[in+j] is the cost of running job j immediately after job i. Returns a 0-based job order and the total setup cost of that order. |
NULL | [anofox_optimize_sequence_as_given([0.0,5.0,9.0,5.0,0.0,3.0,9.0,3.0,0.0], 3)] |
| anofox_optimize_sequence_best_of | scalar | Runs every sequencing algorithm in this family and returns whichever had the lowest total setup. Costs the sum of the parts and never loses to any single member. setup is the nn matrix flattened ROW-MAJOR: setup[in+j] is the cost of running job j immediately after job i. Returns a 0-based job order and the total setup cost of that order. |
NULL | [anofox_optimize_sequence_best_of([0.0,5.0,9.0,5.0,0.0,3.0,9.0,3.0,0.0], 3)] |
| anofox_optimize_sequence_nearest_neighbour | scalar | Sequences jobs by repeatedly jumping to the cheapest unvisited successor, starting from job 0. Fast and usually far better than the given order; its classic failure is stranding an expensive job until last, which it cannot then undo. setup is the nn matrix flattened ROW-MAJOR: setup[in+j] is the cost of running job j immediately after job i. Returns a 0-based job order and the total setup cost of that order. |
NULL | [anofox_optimize_sequence_nearest_neighbour([0.0,5.0,9.0,5.0,0.0,3.0,9.0,3.0,0.0], 3)] |
| anofox_optimize_sequence_two_opt | scalar | Sequences jobs by nearest-neighbour and then improves with 2-OPT: reverses any segment whose reversal lowers total setup, until none does. The member that can escape a bad greedy start, at O(n^2) per improving pass. setup is the nn matrix flattened ROW-MAJOR: setup[in+j] is the cost of running job j immediately after job i. Returns a 0-based job order and the total setup cost of that order. |
NULL | [anofox_optimize_sequence_two_opt([0.0,5.0,9.0,5.0,0.0,3.0,9.0,3.0,0.0], 3)] |
| anofox_optimize_version | scalar | Returns the version of the loaded anofox_optimize extension, as stamped by the build. | NULL | [anofox_optimize_version()] |
| anofox_optimize_wave_as_given | scalar | Batches orders into capacity-bounded waves in the order given. The do-nothing baseline and usually poor; included so a search has a valid option to move away from. Takes items and priorities (one per order) and a per-wave capacity. Returns a 1-based wave number per order and the priority-weighted mean wave, sum(wave*priority)/sum(priority) — lower is better. | NULL | [anofox_optimize_wave_as_given([3.0,4.0,5.0],[1.0,5.0,1.0], 7.0)] |
| anofox_optimize_wave_best_of | scalar | Runs every batching algorithm in this family and returns whichever had the lowest priority-weighted mean wave. Takes items and priorities (one per order) and a per-wave capacity. Returns a 1-based wave number per order and the priority-weighted mean wave, sum(wave*priority)/sum(priority) — lower is better. | NULL | [anofox_optimize_wave_best_of([3.0,4.0,5.0],[1.0,5.0,1.0], 7.0)] |
| anofox_optimize_wave_fewest_waves | scalar | Batches largest orders first, minimising the NUMBER of waves rather than the weighted mean wave. Kept deliberately: it optimizes the wrong quantity for this objective, and shows what that costs. Takes items and priorities (one per order) and a per-wave capacity. Returns a 1-based wave number per order and the priority-weighted mean wave, sum(wave*priority)/sum(priority) — lower is better. | NULL | [anofox_optimize_wave_fewest_waves([3.0,4.0,5.0],[1.0,5.0,1.0], 7.0)] |
| anofox_optimize_wave_priority_density | scalar | Batches by highest priority PER UNIT OF WORK, since an urgent order that fills a whole wave delays everything behind it. Usually beats plain priority-first when order sizes vary widely. Takes items and priorities (one per order) and a per-wave capacity. Returns a 1-based wave number per order and the priority-weighted mean wave, sum(wave*priority)/sum(priority) — lower is better. | NULL | [anofox_optimize_wave_priority_density([3.0,4.0,5.0],[1.0,5.0,1.0], 7.0)] |
| anofox_optimize_wave_priority_first | scalar | Batches HIGHEST PRIORITY FIRST, so urgent orders land in early waves. Directly targets the weighted-wave objective; can waste capacity when an urgent order is also large. Takes items and priorities (one per order) and a per-wave capacity. Returns a 1-based wave number per order and the priority-weighted mean wave, sum(wave*priority)/sum(priority) — lower is better. | NULL | [anofox_optimize_wave_priority_first([3.0,4.0,5.0],[1.0,5.0,1.0], 7.0)] |
| opt_assortment_best_of | scalar | NULL | NULL | |
| opt_assortment_greedy_marginal | scalar | NULL | NULL | |
| opt_assortment_local_search | scalar | NULL | NULL | |
| opt_assortment_recapture_best_of | scalar | NULL | NULL | |
| opt_assortment_recapture_greedy_marginal | scalar | NULL | NULL | |
| opt_assortment_recapture_local_search | scalar | NULL | NULL | |
| opt_assortment_recapture_top_margin | scalar | NULL | NULL | |
| opt_assortment_top_margin | scalar | NULL | NULL | |
| opt_knapsack_best_of | scalar | NULL | NULL | |
| opt_knapsack_exact | scalar | NULL | NULL | |
| opt_knapsack_greedy_ratio | scalar | NULL | NULL | |
| opt_knapsack_greedy_value | scalar | NULL | NULL | |
| opt_matrix_from_triples | scalar | NULL | NULL | |
| opt_pack_best_fit_decreasing | scalar | NULL | NULL | |
| opt_pack_best_of | scalar | NULL | NULL | |
| opt_pack_bin_completion | scalar | NULL | NULL | |
| opt_pack_first_fit_decreasing | scalar | NULL | NULL | |
| opt_pack_local_search | scalar | NULL | NULL | |
| opt_pack_next_fit | scalar | NULL | NULL | |
| opt_pack_worst_fit_decreasing | scalar | NULL | NULL | |
| opt_portfolio_best_of | scalar | NULL | NULL | |
| opt_portfolio_greedy_sharpe | scalar | NULL | NULL | |
| opt_portfolio_top_return | scalar | NULL | NULL | |
| opt_portfolio_top_return_optimized | scalar | NULL | NULL | |
| opt_schedule_atcs | scalar | NULL | NULL | |
| opt_schedule_best_of | scalar | NULL | NULL | |
| opt_schedule_edd | scalar | NULL | NULL | |
| opt_schedule_exact | scalar | NULL | NULL | |
| opt_schedule_local_search | scalar | NULL | NULL | |
| opt_schedule_wspt | scalar | NULL | NULL | |
| opt_sequence_as_given | scalar | NULL | NULL | |
| opt_sequence_best_of | scalar | NULL | NULL | |
| opt_sequence_nearest_neighbour | scalar | NULL | NULL | |
| opt_sequence_two_opt | scalar | NULL | NULL | |
| opt_version | scalar | NULL | NULL | |
| opt_wave_as_given | scalar | NULL | NULL | |
| opt_wave_best_of | scalar | NULL | NULL | |
| opt_wave_fewest_waves | scalar | NULL | NULL | |
| opt_wave_priority_density | scalar | NULL | NULL | |
| opt_wave_priority_first | scalar | NULL | NULL |
Overloaded Functions
This extension does not add any function overloads.
Added Types
This extension does not add any types.
Added Settings
| name | description | input_type | scope | aliases |
|---|---|---|---|---|
| anofox_telemetry_enabled | Enable or disable anonymous usage telemetry | BOOLEAN | GLOBAL | [] |
| anofox_telemetry_key | PostHog API key for telemetry | VARCHAR | GLOBAL | [] |
| datazoo_banner | Show the DataZoo feedback banner when an extension is loaded in an interactive terminal (at most once a day per extension). | BOOLEAN | GLOBAL | [] |