diff --git a/src/main/java/com/jdoe/algorithms/BuildRegressionMatrix.java b/src/main/java/com/jdoe/algorithms/BuildRegressionMatrix.java
new file mode 100644
index 0000000..393b7d7
--- /dev/null
+++ b/src/main/java/com/jdoe/algorithms/BuildRegressionMatrix.java
@@ -0,0 +1,212 @@
+package com.jdoe.algorithms;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.jdoe.util.BuildRegressionMatrixUtility;
+
+public class BuildRegressionMatrix {
+
+ /**
+ * Builds a regression matrix from an experimental design matrix and a mathematical model string.
+ *
+ *
+ * This method constructs a regression matrix by evaluating mathematical expressions defined in
+ * the model string using values from the experimental design matrix. Each token in the model
+ * string represents a mathematical expression involving variables (x00, x01, etc.) that correspond
+ * to columns in the experimental design matrix.
+ *
+ *
+ *
+ * The method supports two modes of operation:
+ *
+ * - Matrix Mode: When the experimental design matrix has multiple columns,
+ * each row of the design matrix is used to evaluate all expressions in the model string.
+ * The resulting regression matrix will have dimensions [n_rows × n_terms], where n_rows
+ * is the number of rows in the design matrix and n_terms is the number of terms in the model.
+ * - Vector Mode: When the experimental design matrix has a single column,
+ * the matrix is treated as a vector of variables, and the regression matrix will have
+ * dimensions [n_terms × 1], where each row represents the evaluation of one expression.
+ *
+ *
+ *
+ *
+ * The model string should contain space-separated mathematical expressions. Variables are
+ * represented as x followed by zero-padded indices (e.g., x00, x01, x02...). The method
+ * supports standard mathematical operations: addition (+), subtraction (-), multiplication (*),
+ * division (/), and exponentiation (^), as well as parentheses for grouping.
+ *
+ *
+ *
+ * Example usage:
+ *
+ * // Matrix mode example
+ * double[][] design = {{1.0, 2.0}, {3.0, 4.0}};
+ * String model = "x00 x01 x00^2 x01^2 x00*x01";
+ * double[][] regressionMatrix = BuildRegressionMatrix.buildRegressionMatrix(design, model, null);
+ * // Result: 2x5 matrix with evaluated expressions
+ *
+ * // Vector mode example
+ * double[][] design = {{1.0}, {2.0}, {3.0}};
+ * String model = "x00 x00^2 x00^3";
+ * double[][] regressionMatrix = BuildRegressionMatrix.buildRegressionMatrix(design, model, null);
+ * // Result: 3x1 matrix with evaluated expressions
+ *
+ *
+ *
+ *
+ * If the experimental design matrix has a single row but multiple columns, it will be
+ * automatically transposed to column format before processing. The buildFlags parameter
+ * allows selective evaluation of specific terms in the model string.
+ *
+ *
+ *
+ * Supported mathematical operations:
+ *
+ * - Basic arithmetic: +, -, *, /
+ * - Exponentiation: ^
+ * - Parentheses for grouping: ( )
+ * - Variable expressions: x00, x01, etc.
+ *
+ *
+ *
+ * @param experimentalDesignMatrix A 2D array containing experimental design data.
+ * In matrix mode, each row represents an experimental run and each column represents
+ * a factor. In vector mode, each row represents a variable value.
+ * @param modelString A space-separated string containing mathematical expressions to evaluate.
+ * Each token represents an expression involving variables (x00, x01, etc.) and mathematical
+ * operations.
+ * @param buildFlags A boolean array indicating which terms in the model string to evaluate.
+ * If null, all terms will be evaluated. If provided, only terms with true values will
+ * be processed, though the resulting matrix will still have columns for all terms
+ * (with potentially unused columns).
+ * @return A 2D array representing the regression matrix where each element is the result
+ * of evaluating the corresponding mathematical expression using values from the
+ * experimental design matrix. The dimensions depend on the mode:
+ * - Matrix mode: [n_rows × n_terms] where n_rows is rows in design matrix
+ * - Vector mode: [n_terms × 1] where n_terms is number of valid terms in model
+ * @throws IllegalArgumentException if the mathematical expressions are invalid or contain
+ * syntax errors, or if division by zero occurs during evaluation
+ * @throws ArithmeticException if division by zero occurs during evaluation
+ * @see BuildRegressionMatrixUtility#grep(String[], String)
+ * @see FactorialDOE#fullFactorial(Integer[])
+ * @see BoxBehnkenDOE#boxBehnkenDesign(int)
+ */
+ public static double[][] buildRegressionMatrix(double[][] experimentalDesignMatrix,
+ String modelString,
+ boolean[] buildFlags) {
+
+ // Spliting the model string into individual tokens
+ String[] listOfTokens = modelString.split(" ");
+
+ // Determine the size index based on the matrix dimensions
+ int sizeIndex;
+ if (experimentalDesignMatrix[0].length == 1) {
+ // For vector mode (single column)
+ sizeIndex = String.valueOf(experimentalDesignMatrix.length - 1).length();
+ } else {
+ // For matrix mode
+ sizeIndex = String.valueOf(experimentalDesignMatrix[0].length - 1).length();
+ }
+
+ // If buildFlags is null, create a default array with all true values
+ if (buildFlags == null) {
+ buildFlags = new boolean[listOfTokens.length];
+ Arrays.fill(buildFlags, true);
+ }
+
+ // Test if the matrix has the wrong orientation (single row instead of columns)
+ if (experimentalDesignMatrix.length == 1 && experimentalDesignMatrix[0].length > 1) {
+ // Transpose the matrix (single row to single column)
+ double[][] transposedMatrix = new double[experimentalDesignMatrix[0].length][1];
+ for (int i = 0; i < experimentalDesignMatrix[0].length; i++) {
+ transposedMatrix[i][0] = experimentalDesignMatrix[0][i];
+ }
+ experimentalDesignMatrix = transposedMatrix;
+ }
+
+ // Filter tokens based on buildFlags
+ List filteredTokens = new ArrayList<>();
+ for (int i = 0; i < listOfTokens.length; i++) {
+ if (buildFlags[i]) {
+ filteredTokens.add(listOfTokens[i]);
+ }
+ }
+
+ // Determine mode and number of variables
+ boolean isVectorMode = (experimentalDesignMatrix[0].length == 1);
+ int numberOfVariables;
+
+ if (isVectorMode) {
+ numberOfVariables = experimentalDesignMatrix.length;
+ } else {
+ numberOfVariables = experimentalDesignMatrix[0].length;
+ }
+
+ // Create variable replacement patterns
+ String[][] variableReplacements = new String[numberOfVariables][2];
+ for (int i = 0; i < numberOfVariables; i++) {
+ String paddedIndex = String.format("%0" + sizeIndex + "d", i);
+ variableReplacements[i][0] = "x" + paddedIndex;
+ if (isVectorMode) {
+ variableReplacements[i][1] = "H[" + i + "]";
+ } else {
+ variableReplacements[i][1] = "H[row][" + i + "]";
+ }
+ }
+
+ // Applying variable replacements to all filtered tokens
+ String[] processedTokens = new String[filteredTokens.size()];
+ for (int tokenIndex = 0; tokenIndex < filteredTokens.size(); tokenIndex++) {
+ String token = filteredTokens.get(tokenIndex);
+ for (int varIndex = 0; varIndex < numberOfVariables; varIndex++) {
+ token = token.replace(variableReplacements[varIndex][0],
+ variableReplacements[varIndex][1]);
+ }
+ processedTokens[tokenIndex] = token;
+ }
+
+ // Building the regression matrix
+ double[][] regressionMatrix;
+
+ if (isVectorMode) {
+ // Vector mode: single column output
+ regressionMatrix = new double[filteredTokens.size()][1];
+
+ for (int tokenIndex = 0; tokenIndex < filteredTokens.size(); tokenIndex++) {
+ String expression = processedTokens[tokenIndex];
+ // Replace H[i] with actual values
+ for (int i = 0; i < numberOfVariables; i++) {
+ String placeholder = "H[" + i + "]";
+ String value = String.valueOf(experimentalDesignMatrix[i][0]);
+ expression = expression.replace(placeholder, value);
+ }
+ regressionMatrix[tokenIndex][0] = BuildRegressionMatrixUtility.evaluateMathExpression(expression);
+ }
+ } else {
+ // Matrix mode: one row per design point
+ int numRows = experimentalDesignMatrix.length;
+ int numCols = filteredTokens.size();
+ regressionMatrix = new double[numRows][numCols];
+
+ for (int row = 0; row < numRows; row++) {
+ for (int tokenIndex = 0; tokenIndex < filteredTokens.size(); tokenIndex++) {
+ String expression = processedTokens[tokenIndex];
+ // Replacing H[row][i] with actual values
+ for (int i = 0; i < numberOfVariables; i++) {
+ String placeholder = "H[row][" + i + "]";
+ String value = String.valueOf(experimentalDesignMatrix[row][i]);
+ expression = expression.replace(placeholder, value);
+ }
+ // Replacing 'row' placeholder
+ expression = expression.replace("row", String.valueOf(row));
+ regressionMatrix[row][tokenIndex] = BuildRegressionMatrixUtility.evaluateMathExpression(expression);
+ }
+ }
+ }
+
+ return regressionMatrix;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/jdoe/util/BuildRegressionMatrixUtility.java b/src/main/java/com/jdoe/util/BuildRegressionMatrixUtility.java
new file mode 100644
index 0000000..45a7360
--- /dev/null
+++ b/src/main/java/com/jdoe/util/BuildRegressionMatrixUtility.java
@@ -0,0 +1,197 @@
+package com.jdoe.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BuildRegressionMatrixUtility {
+
+ /**
+ * Grep function to find all occurrences of a pattern in an array of strings
+ */
+ public static List grep( String[] dataArray, String pattern ) {
+ List occurrenceIndexes = new ArrayList<>();
+ for (int i = 0; i < dataArray.length; i++) {
+ if (dataArray[i].contains(pattern)) {
+ occurrenceIndexes.add(i);
+ }
+ }
+ return occurrenceIndexes;
+ }
+
+ /**
+ * Evaluate a mathematical expression string
+ */
+ public static double evaluateMathExpression( String expression ) {
+ try {
+ // Remove whitespace
+ expression = expression.replaceAll("\\s+", "");
+
+ // Handle parentheses first
+ while (expression.contains("(")) {
+ int openParen = expression.lastIndexOf("(");
+ int closeParen = expression.indexOf(")", openParen);
+
+ if (closeParen == -1) {
+ throw new IllegalArgumentException("Mismatched parentheses");
+ }
+
+ String innerExpr = expression.substring(openParen + 1, closeParen);
+ double innerResult = evaluateSimpleExpression(innerExpr);
+
+ expression = expression.substring(0, openParen) + innerResult +
+ expression.substring(closeParen + 1);
+ }
+
+ // Evaluate the final expression
+ return evaluateSimpleExpression(expression);
+ } catch (Exception exception) {
+ System.err.println("Error in math evaluation: " + expression);
+ throw new IllegalArgumentException("Invalid mathematical expression: " + expression, exception);
+ }
+ }
+
+ /**
+ * Evaluate simple expression without parentheses
+ */
+ public static double evaluateSimpleExpression( String expression ) {
+ // Handle exponentiation first (using ^)
+ String[] exponentParts = splitByOperator(expression, '^');
+ if (exponentParts.length > 1) {
+ double result = evaluateSimpleExpression(exponentParts[0]);
+ for (int i = 1; i < exponentParts.length; i++) {
+ result = Math.pow(result, evaluateSimpleExpression(exponentParts[i]));
+ }
+ return result;
+ }
+
+ // Handle multiplication and division
+ String[] mulDivParts = splitByOperators(expression, new char[]{'*', '/'});
+ if (mulDivParts.length > 1) {
+ double result = evaluateSimpleExpression(mulDivParts[0]);
+ int operatorIndex = mulDivParts[0].length();
+
+ for (int i = 1; i < mulDivParts.length; i++) {
+ char operator = expression.charAt(operatorIndex);
+ double nextValue = evaluateSimpleExpression(mulDivParts[i]);
+
+ if (operator == '*') {
+ result *= nextValue;
+ } else if (operator == '/') {
+ if (nextValue == 0) {
+ throw new ArithmeticException("Division by zero");
+ }
+ result /= nextValue;
+ }
+
+ operatorIndex += mulDivParts[i].length() + 1;
+ }
+ return result;
+ }
+
+ // Handle addition and subtraction
+ String[] addSubParts = splitByOperators(expression, new char[]{'+', '-'});
+ if (addSubParts.length > 1) {
+ double result = evaluateSimpleExpression(addSubParts[0]);
+ int operatorIndex = addSubParts[0].length();
+
+ // Check if first part might be negative
+ if (expression.charAt(0) == '-') {
+ result = -result;
+ operatorIndex = 1;
+ }
+
+ for (int i = 1; i < addSubParts.length; i++) {
+ char operator = expression.charAt(operatorIndex);
+ double nextValue = evaluateSimpleExpression(addSubParts[i]);
+
+ if (operator == '+') {
+ result += nextValue;
+ } else if (operator == '-') {
+ result -= nextValue;
+ }
+
+ operatorIndex += addSubParts[i].length() + 1;
+ }
+ return result;
+ }
+
+ // If no operators, parse as a number
+ try {
+ return Double.parseDouble(expression);
+ } catch (NumberFormatException exception) {
+ // Check if it's a numeric constant like "1" or "2"
+ if (expression.matches("-?\\d+(\\.\\d+)?")) {
+ return Double.parseDouble(expression);
+ }
+ throw new IllegalArgumentException("Invalid number: " + expression);
+ }
+ }
+
+ /**
+ * Split expression by a single operator
+ */
+ public static String[] splitByOperator( String expression, char operator ) {
+ List parts = new ArrayList<>();
+ StringBuilder currentPart = new StringBuilder();
+ int parenthesisDepth = 0;
+
+ for (int i = 0; i < expression.length(); i++) {
+ char currentChar = expression.charAt(i);
+
+ if (currentChar == '(') {
+ parenthesisDepth++;
+ } else if (currentChar == ')') {
+ parenthesisDepth--;
+ }
+
+ if (currentChar == operator && parenthesisDepth == 0) {
+ parts.add(currentPart.toString());
+ currentPart = new StringBuilder();
+ } else {
+ currentPart.append(currentChar);
+ }
+ }
+
+ parts.add(currentPart.toString());
+ return parts.toArray(new String[0]);
+ }
+
+ /**
+ * Split expression by multiple operators
+ */
+ public static String[] splitByOperators( String expression, char[] operators ) {
+ List parts = new ArrayList<>();
+ StringBuilder currentPart = new StringBuilder();
+ int parenthesisDepth = 0;
+
+ for (int i = 0; i < expression.length(); i++) {
+ char currentChar = expression.charAt(i);
+
+ if (currentChar == '(') {
+ parenthesisDepth++;
+ } else if (currentChar == ')') {
+ parenthesisDepth--;
+ }
+
+ boolean isOperator = false;
+ for (char operator : operators) {
+ if (currentChar == operator && parenthesisDepth == 0) {
+ isOperator = true;
+ break;
+ }
+ }
+
+ if (isOperator) {
+ parts.add(currentPart.toString());
+ currentPart = new StringBuilder();
+ // Don't append the operator
+ } else {
+ currentPart.append(currentChar);
+ }
+ }
+
+ parts.add(currentPart.toString());
+ return parts.toArray(new String[0]);
+ }
+
+}