# Performance tuning in Anaplan’s Optimizer

Author: Mike Henderson is a Principal Solution Architect at Anaplan.

A question recently came up from a customer regarding Anaplan Optimizer, and I thought it would be useful to share the answer with the broader Community.

For background, Optimizer uses linear programming to quickly solve complex problems involving thousands of inputs, aiding business planning and decision-making. Optimizer does this by identifying values for variables that maximize or minimize the configured objective. For example, it identifies the most profitable, the fastest, or cheapest, while accounting for any specified constraints. For more information, you can reference this Community article: [Start Here] Anaplan Optimizer.

## The customer’s question

This particular customer leverages Optimizer for finding the sweet spot between demand and capacity for production of a specific product. When they introduced/rolled out a new sort of engine, the time of the Optimizer processing a request went up tremendously.

Now, a few iterations later, after the Optimizer was running a few times, the processing time gradually decreased and is now a little bit above the (pre-new engine) rollout time. They wanted to know — can this behavior be explained by how Optimizer works? Is there, for example, a kind of memory that records the last best state and looks for an improvement from there?

Optimizer has no memory from job to job, there is no learning. Optimizer starts fresh each time it runs. When I have run the same job repetitively with NO changes, I have observed only minor variation in run times and no differences in the result. Optimizer run times are among the great mysteries of the current era. I have seen situations where solve times go from a few seconds to 30 minutes with only a change in the data and not the formula logic.

Here are a few suggestions to help:

1. Use REAL values wherever possible, especially in the "primary variables" (the ones that appear in the objective function). If those need to be integers, there’s a trick where you add "integer twins" whose only constraints is that the vbl_Real - vbl_Integer = 0. The solver is then able to use the continuous gradient of the real numbers, but only keeps the ones that are integers.
2. Sort big lists in order of their contribution to the objective function. For example, suppose you're trying to minimize cost, rank and sort your products list by order of cost per unit. This creates a sort of artificial gradient, and the solver is able to find the best answer more quickly.
3. Have support run the Splunk query to generate the Gurobi logfile for a specific run. This will show them how the solver engine behaved along the path to the solution. This information is useful to set the MIP Gap % tolerance. (See graphic below for a typical minimization problem.)
4. Add constraints that eliminate "stupid alternatives" from consideration. For example, if you're trying to find the shortest path that makes six stops from Miami to Seattle, it never makes any sense to fly from the east coast to the west coast and back to the east coast again. Although the extra constraints add to the size of the problem, they make the solver's solution space much smaller.
5. Can the time horizon be reduced? Time series problems can get very "expensive." I compare this to a chess grandmaster who can assess several moves forward: the more future possibilities are contemplated, the larger the solution space grows. The solver is looking for the optimal solution over all time, so inventory in period 52 depends upon decisions made in each of periods 1 through 51.
6. Re-order the constraints. The solver is doing matrix algebra and by changing the order, you are simply swapping the places of rows in the matrix ... to the solver each is a distinct problem, and it is able to solve some faster than others. Unfortunately, there are no guidelines for what order is best; I personally feel that the first and last constraints seem to make the biggest difference.