ComputeField Interface

Analogous to an Excel cell, the ComputeField interface is a high level representation of the Adaptive Calculation Engine input and formula fields.

Introduction

Suppose we have a simple Excel formula A2=B2+C2:

Illustration of Excel cell via Computefield. Example of a range of cells B1:C4 that forms a produce table.

The below code creates three ComputeFields: inputField1, inputField2, and formulaField analogous to input cells B2 and C2, and formula cell A2. It stores them in the CalculationContext object with corresponding key names. Finally it invokes the static method HybridFormulaEvaluator.evaluateFormula to evaluate the formula of the formulaField.

ComputeField inputField1 = new InputField(ComputeFieldType.NUMERIC, 2);
ComputeField inputField2 = new InputField(ComputeFieldType.NUMERIC, 3);
ComputeField formulaField = new FormulaField(ComputeFieldType.NUMERIC, "B2 + C2");
CalculationContext calculationContext = new CalculationContext("ComputeFieldIntro");
calculationContext.put("B2", inputField1);
calculationContext.put("C2", inputField2);
calculationContext.put("A2", formulaField);
HybridFormulaEvaluator.evaluateFormula("A2", calculationContext);
System.out.printf("Calculated result: %s", calculationContext.get("A2").getDisplayValue());

Calculated result: 5

Excel-like key names of ComputeFields are not required, they are used in this example only for demonstration purposes.

Range of ComputeFields

A range of ComputeFields is a logical collection of input and formula fields. It is not an object.

The code below shows how to place the above mentioned formulaField, inputField1, and inputField2 in the 0, 1, and 2 positions of a ComputeFields range named "my_range", analogous to the range of cells A2:C2:

formulaField.setRangeName("my_range");
inputField1.setRangeName("my_range");
inputField2.setRangeName("my_range");

formulaField.setRangePosition(0);
inputField1.setRangePosition(1);
inputField2.setRangePosition(2);
                

The last three lines of code define the order of formulaField, inputField1, and inputField2 in the ComputeFields range "my_range." The order of these fields would be arbitrary without them.

LAMBDA Field

A LambdaField is analogous to the Excel LAMBDA function. It used to create a custom reusable function based on the Adaptive Calculation Engine formula. The LambdaField functionality allows to simplify formulas and reduce their testing time.

Overview

The Adaptive Calculation Engine supports the following ComputeField data types specified in the ComputeFieldType enum:

  • ComputeFieldType.NUMERIC;
  • ComputeFieldType.ALPHANUMERIC;
  • ComputeFieldType.BOOLEAN.

The InputField class implements the ComputeField interface and the FormulaField class is a subclass of the InputField class.

The InputField class has two constructors:

  • InputField (ComputeFieldType inputFieldType);
  • InputField(ComputeFieldType inputFieldType, Object inputFieldValue).

The first constructor throws the IllegalArgumentException if the inputFieldType is null.

The second constructor throws the IllegalArgumentException if the inputFieldType is null or if it conflicts with the inputFieldValue type.

The FormulaField class has one constructor:

  • FormulaField(ComputeFieldType formulaFieldType, String formulaText).

This constructor throws the IllegalArgumentException if the formulaFieldType is null or the formulaText is null.

All methods of the ComputeField interface are implemented by the InputField class as follows:

  • int getType()

    Note: field type setter is not available.

  • Object getValue()
  • setValue(Object value)

    Throws the IllegalArgumentException if an InputField type conflicts with the value type.

  • Double geNumericValue()

    Throws the NumberFormatException if an InputField value is not a parsable double.

  • String getAlphaNumericValue()

  • Boolean gettBooleanValue()

    Throws the IllegalStateException if an InputField is not a ComputeFieldType.BOOLEAN.

  • String getDisplayValue()

    Returns a string representation of an InputField value or one of the error types such as #VALUE!, #ERROR!, #NUM!, #NAME?, #REF!, #DIV/0!, and #N/A if an InputField is in error.
    If the InputField instance value is an integer stored as a number with zeros after the decimal point, the returned string will contain only the integer.

  • boolean isError()
  • int getErrorCode()

In addition to these methods the FormulaField class utilizes the following methods:

  • String getFormulaText()

    Note: formula text setter is not available.

  • boolean isFormulaFieldOverridden()
  • setFormulaFieldOverridden(boolean formulaFieldOverridden)

    This method should be used when there is a need to lock a certain formula value and use it in the dependent formulas recalculations;
    thus, making the overridden formula field a simple input field.
    This is achieved by invoking this method with the formulaFieldOverridden argument equals true.
    To unlock an overridden formula this method should be invoked with the formulaFieldOverridden argument equals false.

  • String getOperandInErrorName()
  • FormulaIterator getFormulaIterator()
  • setFormulaIterator(FormulaIterator formulaIterator)

Example 1

In this example, the first InputField constructor creates a numeric input field. The following two constructors create the numeric and boolean input fields with the values 20 and true. The fourth constructor creates an alphaNumeric input field with the value "Orange" while the fifth constructor creates an alphaNumeric formula field with the formula text "RIGHT(text, num_chars)".

import com.crystalprism.ce.usermodel.ComputeField;
import com.crystalprism.ce.usermodel.ComputeFieldType;
import com.crystalprism.ce.usermodel.FormulaField;
import com.crystalprism.ce.usermodel.InputField;

