Search Shortcut cmd + k | ctrl + k
anofox_optimize

Combinatorial decision algorithms as SQL — bin packing, knapsack, wave batching, sequencing, scheduling, assortment and portfolio selection

Maintainer(s): jrosskopf

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 []