Define calculations

Use calculations to compute new information during the configuration process. Defined as arithmetic equations or formulas, they handle tasks such as cost estimation based on user input and calculating other dependent parameters.

For example, for a product made of metal, calculations can determine the area based on its length and width. Then, the pricing engine can use this calculated area to estimate the metal product cost.

Tip

The pricing engine calculates the cost, while the calculation engine calculates the area.

Calculations are defined in the product knowledge base and compute the values of Dynamic Data Attributes (DDA) and Dynamic Symbolic Attributes (DSA) of the numeric type. However, you can perform assignments only on numeric DDAs.

Using basic BODMAS principles combined with arithmetic functions, calculations can handle anything from simple estimations to complex computations.

Tip

IMCScript offers a more powerful tool set to set up custom calculations in the model. However, IMCScript applies to the whole system, while calculations apply only to a specific knowledge base.

Create a calculation

  1. Create a dynamic data attribute (DDA) of the numeric type.

  2. Add the DDA to the product knowledge base.

  3. Group the attributes in the product knowledge base.

  4. In the knowledge base, go to the Calculations tab by following these steps:

    1. From the application left navigation area, select Products.
    2. Select a product.
    3. From the top navigation bar, select Knowledge Base.
    4. Select a knowledge base, then go to the Calculations tab.
  5. Select to create a calculation.

  6. On the Create New Calculation dialog, enter the following information:

    • Name—Enter a name for the calculation, for example the name of your dynamic attribute.
    • Arithmetic Expression—Enter an arithmetic expression including one or multiple numeric dynamic attributes. Use the $() syntax to add a dynamic attribute.
  7. Create a knowledge base snapshot.

In the product configurator, users can't edit the value of the dynamic attribute, whose value is computed based on a calculation.

Calculation features

  • Includes various checks such as cyclic dependency detection, cast exceptions, divide-by-zero exceptions, and unacceptable syntax validation.
  • Includes several built-in functions from the Jexl library, such as substring() for strings and size() for various objects.
  • Supports basic mathematical operators (+, -, *, /, %) and includes additional constants and custom functions.
  • Allows nested function calls, for example, min(max(5, 2, pow(2, 3)), 20, 30).
  • Unlike the conventional Java math library, we support dynamic variable lengths for custom functions. For example, you can calculate GCD, LCM, or AVG for multiple variables in a single function call, such as gcd(12, 24, 36, 40).

Calculation performance

All functions execute with an average duration of less than 0.1 ms.

We conducted the performance tests on a system with the following specifications:

  • Processor: Core i5
  • Memory: 8 GB RAM
  • Operating system: Windows 10 Pro, 64-bit

We used a typical machine after startup, parameters, for example arrays, of up to 5 elements and relatively small integers and strings. Actual performance may vary based on specific use cases and system configurations.

Libraries

Constant library

The Math. prefix can use defined here functions, for example, Math.PIE, Math.E, or Math.EQ.

Standard constants

Constant Value
PIE π 3.14159265358979323846, ratio of circumference to its diameter.
E e 2.7182818284590452354, the base of natural algorithms.

Conditional constants

Constant Function
EQ Defines Equivalence relation (==) between 2 operands.
NEQ Defines Not-equivalence relation (!=) between 2 operands.
LT Defines Less than relation (<) between 2 operands.
LTE Defines Less than and equals to relation (<=) between 2 operands.
GT Defines Greater than relation (>) between 2 operands.
GTE Defines Greater than and equals to relations (>=) between 2 operands.

Directional constants

Constant Functions
ASC Depending on the use case context, defines ascending direction for any operation.
DESC Depending on the use case context, defines descending direction for any operation.

Standard functions

Function Description Example
Summation sum(Number... nVals) : Double
Computes the sum of all provided values.
sum([10, 20, 30]) = 60.0

sum([5, 15, 25, 100]) = 145.0
Multiplication mul(Number... nVals) : Double
Computes the multiplication of all provided values.
mul([1, 2, 3]) = 6.0

mul(2, 3, 5, 1) = 30.0
Absolute abs(Number n) : Double
Returns the absolute value of the provided number.
abs(-7) = 7.0
Count count(Number... nVals) : Integer
Counts the number of provided arguments or elements in an array.
This function is similar to Jexl's default size method.
count([4, 5]) = 2

count(1, 2, 3, 4, 5) = 5
Maximum max(Number... nVals) : Double
Returns the largest number among the provided numbers.
max(4, 11) = 11.0

max(1, 2, 7, 9) = 9.0
Average avg(Number... nVals) : Double
Computes the average of the provided values.
This function is equivalent to the Mean function in statistics.
avg(4, 7) = 5.5