public class ComputeFieldExample1 {
    public static void main(String[] args) {
        ComputeField numericInputField1 = new InputField(ComputeFieldType.NUMERIC);
        ComputeField numericInputField2 = new InputField(ComputeFieldType.NUMERIC, 20);
        ComputeField booleanInputField = new InputField(ComputeFieldType.BOOLEAN, true);

        String value = "Orange";
        ComputeField alphaInputField = new InputField(ComputeFieldType.ALPHANUMERIC, value);
        String formulaText = "RIGHT(text, num_chars)";
        ComputeField formulaField = new FormulaField(ComputeFieldType.ALPHANUMERIC, formulaText);
    }
}

Example 2

This example shows how to invoke the ComputeField interface getType() getter.

import com.crystalprism.ce.usermodel.ComputeField;
import com.crystalprism.ce.usermodel.ComputeFieldType;
import com.crystalprism.ce.usermodel.FormulaField;
import com.crystalprism.ce.usermodel.InputField;

public class ComputeFieldExample2 {
    public static void main(String[] args) {
        String myFormulaText = "ROUND(165.78, 1)";
        ComputeField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText);
        ComputeField alphaInputField = new InputField(ComputeFieldType.ALPHANUMERIC);
        ComputeField booleanInputField = new InputField(ComputeFieldType.BOOLEAN);

        System.out.printf("Numeric type: %s ; AlphaNumeric type: %s ; Boolean type: %s",
                myFormulaField.getType(), alphaInputField.getType(), booleanInputField.getType());
    }
}

Numeric type: NUMERIC ; AlphaNumeric type: ALPHANUMERIC ; Boolean type: BOOLEAN

Example 3

This example shows how to invoke the FormulaField class getFormulaText() getter.

import com.crystalprism.ce.usermodel.ComputeFieldType;
import com.crystalprism.ce.usermodel.FormulaField;

public class ComputeFieldExample3 {
    public static void main(String[] args) {
        String myFormulaText = "ROUND(165.78, 1)";
        FormulaField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText);

        System.out.printf("Formula text: %s", myFormulaField.getFormulaText());
    }
}

Formula text: ROUND(165.78, 1)

Example 4

This example shows how to invoke the following ComputeField interface getters and setters: getValue(), getNumericValue(), getAlphaNumericValue(), getDisplayValue(), getBooleanValue() and setValue().
The last getter getBooleanValue() throws the illegalStateException because it is incompatible with the NUMERIC type of the input field in this example.

import com.crystalprism.ce.usermodel.ComputeField;
import com.crystalprism.ce.usermodel.ComputeFieldType;
import com.crystalprism.ce.usermodel.InputField;

public class ComputeFieldExample4 {
    public static void main(String[] args) {
        ComputeField numericInputField = new InputField(ComputeFieldType.NUMERIC);

        numericInputField.setValue(10.0);
        System.out.println("Field value: " + numericInputField.getValue().toString());
        System.out.println("Numeric value: " + numericInputField.getNumericValue());
        System.out.println("AlphaNumeric value: " + numericInputField.getAlphaNumericValue());
        System.out.println("Display value: " + numericInputField.getDisplayValue());
        // Intentional exception
        System.out.println("Boolean value: " + numericInputField.getBooleanValue());
    }
}

Field value: 10.0
Numeric value: 10.0
AlphaNumeric value: 10.0
Display value: 10
java.lang.IllegalStateException: incorrect field type for this method: NUMERIC

Example 5

This example shows how to invoke the ComputeField interface isError() and getErrorCode() getters. The formula text here has one extra closing bracket, which produces an error code 101, corresponding to an unbalanced parentheses condition.

import com.crystalprism.ce.formula.HybridFormulaEvaluator;
import com.crystalprism.ce.usermodel.ComputeFieldType;
import com.crystalprism.ce.usermodel.FormulaField;

public class ComputeFieldExample5 {
    public static void main(String[] args) {
        String myFormulaText = "ROUND(565.78, -3))";
        FormulaField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText);
        HybridFormulaEvaluator.compileExpression(myFormulaField);
        System.out.println("Error was detected: " + myFormulaField.isError());
        System.out.println("Error code: " + myFormulaField.getErrorCode());
    }
}

Error was detected: true
Error code: 101

Example 6

This example shows how to override and lock a formula value. First it evaluates a formula with the value 300, then overrides it with the value 600, and finally the overridden formula value gets locked by the setter setFormulaFieldOverridden(true).

import com.crystalprism.ce.formula.HybridFormulaEvaluator;
import com.crystalprism.ce.usermodel.*;

public class ComputeFieldExample6 {
    public static void main(String[] args) {
        String myFormulaText = "SUM(number1, number2)";
        FormulaField myFormulaField = new FormulaField(ComputeFieldType.NUMERIC, myFormulaText);
        CalculationContext calculationContext = new CalculationContext("ComputeFieldExample6");

        calculationContext.put("number1", new InputField(ComputeFieldType.NUMERIC, 100));
        calculationContext.put("number2", new InputField(ComputeFieldType.NUMERIC, 200));
        calculationContext.put("my_formula", myFormulaField);
        HybridFormulaEvaluator.evaluateFormula("my_formula", calculationContext);
        System.out.println("Calculated result: " +  myFormulaField.getDisplayValue());

        myFormulaField.setValue(600);
        myFormulaField.setFormulaFieldOverridden(true);
        HybridFormulaEvaluator.evaluateFormula("my_formula", calculationContext);
        System.out.println("Is formula field overridden: " +  myFormulaField.isFormulaFieldOverridden());
        System.out.println("Overridden result: " +  myFormulaField.getDisplayValue());

    }
}

Calculated result: 300
Is formula field overridden: true
Overridden result: 600