- 26 Nov 2024
- 13 Minutes to read
- Print
- DarkLight
Define calculations
- Updated on 26 Nov 2024
- 13 Minutes to read
- Print
- DarkLight
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.
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.
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
In the knowledge base, go to the Calculations tab by following these steps:
- From the application left navigation area, select Products.
- Select a product.
- From the top navigation bar, select Knowledge Base.
- Select a knowledge base, then go to the Calculations tab.
Select to create a calculation.
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.
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.0sum([5, 15, 25, 100]) = 145.0 |
Multiplication | mul(Number... nVals) : Double Computes the multiplication of all provided values. | mul([1, 2, 3]) = 6.0mul(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]) = 2count(1, 2, 3, 4, 5) = 5 |
Maximum | max(Number... nVals) : Double Returns the largest number among the provided numbers. | max(4, 11) = 11.0max(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.5avg(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) = 6gcd(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) = 16lcm(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
, andnull
, as they may return results likeNaN
,+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 providingNaN
ornull
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 asmax([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:
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" |