/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.components.doe.common; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; /** * Utility class containing algorithms for filling up a table with design points. * * @author Sascha Zur */ public final class DOEAlgorithms { /** * Constant for the maximum sampling count. */ public static final double MAXMIMAL_RUNS = Math.pow(10, 5); private DOEAlgorithms() { } /** * Fills a new table with design points using the full factorial method. This algorithm is * recursive. * * @param varCount number of variables in the table * @param numLevels level count for the precision, must be >= 2 * @return populated array with the dimensions numLevel^varCount by varCount */ public static Double[][] populateTableFullFactorial(int varCount, int numLevels) { if (Math.pow(numLevels, varCount) < MAXMIMAL_RUNS) { int noRuns = (int) Math.pow(numLevels, varCount); Double[][] table = new Double[noRuns][varCount]; AtomicInteger run = new AtomicInteger(0); populateTableFullFactorialRec(varCount, varCount - 1, numLevels, new double[varCount], run, table); return table; } else { return new Double[0][0]; } } private static void populateTableFullFactorialRec(int varCount, int varIndex, int numLevels, double[] values, AtomicInteger run, Double[][] table) { if (varIndex < 0) { for (int i = 0; i < varCount; i++) { table[run.get()][i] = values[i]; } run.incrementAndGet(); values = new double[varCount]; } else { final int lb = -1; final int ub = 1; double step = (ub - lb) / ((double) numLevels - 1); for (int i = 0; i < numLevels; i++) { values[varIndex] = lb + i * step; populateTableFullFactorialRec(varCount, varIndex - 1, numLevels, values, run, table); } } } /** * Fills a new table with design points using the latin hypercuve method. * * @param varCount number of variables in the table * @param desiredRuns number of runs to be calculated * @param seed the seed for random number generator * @return populated array with the dimensions desiredRuns by varCount */ public static Double[][] populateTableLatinHypercube(int varCount, int desiredRuns, int seed) { if (desiredRuns < MAXMIMAL_RUNS) { int numRuns = desiredRuns; Random generator = new Random(seed); double binSize = 2.0 / numRuns; int[] iindex = new int[numRuns]; Double[][] table = new Double[desiredRuns][varCount]; for (int i = 0; i < varCount; i++) { for (int j = 0; j < numRuns; j++) { iindex[j] = j; } for (int j = 0; j < numRuns; j++) { int k = (int) (generator.nextDouble() * numRuns); int itemp = iindex[k]; iindex[k] = iindex[j]; iindex[j] = itemp; } for (int j = 0; j < numRuns; j++) { final double minusOne = -1.0; double val = minusOne + iindex[j] * binSize + generator.nextDouble() * binSize; table[j][i] = val; } } return table; } else { return new Double[0][0]; } } /** * * Fills a new table with design points using the monte carlo method. * * @param varCount number of variables in the table * @param runs number of runs to be calculated * @param seed the seed for random number generator * @return populated array with the dimensions runs by varCount */ public static Double[][] populateTableMonteCarlo(int varCount, int runs, int seed) { if (runs < MAXMIMAL_RUNS) { Double[][] result = new Double[runs][varCount]; Random generator = new Random(seed); for (int i = 0; i < runs; i++) { for (int j = 0; j < varCount; j++) { result[i][j] = generator.nextDouble() * 2 - 1; } } return result; } else { return new Double[0][0]; } } /** * * Transforms the given value from an interval [-1; 1] to the interval [low, up]. * * @param low lower bound of the target interval * @param up upper bound of the target interval * @param valueOf relative value in the source interval * @return value in the interval [low, up] */ public static Double convertValue(Double low, Double up, Double valueOf) { final int minusOne = -1; if (valueOf == minusOne) { return low; } else if (valueOf == 1) { return up; } else { return (((up - low) / 2.0) * valueOf + ((low + up) / 2.0)); } } }