Anaplan is very good at answering "what happens if we do this?" Optimizer answers a harder question: "given everything we can and cannot do, what is the best thing to do?" It is a linear and mixed-integer programming engine built into the platform, and it turns a planning model into a prescriptive one — allocating supply across plants, assigning territories to reps, choosing which promotions to run inside a fixed budget.
Most teams never switch it on, usually because the setup looks unfamiliar rather than because the maths is hard. This tutorial walks through the concepts, a complete worked example, and the practices that keep an optimization model solvable.
What Optimizer actually is
Optimizer solves problems of a specific shape:
- You have decision variables — the numbers the solver is allowed to choose (units shipped from each plant to each region).
- You have an objective — one number to maximize or minimize (total cost, total margin).
- You have constraints — rules the answer must respect (do not exceed plant capacity, meet at least 95% of demand).
Everything must be linear: decision variables can be multiplied by constants and added together, but not multiplied by each other, and not fed into IF statements that depend on the decision itself. If your logic says Cost = Units * Rate and Rate is an input, that is linear. If Rate depends on Units via a tiered discount, it is not — you will need to reformulate it, usually by splitting into tiers.
Optimizer runs as an action in Anaplan. It reads your module data, solves, and writes the results back into designated line items. That means it fits into the same process furniture as everything else: buttons on UX pages, process chains, scheduled runs.
The worked example: shipping at least cost
A distributor has three plants and four regions. Each plant has monthly capacity, each region has demand, and each plant-to-region lane has a unit cost. We want the cheapest shipping plan that meets all demand without exceeding capacity.
Step 1: build the data structures
Two lists: Plant (P1, P2, P3) and Region (R1..R4). Then four modules, following DISCO conventions:
SYS01 Plant Properties : Plant -> Capacity (number)
SYS02 Region Properties : Region -> Demand (number)
INP01 Lane Costs : Plant x Region -> Unit Cost (number)
OPT01 Shipping Decision : Plant x Region -> Units Shipped (number)
Lane Cost (number)
Units Shipped is the decision variable. It must be a plain number line item with no formula — the solver writes into it, so a formula would both block the write and defeat the purpose. Set its summary to Sum so you can read totals per plant and per region.
Lane Cost is the linear expression that builds the objective:
Lane Cost = Units Shipped * INP01 Lane Costs.Unit Cost
Note the shape: decision variable multiplied by a constant. That is the only pattern Optimizer accepts in an objective or constraint expression.
Step 2: build the objective module
The objective must resolve to a single cell: one line item, in a module with no dimensions.
OPT00 Objective (no dimensions) -> Total Shipping Cost (number)
Total Shipping Cost = OPT01 Shipping Decision.Lane Cost
Because Lane Cost has a Sum summary across both dimensions, referencing it from an undimensioned module gives the grand total. We will tell Optimizer to minimize this.
Step 3: build the constraint modules
Each constraint is a Boolean line item whose formula compares a linear expression to a limit. Constraints are dimensioned by whatever they apply to — one per plant, one per region.
CON01 Capacity Constraints : Plant
Shipped From Plant = OPT01 Shipping Decision.Units Shipped -- sums across Region
Capacity = SYS01 Plant Properties.Capacity
Within Capacity = Shipped From Plant <= Capacity -- Boolean
CON02 Demand Constraints : Region
Shipped To Region = OPT01 Shipping Decision.Units Shipped -- sums across Plant
Demand = SYS02 Region Properties.Demand
Demand Met = Shipped To Region >= Demand -- Boolean
The Boolean line item is the constraint Optimizer enforces. Anaplan will show it as FALSE while the model is unsolved; that is expected, not an error.
Also add a non-negativity guard. The solver will not invent negative shipments if you tell it the variable's minimum is zero, which you do in the action setup rather than in a formula.
Step 4: create the Optimizer action
From Actions → New Action → Optimizer, then work through the panels:
- Objective — pick
OPT00 Objective.Total Shipping Cost, direction Minimize. - Decision variables — pick
OPT01 Shipping Decision.Units Shipped. Choose the variable type: Continuous if fractional units are acceptable, Integer if not, Binary for yes/no decisions. Set a lower bound of 0 and, where you know one, an upper bound — bounds dramatically shrink the search space. - Constraints — add
CON01.Within CapacityandCON02.Demand Met. - Mapping / time — if the problem repeats per period, map the time dimension here so the solver runs the problem once per period rather than as one giant problem.
- Solve options — set a time limit and, for integer problems, an optimality gap (see below).
Save the action, run it, and read the results back in OPT01 Shipping Decision.Units Shipped.
Continuous, integer, binary — and why it matters
| Type | Use for | Cost |
|---|---|---|
| Continuous | Volumes, currency, hours | Fast; solves in seconds |
| Integer | Whole units, headcount, trucks | Much slower; grows quickly with variable count |
| Binary | Open/close, assign/do not assign | Slowest; combinatorial |
The jump from continuous to integer is the single biggest performance cliff in Optimizer. A continuous problem with 50,000 variables can solve comfortably; a binary problem with 5,000 can time out. If integers are genuinely required, use the optimality gap setting: telling the solver to accept a solution within 1% of the theoretical optimum often cuts run time by an order of magnitude, and 1% is well inside the noise of your input data anyway.
Binary decisions: adding the "big M" pattern
The classic extension is a fixed cost: opening a plant costs money whether or not you ship much from it. That needs a binary variable and a link between the binary and the continuous flow.
OPT01 Shipping Decision : Plant
Plant Open = binary decision variable (number, 0 or 1, no formula)
Fixed Cost = Plant Open * SYS01 Plant Properties.Fixed Cost
CON03 Linking : Plant
Shipped From Plant = OPT01 Shipping Decision.Units Shipped
Max If Open = Plant Open * SYS01 Plant Properties.Capacity
Link Valid = Shipped From Plant <= Max If Open -- Boolean
If Plant Open is 0, the constraint forces shipments from that plant to 0. If it is 1, the constraint reduces to the ordinary capacity limit. Add Fixed Cost into the objective and the solver now trades shipping cost against fixed cost on its own.
Keep the "big M" — here the capacity — as tight as you truthfully can. An artificially huge number makes the solver's job much harder and is a common cause of models that run for an hour and return nothing useful.
When the solver says "infeasible"
Infeasible means no answer satisfies every constraint at once. It is almost always a data problem, not a solver problem. Work through it in this order:
- Check totals. Is total capacity actually greater than total demand? Sum both. This finds the majority of cases.
- Look for contradictory hard constraints. A minimum volume per lane plus a strict capacity limit is a common pair that cannot both hold.
- Check units and time. Monthly capacity against annual demand produces instant infeasibility.
- Relax one constraint at a time. Turn each Boolean off in the action and re-run. The one that makes the problem solvable is your culprit.
- Soften the constraint. Where the business rule is really a preference, replace the hard constraint with a penalty: allow the shortfall as a decision variable and add a large per-unit cost for it in the objective. The model then returns the least-bad plan instead of nothing — which is far more useful to a planner at 6pm.
That last pattern is worth adopting by default for demand satisfaction. Planners would rather see "we can meet 96% and here is what is short" than an error message.
Performance practices
- Shrink the problem before you tune the solver. Do not create decision variables for lanes that cannot exist. Filter the decision module's dimensions with a subset or a Boolean mapping so infeasible combinations never become variables.
- Bound everything. Every decision variable should have a lower and an upper bound. Unbounded variables force the solver to explore nonsense.
- Solve per period, not across all periods — unless the periods are genuinely linked by inventory carry-over. One problem per month is many small problems; one problem across twelve months is one enormous one.
- Keep the decision module clean. Nothing but decision variables and the linear expressions built from them. Reporting and allocation logic belongs downstream, in ordinary calculation modules.
- Set a time limit. Always. An action with no time limit will happily consume your patience.
- Save the inputs with the result. Copy the inputs used into a snapshot module when a scenario is run, so a plan can be reproduced and explained three weeks later.
Fitting Optimizer into the planning process
An optimization run is not a plan until a human accepts it. The pattern that works:
- A planner sets the scenario inputs on a UX page — capacities, service level, budget.
- A button runs a process: refresh inputs → run Optimizer → copy results into a scenario version.
- The page shows the recommendation next to the current plan, with the deltas and the objective value.
- The planner overrides what they disagree with, and the model reports the cost of those overrides.
Step 4 is what makes the tool trusted. Showing "your manual change costs £41k versus the optimal plan" turns the solver from an oracle into a negotiating partner, and it is also the fastest way to find the constraints nobody told you about. Wrap the whole thing in an approval flow if the output commits real money — the same pattern as approval chains with Anaplan Workflow.
Optimizer, Forecaster, and AI: which does what
These get conflated constantly.
- Forecaster predicts what will happen: statistical and ML forecasting from history. See our Forecaster guide.
- Optimizer prescribes what to do: a deterministic solver over constraints you define.
- AI assistants and agents help people navigate and explain the model. Our take on where that is real is in AI agents in enterprise planning.
A mature supply chain model uses all three in sequence: forecast demand, optimize the response, explain the result. Note that Optimizer is a Hyperblock-era capability; if you are weighing calculation engines, read Hyperblock or Polaris first, because that choice affects what is available to you.
A sensible first project
Do not start with the enterprise network. Start with something a single planner owns, that runs in under a minute, and where the current process is a spreadsheet:
- allocating a fixed marketing budget across campaigns to maximize modeled return,
- assigning accounts to sales reps subject to workload balance,
- choosing production runs for one plant for one month.
Get one of these live, prove the numbers against the manual answer, and let the planner break it for two weeks. The credibility you build there is what buys you the network model.
Where we help
We build Optimizer models — formulating the problem, keeping it linear and solvable, and wiring the results into pages planners will actually use. It sits alongside our supply chain and sales forecasting work, and behind it our model design and build and performance optimization practices. If you have a spreadsheet that someone solves by hand every month, that is usually the right first candidate — get in touch and we will tell you whether it is a fit.