diff --git a/src/main/java/com/jdoe/DesignFactory.java b/src/main/java/com/jdoe/DesignFactory.java
deleted file mode 100644
index 6782fc4..0000000
--- a/src/main/java/com/jdoe/DesignFactory.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.jdoe;
-
-public class DesignFactory {
-
- public static void fullFactorialFactory() {
- /*
- will return an instance of the fullfactorial algo object to make its methods accessible
- methods can be static but that is for topic for later
- */
- }
-}
diff --git a/src/main/java/com/jdoe/Testing.java b/src/main/java/com/jdoe/Testing.java
index bba5a4a..75d54d7 100644
--- a/src/main/java/com/jdoe/Testing.java
+++ b/src/main/java/com/jdoe/Testing.java
@@ -1,5 +1,6 @@
package com.jdoe;
+import com.jdoe.algorithms.BoxBehnkenDOE;
import com.jdoe.algorithms.FactorialDOE;
/**
@@ -16,6 +17,7 @@ public static void main( String[] args )
// FactorialDOE.fullFactorial2Level( arrayOfLevels.length );
// FactorialDOE.fractionalFactorial( "a b -ab" );
// FactorialDOE.fractionalFactorial( "a b +ab" );
- FactorialDOE.fractionalFactorialByResolution( 6,4 );
+// FactorialDOE.fractionalFactorialByResolution( 6,4 );
+ // BoxBehnkenDOE.boxBehnkenDesign( 4 );
}
}
diff --git a/src/main/java/com/jdoe/algorithms/BoxBehnkenDOE.java b/src/main/java/com/jdoe/algorithms/BoxBehnkenDOE.java
new file mode 100644
index 0000000..1a2cf2d
--- /dev/null
+++ b/src/main/java/com/jdoe/algorithms/BoxBehnkenDOE.java
@@ -0,0 +1,128 @@
+package com.jdoe.algorithms;
+
+import org.apache.commons.math3.linear.Array2DRowRealMatrix;
+import org.apache.commons.math3.linear.RealMatrix;
+
+public class BoxBehnkenDOE {
+
+ /**
+ * Generates a Box–Behnken design matrix for response surface methodology (RSM).
+ *
+ *
+ * A Box–Behnken design is a three-level experimental design where factor levels take values {@code -1}, {@code 0}, and {@code +1}. In
+ * each experimental run, exactly two factors vary at {@code ±1} while all remaining factors are held at the center level {@code 0}.
+ * This structure allows efficient estimation of quadratic response surfaces while avoiding extreme corner points of the experimental
+ * space.
+ *
+ *
+ *
+ * Design construction logic:
+ *
+ * - Generate a full 2-level factorial design for two factors ({@code ±1}).
+ * - Iterate over all unique pairs of factors {@code (i, j)}.
+ * - For each factor pair, embed the 2-level factorial values into columns
+ * {@code i} and {@code j}, while setting all other factor columns to
+ * the center level {@code 0}.
+ * - Concatenate all such pairwise designs into a single matrix.
+ * - Append center-point runs (all factors set to {@code 0}) to improve
+ * model stability and allow pure-error estimation.
+ *
+ *
+ *
+ *
+ * Matrix dimensions:
+ *
+ * - Number of columns = {@code totalNumberOfFactors}
+ * - Number of non-center rows =
+ * {@code 0.5 × k × (k − 1) × 2²}, where {@code k} is the number of factors
+ * - Number of center-point rows =
+ * {@code k} for {@code k < 16}, otherwise taken from a predefined
+ * standard table
+ *
+ *
+ *
+ *
+ * Example (4 factors):
+ *
+ * {-1, -1, 0, 0}
+ * { 1, -1, 0, 0}
+ * {-1, 1, 0, 0}
+ * { 1, 1, 0, 0}
+ * {-1, 0, -1, 0}
+ * ...
+ * { 0, 0, 0, 0} // center points
+ *
+ *
+ *
+ *
+ * Notes:
+ *
+ * - Only second-order (quadratic) models are supported.
+ * - No run contains more than two active factors.
+ * - Corner points of the full factorial space are intentionally excluded.
+ * - Returned values are coded and must be scaled for physical experiments.
+ *
+ *
+ *
+ * @param totalNumberOfFactors
+ * the number of design factors (must be ≥ 3)
+ *
+ * @return a {@link RealMatrix} representing the Box–Behnken design
+ *
+ * @throws IllegalArgumentException
+ * if {@code totalNumberOfFactors < 3}
+ * @see FactorialDOE#fullFactorial2Level(int)
+ */
+
+ public static RealMatrix boxBehnkenDesign( int totalNumberOfFactors ) {
+
+ // validation
+ if ( totalNumberOfFactors < 3 ) {
+ throw new IllegalArgumentException( "design requires atleast 3 factors" );
+ }
+
+ // making a 2 level design base for the bbdesign
+ RealMatrix ff2levelMatrix = FactorialDOE.fullFactorial2Level( 2 );
+
+ // result matrix dimension calculation
+ int numberOfRows = ( int ) ( 0.5 * totalNumberOfFactors * ( totalNumberOfFactors - 1 ) * ff2levelMatrix.getRowDimension() );
+
+ RealMatrix resultMatrix = new Array2DRowRealMatrix( numberOfRows, totalNumberOfFactors );
+
+ // populate result matrix with base matrix
+ int row = 0;
+ for ( int i = 0; i < totalNumberOfFactors - 1; i++ ) {
+ for ( int j = i + 1; j < totalNumberOfFactors; j++ ) {
+ for ( int r = 0; r < ff2levelMatrix.getRowDimension(); r++ ) {
+ // setting all columns to 0 first
+ for ( int c = 0; c < totalNumberOfFactors; c++ ) {
+ resultMatrix.setEntry( row, c, 0.0 );
+ }
+ // assign ±1 to the factor pair
+ resultMatrix.setEntry( row, i, ff2levelMatrix.getEntry( r, 0 ) );
+ resultMatrix.setEntry( row, j, ff2levelMatrix.getEntry( r, 1 ) );
+ row++;
+ }
+ }
+ }
+
+ int center;
+ // center points
+ if ( totalNumberOfFactors >= 16 ) {
+ int[] predefinedPointsArr = new int[]{ 0, 0, 0, 3, 3, 6, 6, 6, 8, 9, 10, 12, 12, 13, 14, 15, 16 };
+ center = predefinedPointsArr[ totalNumberOfFactors ];
+ } else {
+ center = totalNumberOfFactors;
+ }
+ RealMatrix centerPointRepeatMatrix = new Array2DRowRealMatrix( center, totalNumberOfFactors );
+
+ // creating matrix and appending centerPointRepeatMatrix at the end
+ int rows = resultMatrix.getRowDimension() + center;
+ RealMatrix finalMatrix = new Array2DRowRealMatrix( rows, totalNumberOfFactors );
+
+ finalMatrix.setSubMatrix( resultMatrix.getData(), 0, 0 );
+ finalMatrix.setSubMatrix( centerPointRepeatMatrix.getData(), resultMatrix.getRowDimension(), 0 );
+ return finalMatrix;
+ }
+
+}
diff --git a/src/test/java/com/jdoe/algorithms/BoxBehnkenDOETest.java b/src/test/java/com/jdoe/algorithms/BoxBehnkenDOETest.java
new file mode 100644
index 0000000..c78f241
--- /dev/null
+++ b/src/test/java/com/jdoe/algorithms/BoxBehnkenDOETest.java
@@ -0,0 +1,90 @@
+package com.jdoe.algorithms;
+
+import static org.junit.Assert.*;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Unit tests for {@link BoxBehnkenDOE}.
+ */
+public class BoxBehnkenDOETest {
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testBoxBehnkenDesign_LessThanThreeFactors_ThrowsException() {
+ BoxBehnkenDOE.boxBehnkenDesign(2);
+ }
+
+ @Test
+ public void testBoxBehnkenDesign_FourFactors_DimensionsCorrect() {
+ int factors = 4;
+
+ RealMatrix design = BoxBehnkenDOE.boxBehnkenDesign(factors);
+
+ // For Box-Behnken:
+ // rows = 0.5 * k * (k - 1) * 2^2 + center
+ // = 0.5 * 4 * 3 * 4 + 4 = 24 + 4 = 28
+ assertNotNull(design);
+ assertEquals(28, design.getRowDimension());
+ assertEquals(4, design.getColumnDimension());
+ }
+
+ @Test
+ public void testBoxBehnkenDesign_FourFactors_OnlyTwoNonZeroPerRow() {
+ int factors = 4;
+ RealMatrix design = BoxBehnkenDOE.boxBehnkenDesign(factors);
+
+ int nonCenterRows = 24; // last 4 are center points
+
+ for (int r = 0; r < nonCenterRows; r++) {
+ int nonZeroCount = 0;
+ for (int c = 0; c < factors; c++) {
+ double v = design.getEntry(r, c);
+ if (v != 0.0) {
+ nonZeroCount++;
+ assertTrue(v == -1.0 || v == 1.0);
+ }
+ }
+ assertEquals(2, nonZeroCount);
+ }
+ }
+
+ @Test
+ public void testBoxBehnkenDesign_FourFactors_CenterPointsAreZero() {
+ int factors = 4;
+ RealMatrix design = BoxBehnkenDOE.boxBehnkenDesign(factors);
+
+ int rows = design.getRowDimension();
+ int center = factors;
+
+ for (int r = rows - center; r < rows; r++) {
+ for (int c = 0; c < factors; c++) {
+ assertEquals(0.0, design.getEntry(r, c), 0.0);
+ }
+ }
+ }
+
+ @Test
+ public void testBoxBehnkenDesign_LevelsRestrictedToMinusOneZeroPlusOne() {
+ RealMatrix design = BoxBehnkenDOE.boxBehnkenDesign(5);
+
+ for (int r = 0; r < design.getRowDimension(); r++) {
+ for (int c = 0; c < design.getColumnDimension(); c++) {
+ double v = design.getEntry(r, c);
+ assertTrue(v == -1.0 || v == 0.0 || v == 1.0);
+ }
+ }
+ }
+
+ @Test
+ public void testBoxBehnkenDesign_RowCountFormulaHolds() {
+ int factors = 6;
+ RealMatrix design = BoxBehnkenDOE.boxBehnkenDesign(factors);
+
+ int expectedRows =
+ (int) (0.5 * factors * (factors - 1) * 4) + factors;
+
+ assertEquals(expectedRows, design.getRowDimension());
+ }
+}