avg(6, 4.5, 11.5, 2) = 6.0
Greatest Common Divisor (GCD) gcd(Number... nVals) : Integer
Calculates the greatest common divisor (GCD) of the provided numbers.
gcd(24, 18) = 6

gcd(50, 24, 18) = 2
Least Common Multiple (LCM) lcm(Number... nVals) : Integer
Calculates the least common multiple (LCM) of the provided numbers.
lcm(16, 4) = 16

lcm(32, 12, 16, 2) = 96

Convergence functions

Function Description Example
Round round(Number n, Number decimal) : Double
Rounds the number to the specified decimal digits. If the second argument is not provided, the default decimal digits will be 2.
round(3.1345964, 4) = 3.1346

round(3.1345964) = 3.13
Ceil ceil(Number n) : Double
Finds the ceiling value of a number.
ceil(7.345) = 8.0

ceil(-7.345) = -7.0
Floor floor(Number n) : Double
Finds the floor value of a number.
floor(7.345) = 7.0

floor(-7.345) = -8.0

Statistical functions

Function Description Example
Mean mean(Number… nVals) : Double
Finds the mean of the provided numbers. This function is the same as the Average function in the list of standard functions.
mean(4, 7) = 5.5

mean(6, 4.5, 11.5, 2) = 6.0
Median median(Number… nVals) : Double
Finds the median of the provided numbers.
median(3, 2, 7, 1, 9, 2, 10) = 3.0

median(1, 2, 3, 4, 5, 6) = 3.5
Mode mode(Number… nVals) : Double
Finds the mode of the provided numbers. This function doesn’t guarantee any order of outcomes (modes).
mode(8, 2, 7, 2, 9, 2, 10) = [2.0]

mode(1, 3, 3, 4, 2, 5, 2) = [3.0, 2.0]

mode(1, 2, 3, 4, 5) = []

mode(1, 1, 2, 2, 3, 3) = [1.0, 2.0, 3.0]

Exponential functions

Function Description Example
Power pow(Number n, Number exponent) : Double
Finds the nth power of the number.
pow(2, 3) = 8.0
pow(5, 2) = 25.0
Root root(Number n, Number root) : Double
Finds the nth root of the number. If multiple roots exist, the function returns only the positive root.
root(16, 4) = 2.0

root(3, 2) = 1.7320508075688772
Square sq(Number n) : Double
Finds the square of a number.
This is a special case of the Power method with an exponent of 2; hence, it’s equivalent to calling pow(n, 2).
sq(3) = 9.0
Cube cube(Number n) : Double
Returns the cube of a number.
This is a special case of the Power method with an exponent of 3; hence, it’s equivalent to calling pow(n, 3).
cube(3) = 27.0
Square-Root sqrt(Number n) : Double
Returns the positive square root of a number.
This is a special case of the Root method with root 2; hence, it’s equivalent to calling root(n, 2).
sqrt(25) = 5.0
Cube-Root cbrt(Number n) : Double
Returns the cube root of a number.
This is a special case of the Root method with root 3; hence, it’s equivalent to calling root(n, 3).
cbrt(27) = 3.0

Trigonometric functions

Function Description Example
Degree to Radian rad(Number degree) : Double
Converts degrees to radians.
rad(50) = 0.8726646259971648
Radian to Degree deg(Number radian) : Double
Converts radians to degrees.
deg(0.8726646259971648) = 50
Sine sin(Number radian) : Double
Returns the sine value of a radian.
sin(0) = 0.0

sin(rad(45)) = 0.7071067811865475
Cosine cos(Number radian) : Double
Returns the cosine value of a radian.
cos(0) = 1.0

cos(rad(45)) = 0.7071067811865476
Tangent tan(Number radian) : Double
Returns the tangent value of a radian.
tan(0) = 0.0

tan(rad(45)) = 0.9999999999999999
Arc-Sine asin(Number value) : Double
Returns the arc-sine (inverse of the sine function) of a value.
asin(0.70) = 0.775397496610753

asin(sin(1)) = 1.0
Arc-Cosine acos(Number value) : Double
Returns the arc-cosine of a value (inverse of the cosine function).
acos(0.70) = 0.7953988301841436

acos(cos(1)) = 1.0
Arc-Tangent atan(Number value) : Double
Returns the arc-tangent of a value (inverse of the tangent function).
atan(0.70) = 0.6107259643892086

atan(tan(1)) = 1.0

Logarithmic functions

Function Description Example
Logarithm log (Number number, Number base) : Double
Calculates and returns the logarithmic value of a number using the provided base. If the second argument is absent, the default base will be considered as e = 2.718281828459045, which is the base of natural logarithms.
log (100,10) = 2.0

log (100) = 4.605170185988092
Logarithm with base 10 log10 (Number number) : Double
Calculates and returns the logarithmic value of a number using base 10. This is a special case of the Logarithm method with base 10, hence it’s the same as calling log(n,10).
log10 (100) = 2.0

