This article is part of a series on Polaris best practices. Click here for more Community content or visit Anapedia for detailed technical guidance. This is a deeper dive on the concept outlined in the Anaplan Polaris – Understanding Blueprint Insights and Optimizing for Populated Space article.
A “guard” refers to an IF THEN statement used in a formula with conditions to tell the Polaris engine when to calculate. Polaris is already designed to minimize unnecessary calculations by skipping the default values of zero, blank and false, but it can only act on what it inherently knows. Guards help fill in the gaps by explicitly telling the engine when to calculate and when to skip. The goal is to focus the calculation effort by using your knowledge of the use case to identify the intersections you want to calculate. This technique is highly effective for calculations in modules with high dimensionality and inherent sparsity.
Below are some examples of effective, ineffective or completely missing guards and recommendations on their use in Polaris.
Missing Guards
Guards are not required or recommended everywhere in Polaris. Deriving attributes in system modules, calculations on modules that will always have low dimensionality, and calculations on already guarded values or very sparse data likely do not need to use this technique. However, omitting guards can easily lead to overly dense and inefficient calculations.
For this example, consider a calculation of Growth Rate % across all intersections in a module that includes Product SKUs and Accounts over time. While this would be a valid formula if every Account sold every SKU, such a scenario is highly unlikely in real-world situations. You can see below that the formula without guards populates nearly 5.8 million cells, with a calculation effort close to 90%.
Formula without guards: Growth Rate % = 'DEM02 Volume Growth Rates by Week'.Growth %[LOOKUP: 'SYS08 SKU Details'.Product Family]
Effective guards
In the Growth Rate % example above, adding a simple guard will bring the Populated Cell Count, Memory Used and the Calculation Effort down markedly. One way to do this is by creating a validation module (1)
to tell Polaris when to calculate the Growth Rate %. This validation module is a small, targeted module that indicates valid product-account combinations. Because it is much smaller than the main calculation module, it’s inexpensive to evaluate.
Formula with guards: Growth Rate % = IF 'SYS11_Valid Products by Account'.Valid? THEN 'DEM02 Volume Growth Rates by Week'.Growth %[LOOKUP: 'SYS08 SKU Details'.Product Family] ELSE 0
Validation module:
Unnecessary guards
On the other hand, some guards are redundant in Polaris and add no performance benefit. In the Classic Anaplan engine model builders will often use a “<> 0” guard to enable an early exit in IF statements. In Polaris, this isn’t needed. Polaris inherently ignores zero values. The examples below show unnecessary guards that check for zeros, and while such guards don’t affect performance, avoiding them will help build a better understanding of how Polaris works, and keep formulas clean and concise.
Example 1
The generic example of this is the formula “IF X <> 0 THEN X ELSE 0”. Polaris calculates this as if the formula was simply “X” because it skips the parts of the calculation that result in a default value. The results are identical, but the IF/THEN portion is unnecessary.
Example 2
A more complicated example of an ineffective guard can be seen when nesting IF statements. The first version, which is trying to provide “early exit” logic, is calculated in an identical manner as the second version because Polaris does not check for TRUE Boolean values when the result would be zero. This can give a false sense of security that the calculation has been optimized.
Before — formula containing unnecessary guard:
After — formula with guard removed:
Reversing sparsity with guards
While guards can dramatically improve performance, it should be noted they can inadvertently “reverse” the sparsity of a line item and thus it is important to use caution when writing your formulas. Formulas that result in a value for many or most cells, like “…ELSE X + 1” or “…ELSE TRUE” can result in high density and poor performance at high dimensionality. One way to think through this is to ask yourself: if all variables feeding this formula are zero (or blank or FALSE), what is the result? If the answer is not zero, blank or FALSE then you should rethink your logic.
Returning to our example above, if we were to write the formula for “Growth Rate %” as IF 'SYS11_Valid Products by Account'.Valid? THEN 'DEM02 Volume Growth Rates by Week'.Growth %[LOOKUP: 'SYS08 SKU Details'.Product Family] ELSE 1” it would have the opposite effect of guarding and would instead make the line item fully dense with a calculation complexity of “All Cells”.
In summary, when optimizing formulas with conditions, it is important to distinguish between values which Polaris already knows to skip — the default values of zero, false, or blank — and what it doesn't know unless you specify it, such as "this account only sells these products”. However, not every calculation needs a guard. Overuse can lead to ineffective logic and make the model harder to understand and maintain. Apply them thoughtfully, and they can improve performance, reduce memory usage, and create clear, more maintainable models.
(1) It is easy to get into trouble by building very large, very dense guard line items. Such guard line items are often just as expensive as the formula they are guarding: negating the point of having a guard in the first place. If you are using a Boolean line item as a guard condition, it must be significantly smaller (in populated cells) than the formula it is designed to act as a guard for. Ideally with much lower dimensionality (inherently smaller), but if not lower dimensionality, then much sparser (almost always false).
……………
Author: Anaplan’s Theresa Reid (@TheresaR), Performance and Architecture Director
.
Special thanks to Rob Marshall ,@rob_marshall), Mark Warren (@MarkWarren), and Tom Shackell (@TomS) for their contributions.