Casting functions

Function Description Example
To Integer (String) toInteger (String s, Integer default) : Integer
Converts the provided String to Integer type. If any exception occurs during execution (for example, CastException), it will return the default value provided as the second argument.
toInteger (String[] sArray, Integer default) : Integer
Converts the provided String array to an Integer array. If any exception occurs during conversion of any element (for example, CastException), it will return the default value provided as the second argument.
Note: If the second argument is of the Double type, it will consider its Integer part as the default value.
toInteger("11.3",5) = 11

toInteger("11",5) = 11

toInteger("abc",5) = 5

toInteger("def") = 0

toInteger("abc",5.5) = 5

toInteger(["5", "6"],5.5) = [5, 6]

toInteger(["7", "a"],5.5) = 5.5
To Integer (Number) toInteger (Number n, Integer default) : Integer
Converts the provided Number to Integer type. If any exception occurs (for example, unacceptable numbers like NaN/Infinity/-Infinity), it will return the default value provided as the second argument.
toInteger (Number[] nArray, Integer default) : Integer
Converts the provided Number array to Integer array. If any exception occurs (for example, unacceptable numbers like NaN/Infinity/-Infinity), it will return the default value provided as the second argument.
Note: If the second argument is of the Integer type, it will convert it to Double and consider it as the default value.
toInteger(31.3,5) = 31

toInteger(31,5) = 31

toInteger(NaN,0) = 0

toInteger(log(0),0) = 0

toInteger([8.5,3.6],5) = [8,6]

toInteger([8.5,NaN],5) = [8,5]
To Double (String) toDouble (String s, Number default) : Double
Converts the provided String to Double type. If any exception occurs (for example, CastException), it will return the default value provided as the second argument.
toDouble (String[] sArray, Number default) : Double
Converts the provided String array to an array of Double type. If any exception occurs during conversion of any element (for example, CastException), it will return the default value provided as the second argument.
Note: If the second argument is of the Integer type, it will convert it to Double and consider it as the default value.
toDouble("11.3",5.0) = 11.3

toDouble("11",5.0) = 11.0

toDouble("abc",5.0) = 5.0

toDouble("abc",5) = 5.0

toDouble(["11","13"],5.0) = [11.0,13.0]

toDouble(["11","b"],5.0) = [11.0,5.0]
To Double (Number) toDouble (Number… nVals) : Double
Converts the provided Number to Double type.
toDouble(40) = 40.0

toDouble(51.87) = 51.87

toDouble(40,50) = [40.0,50.0]
To String toString (Number nVals) : String
Converts the provided Number to String type.
toString(11) = "11.0"

toString(11.3,5.0) = ["11.3", "5.0"]

Check functions

Function Description Example
Is Finite isFinite (Number n) : Boolean
Checks if the number is finite or not. Returns true if the argument is a finite value; returns false otherwise (for NaN and Infinity arguments).
isFinite(0.70) = true

isFinite(log(0)) = false

isFinite(NaN) = false
Is Not-A-Number isNaN (Number n) : Boolean
Checks if the number is not a number (NaN) or not. Returns true if the argument is NaN; returns false otherwise.
isNaN(NaN) = true

isNaN(0.70) = false

isNaN(log(0)) = false
Is Null isNull (Number n) : Boolean
Checks if the argument is null or not. Returns true if the argument is null; returns false otherwise.
isNull(null) = true

isNull(log(0)) = false

isNull(NaN) = false

Conditional functions

Function Description Example
If iff(Boolean condition, Number numberIfTrue, Number numberIfFalse) : Number
This conditional function works like a ternary operator, returning a value based on the outcome of the condition (first argument).
iff(10 < 5, 1, 0) = 0

iff(round(sin(rad(45))) == round(cos(rad(45))), 1, 0) = 1
Filter If filterIf(Number[] nArray, Constant condition, Number compareTo) : Number[]
Filters an array based on the provided mathematical condition, using the last two arguments. Here the second argument is a conditional constant: Math.EQ, Math.NEQ, Math.LT, Math.LTE, Math.GT, Math.GTE.
Note: You can also use strings like ">=" instead of constants for better readability. An incorrect condition results in an empty array.
filterIf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], Math.GT, 5) = [6, 7, 8, 9, 10]

filterIf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], Math.LTE, 5) = [1, 2, 3, 4, 5]

filterIf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ">=", 8) = [8, 9, 10]
Count If countIf(Number[] nArray, Constant condition, Number compareTo) : Integer
Counts the number of elements in an array that meet the specified condition. Internally, this method calls Filter If and then Count.
Note: An incorrect condition returns 0 as the result.
countIf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], Math.GT, 5) = 5

Special functions

Before you begin

  • Keep special cases in mind when using these functions, such as NaN, +Infinity, -Infinity, and null, as they may return results like NaN, +Infinity, -Infinity, or other values depending on the case.

  • Avoid passing one or more null arguments, as this typically results in NaN (or a default argument, if specified). We do not recommend providing NaN or null in arguments to prevent unexpected results.

  • All function and constant names are case-sensitive and signature-sensitive. Follow the correct syntax and signatures to avoid errors.

  • Functions with a single parameter of variable argument types (for example, Double..., String...) allow flexibility. You can pass either an array or variable arguments. For example, max(3,4,5) returns the same result as max([3,4,5]).

  • Calculations are currently limited to the same knowledge base. You cannot access DAs from another product’s knowledge base or from parent/child attributes of a SalesItem. However, you can use Search Expressions to bridge this gap.

  • Avoid using the SearchExpression method unless absolutely necessary. If you must use it, review the notes associated with it beforehand.

  • The distinction between type and types keywords has been simplified for search expressions. Previously, type and types behaved differently, but now only the type keyword exists. It returns a collection of all object types, making the syntax more generic for various use cases. You can still retrieve a single type of object using the first keyword, as shown in the following table. When migrating legacy search expressions, update their syntax to align with this change.

    Old syntax New syntax
    SalesItem.type.endsWith('Stamping') SalesItem.type.first().endsWith('Stamping')
    SalesItem.types.ID SalesItem.type.ID

Functions

Function Description Example
Sort sort(Number[] nArray, Constant direction) : Boolean
Sorts the provided array (nArray) in the specified direction (direction). Direction can be one of the constants: Math.ASC (ascending) or Math.DESC (descending). Note: Defaults to Math.ASC if direction is not provided. Invalid direction values result in an unsorted array.
Handles special cases: +Infinity, -Infinity, and NaN based on Java comparator conventions.
sort([4,3,6,9,5], Math.ASC) = [3,4,5,6,9]

sort([4,3,6,9,5], Math.DESC) = [9,6,5,4,3]

sort([10,NaN,-log(0),log(0)]) = [-Infinity, 10, +Infinity, NaN]
Distinct dist(Number[] nArray) : Number[]
Returns an array of distinct elements from the provided array. This function doesn't guarantee any specific order for the output array.
dist([5,3,4,4,5]) = [3,4,5]

dist([10,2,3,10,2]) = [2,3,10]
Concatenate concat(String[] sArray1, String[] sArray2) : String[]
Concatenates corresponding elements of two arrays and returns the result as a new array. Note: Null values are treated as empty strings. The resulting array length equals the maximum length of the input arrays.
concat(["a","b","c"], ["1","2",null]) = ["a1","b2","c"]

concat(["a","b","c"], ["1","2"]) = ["a1","b2","c"]

concat(["a","b"], ["1","2","3"]) = ["a1","b2","3"]
Concatenate concat(String... sArgs) : String
Concatenates one or more string arguments into a single string. Note: Null arguments are treated as empty strings.
concat("a","b","c") = "abc"

concat("a","b",null) = "ab"
Mapper map(String[] sArray, Map<String,String> sMap) : String[]
Updates an array (sArray) by replacing each element using a provided map (sMap). Missing keys leave the element unchanged.
map(["a","b","c"], {"a":"1","b":"2","c":"3"}) = ["1","2","3"]

map(["a","b","c","d"], {"a":"1","b":"2","c":"3"}) = ["1","2","3","d"]
Mapper map(Number[] nArray, Map<Number, Number> nMap) : Double[]
Updates a numeric array (nArray) by replacing elements using a provided map (nMap). Missing keys leave the element unchanged.
map([1,2,3], {1:11,2:22,3:33}) = [11.0,22.0,33.0]

map([1,2,3], {1.0:11,2:22,3:33.0}) = [11.0,22.0,33.0]

map([1,2,3,4], {1:11,2:22,3:33}) = [11.0,22.0,33.0,4.0]
Search Expression se(String expression).as<<TYPE>>(TYPE defaultObj) : TYPE
Enables traversing between object levels (for example, parent SalesItem and its children).
Syntax:
  • se—Accepts a search expression as a string (starts with "ConfigItem").
  • as<<TYPE>>—Specifies the expected return type (Number, String, SArray, or NArray).
If the expression is null or an error occurs, returns defaultObj.
Note: This experimental function has performance limitations and lacks validation for nested dependencies. Consider alternate options like triggers or additional DAs for complex use cases.
se("ConfigItem.configItemIncludedBy.children().getDAValue('DA1')").asNArray([]) = [10,20,30]

se("ConfigItem.configItemIncludedBy.objectName").asString('No_Name') = "SalesItem1"