def function_2(): levels = [3, 3, 4] design = pyDOE2.fullfact(levels) NUM_MACHINES_MFG = [] for i in design[:, 0]: if i == 0: MACHINES_MFG = round(NUM_PATIENTS / 5) elif i == 1: MACHINES_MFG = round(NUM_PATIENTS / 2) else: MACHINES_MFG = round(2 * NUM_PATIENTS / 3) NUM_MACHINES_MFG.append(MACHINES_MFG) print(NUM_MACHINES_MFG) NUM_OPERATORS_MFG = [] for i in design[:, 1]: if i == 0: OPERATOR_MFG = round(NUM_PATIENTS / 5) elif i == 1: OPERATOR_MFG = round(NUM_PATIENTS / 10) else: OPERATOR_MFG = round(NUM_PATIENTS / 20) NUM_OPERATORS_MFG.append(OPERATOR_MFG) print(NUM_OPERATORS_MFG) Product_mix_MFG = [] for i in design[:, 2]: if i == 0: Product_mix = 1 elif i == 1: Product_mix = 2 elif i == 2: Product_mix = 3 else: Product_mix = 4 Product_mix_MFG.append(Product_mix) print(Product_mix_MFG) final_design = np.array( (NUM_MACHINES_MFG, NUM_OPERATORS_MFG, Product_mix_MFG), dtype=float) final_design = np.transpose(final_design) #initializing a dataframe df_consol = pd.DataFrame() run = 0 for x in final_design: run += 1 df = main_call(x[0], x[1], x[2], run) #function1() df['run'] = run df['config: product_mix '] = x[2] df_consol = df_consol.append(df) return df_consol
def factorial_design(data: dict) -> (np.ndarray, str): states, idents = extract_factors_from_analysis(data) state_counts = [len(states[i]) for i, _ in enumerate(states)] design = pyDOE2.fullfact(state_counts) # Transform the designs back to real numbers for i, row in enumerate(design): design[i] = [ states[index][int(item)] for index, item in enumerate(row) ] return design, ','.join(idents)
def full_factorial(samples: int, attributes: int, level: int = None) -> np.ndarray: if level == None: level = np.int(np.exp(np.log(samples) / attributes)) if (level**attributes) > level: print( f'Total number of samples ({level**attributes}) is smaller than input ({samples}) ' f'to have an even number of factor levels ({level}) for all parameters.' ) return pyDOE2.fullfact((np.ones([attributes]) * level).astype(int)) / level
def build_experiment(self): data = doe.fullfact([f.levels for f in self.f]) data = pd.DataFrame(data, columns=[f.name for f in self.f]) for f in self.f: inc = (f.delta * 2) / f.levels data[f.name] = data[f.name] * inc + f.centre - f.delta #********** #this is what you worked on last #********* return (data)
def _generate_design(self, size): """ Generate a full factorial DOE design. Parameters ---------- size : int The number of factors for the design. Returns ------- ndarray The design matrix as a size x levels array of indices. """ return pyDOE2.fullfact([self._levels] * size)
def get_full_factorial_designs(self): """Return full-factorial iterator of the assembly designs.""" if self.num_designs > 500: raise Exception('AssemblyDeclaration will generate %d designs.' % self.num_designs) designs = fullfact([ len(factor.levels) for factor in self._factors ]) for design in designs: yield [ self._factors[factor_index].get_level(int(level_index)) for factor_index, level_index in enumerate(design) ]
def test_model_rastrigin(verbose=False, show_plot=False): """ Test GENN on the rastrigin function (egg-crate looking function) """ if not PYDOE2_INSTALLED: return None else: # Domain lb = -1. ub = 1.5 # Training Data X_train = lb + (ub - lb) * lhs(2, samples=100, criterion='maximin', iterations=100, random_state=0) Y_train, J_train = rastrigin(X_train) # Test Data levels = 15 X_test = fullfact([levels] * 2) / (levels - 1) * (ub - lb) + lb Y_test, J_test = rastrigin(X_test) # Train model = JENN(hidden_layer_sizes=[12] * 2, activation='tanh', num_epochs=1, max_iter=1000, is_finite_difference=False, solver='adam', learning_rate='constant', random_state=0, tol=1e-6, learning_rate_init=0.01, alpha=0, gamma=1, verbose=verbose) model.fit(X_train, Y_train, J_train, is_normalize=True) if show_plot: model.goodness_fit(X_train, Y_train) model.goodness_fit(X_test, Y_test) assert rsquare(Y_train, model.predict(X_train)) > 0.95 assert rsquare(Y_test, model.predict(X_test)) > 0.95
def plot_system_params(message_count, M, l, lambdas): pairs = pde.fullfact([M + 1, l]) print(pairs) prob_list = [] for i in range(l): prob_list.append(1 / 2**i) delay_list = [] avgMsg_list = [] avg_n_th_list = [] delay_theor_list = [] lambd_out_list = [] for lmbd in lambdas: print("len = {} λ = {}".format(l, lmbd)) d, n, lambd_out = simulate_adaptive_aloha(lmbd, message_count, M, l) matrix = get_transition_matrix(lmbd, M, l, pairs, prob_list) dist = stationary_distribution(matrix) print('dist len = {}, sum = {}'.format(len(dist), np.sum(dist))) avg_n_th = get_avg_n_theor(M, l, pairs, dist) lambd_out_theor = get_lambd_out_theor(M, l, pairs, prob_list, dist) delay_theor = avg_n_th / lambd_out_theor print('d = {}, d theor = {}, N = {}, N theor = {}'.format( d, delay_theor, n, avg_n_th)) avg_n_th_list.append(avg_n_th) delay_theor_list.append(delay_theor) delay_list.append(d) avgMsg_list.append(n) lambd_out_list.append(lambd_out) plt.plot(lambdas, delay_list, label='d') plt.plot(lambdas, delay_theor_list, label='d markov chain') plt.xlabel('lambda') plt.legend() plt.savefig('one.png') #plt.show() plt.close() plt.plot(lambdas, avgMsg_list, label='N') plt.plot(lambdas, avg_n_th_list, label='N markov chain') plt.xlabel('lambda') plt.legend() plt.savefig('two.png') #plt.show() plt.close()
def lifetimeVariations(fileName, tradeStudy): varyCols = tradeStudy.varyCols varyValues = tradeStudy.varyValues numOfLevels = [len(val) for val in varyValues] runs = fullfact(numOfLevels).astype(int) paramdf = pd.DataFrame() for ii in range(len(runs.T)): paramdf[varyCols[ii]] = varyValues[ii][runs[:, ii]] dfAllTemp = pd.read_csv(fileName, index_col=0).reset_index( drop=True) # Read previously run Lifetime results df = pd.DataFrame() for jj in range(len(paramdf)): for ii in range(len(varyCols)): dfAllTemp[varyCols[ii]] = paramdf.iloc[jj, ii] df = df.append(dfAllTemp) df = df.drop_duplicates().reset_index(drop=True) # Convert all columns to floats and round to the 10th decimal, otherwise there are some numerical rounding issues. cols = [ col for col in df.columns if col not in ['SolarFluxFile', 'Density Model', '2nd Order Oblateness'] ] df[cols] = df[cols].astype(float) for col in cols: df[col] = np.round(df[col], 10) # Add results df['LT Orbits'] = np.nan df['LT Years'] = np.nan df['LT Runtime'] = np.nan df['Run ID Old'] = df['Run ID'] df = df.drop('Run ID', axis=1) df.index.name = 'Run ID' df = df.reset_index() df.to_csv(os.getcwd() + '\\Results\\' + tradeStudy.fileName) # Create a new csv to store the results return df
def get_practice_data(random=False): """ Return practice data for two-dimensional Rastrigin function :param: random -- boolean, True = random sampling, False = full-factorial sampling :return: (X, Y, J) -- np arrays of shapes (n_x, m), (n_y, m), (n_y, n_x, m) where n_x = 2 and n_y = 1 and m = 15^2 """ # Response (N-dimensional Rastrigin) f = lambda x: np.sum(x**2 - 10 * np.cos(2 * np.pi * x) + 10, axis=1) df = lambda x, j: 2 * x[:, j] + 20 * np.pi * np.sin(2 * np.pi * x[:, j]) # Domain lb = -1.0 # minimum bound (same for all dimensions) ub = 1.5 # maximum bound (same for all dimensions) # Design of experiment (full factorial) n_x = 2 # number of dimensions n_y = 1 # number of responses L = 12 # number of levels per dimension m = L**n_x # number of training examples that will be generated if random: doe = np.random.rand(m, n_x) else: levels = [L] * n_x doe = fullfact(levels) doe = (doe - 0.0) / (L - 1.0 ) # values normalized such that 0 < doe < 1 assert doe.shape == (m, n_x) # Apply bounds X = lb + (ub - lb) * doe # Evaluate response Y = f(X).reshape((m, 1)) # Evaluate partials J = np.zeros((m, n_x, n_y)) for j in range(0, n_x): J[:, j, :] = df(X, j).reshape((m, 1)) return X.T, Y.T, J.T
def full_factorial(points, weights): # perform a full factorial on the converted points and weights D = points[0] L = points[1] cu = points[2] fe = points[3] g_points = [] big_W = [] indx = fullfact([3, 3, 3, 3]) for i in indx: idx_D = int(i[0]) idx_L = int(i[1]) idx_cu = int(i[2]) idx_fe = int(i[3]) g_points.append(calculate_weight(D[idx_D], L[idx_L], cu[idx_cu], fe[idx_fe], limit=0)) big_W.append(weights[idx_D]*weights[idx_L]*weights[idx_cu]*weights[idx_fe]) # table_info.append([D[idx_D], L[idx_L], cu[idx_cu], fe[idx_fe], g_point, weight]) # df_outputs = pd.DataFrame(table_info, columns=['D', 'L', 'cu', 'fe', 'G(pts)', 'W']) return g_points, big_W
techs = cases[case] prob = DesignProblem(techs, is_test=is_test) if sample_design: # Driver configuration driver_config = dict(n_proc=N_processors, cache_dir=run_name + '/' + case, reconnect_cache=False, write_csv=write_to_csv) driver = OptimizationDriver(prob.create_problem, **driver_config) # More information about sampling: https://pythonhosted.org/pyDOE/index.html if sampling_method is 'fullfact': # Full factorial parametric sweep levels = np.array([N_levels] * prob.get_problem_dimen()) design = pyDOE.fullfact(levels) levels[levels == 1] = 2 samples = design / (levels - 1) elif sampling_method is 'lhs': # Latin Hypercube Sampling of design space samples = pyDOE.lhs(prob.get_problem_dimen(), criterion='cm', samples=N_samples) # Saves sampling values for post-process analysis if save_samples: with open(driver.options['cache_dir'] + '/' + case + '_' + sampling_method + '_samples.csv', 'w', newline='') as f: csv_writer = csv.writer(f)
def generate_full(factors): """Generate a full factorial design""" levels = [len(values) for _, values in factors.items()] design = fullfact(levels) return design
def opmsens_write_cases(basefile, header, factors, scenario): """ Main Function for Writing out Scenario Cases This is the main function that controls the writing out of the various requested scenario cases (jobs). The function first calls the opmsens_checkerr routine to check for errors and then the opmsens_clean routine to remove previously created scenario files. After which the opmsens_write_param and opmsens_write_data functions are called to create the scenario PARAM and DATA files Parameters ---------- basefile : str The basefile used to generate all the cases header : list A list of of header names factors : table A table of design factors scenario : str The type of scenario to be generated Returns ------ None """ # Check for Errors and Return if Errors Found checkerr = opmsens_check(basefile, header, factors, scenario) if checkerr: return () # # Cleanup Existing Files # opmsens_clean(basefile) # # Define Factor and Job Data Frame # df = pd.DataFrame(factors, columns=header) df = df[df != ''].dropna() jobdf = pd.DataFrame() jobdf[header[1]] = df[header[1]] for slevel in ['Low', 'Best', 'High']: if slevel in scenario: jobdf[slevel] = df[slevel] nfactor = jobdf.shape[0] nlevel = jobdf.shape[1] # # Write PARAM and DATA Files # jobs = [] jobstart = 1 joberr = False jobdata = Path(basefile) jobparam = Path(basefile).with_suffix('.param') jobque = Path(basefile).with_suffix('.que') print('Scenario: ' + scenario + ' Start') # # Low, Best and High Scenario # if 'Scenario' in scenario: jobnum = 0 for joblevel in range(1, nlevel): (joberr, jobs) = opmsens_write_param(jobstart, jobnum, jobparam, jobdata, jobs) if joberr: break joberr = opmsens_write_data(scenario, joblevel, nfactor, jobdf, jobstart, jobnum, jobdata) if joberr: break jobstart = jobstart + joblevel # # One Job per Factor # elif 'One Job per Factor' in scenario: for joblevel in range(1, nlevel): for jobnum in range(0, nfactor): (joberr, jobs) = opmsens_write_param(jobstart, jobnum, jobparam, jobdata, jobs) if joberr: break joberr = opmsens_write_data(scenario, joblevel, nfactor, jobdf, jobstart, jobnum, jobdata) if joberr: break jobstart = jobstart + nfactor # # Factorial Low and High Full # elif 'Factorial' in scenario: # # Obtain DOE Matrix and Convert to Data Frame # doedata = pd.DataFrame() if 'Factorial Low and High Full' in scenario: doedata = pyDOE2.ff2n(nfactor) + 2 if 'Factorial Low and High Plackett-Burman' in scenario: doedata = pyDOE2.pbdesign(nfactor) + 2 if 'Factorial Low, Best and High Full' in scenario: doedata = (pyDOE2.fullfact([nlevel - 1] * nfactor)) - 1 if 'Factorial Low, Best and High Box-Behnken' in scenario: doedata = pyDOE2.bbdesign(nfactor) doedf = pd.DataFrame(data=doedata).transpose() doedf = doedf.rename(columns=lambda x: 'RUN' + str(x + 1).zfill(3), inplace=False) # # Set Factor Values # for n in range(0, nfactor): doedf.iloc[n, :] = doedf.iloc[n, :].replace( [1.0, 2.0, 3.0], [df.iloc[n, 2], df.iloc[n, 3], df.iloc[n, 4]]) # # Merge Data Frames and Write Out Files # jobdf = pd.DataFrame() jobdf[header[1]] = df[header[1]] jobdf = pd.concat([jobdf, doedf], axis=1) nfactor = jobdf.shape[0] nlevel = jobdf.shape[1] jobstart = 0 for joblevel in range(1, nlevel): jobnum = joblevel (joberr, jobs) = opmsens_write_param(jobstart, jobnum, jobparam, jobdata, jobs) if joberr: break joberr = opmsens_write_data(scenario, joblevel, nfactor, jobdf, jobstart, jobnum, jobdata) if joberr: break print('Scenario: ' + scenario + ' End') if not joberr: print('WriteQueu: Start') opmsens_write_queue(jobs) print('WriteQueu: End') return ()
levels.append([64, 128, 256]) levels.append([5, 10, 20]) levels.append([1]) levels.append([0.001]) for i in range(len(labels)): try: levels[i] = eval( input(labels[i] + " (default " + str(levels[i]) + "): ")) except: pass level_sizes = [] for sub in levels: level_sizes.append(len(sub)) experiments = pd.DataFrame(pyDOE2.fullfact(level_sizes), columns=labels) i = -1 for col in experiments.columns: i = i + 1 experiments[col] = experiments[col].apply(lambda x: levels[i][int(x)]) print(experiments) ## Print the commands try: number_rep = int(input("Number of repetitions (default 1): ")) except: number_rep = 1 try: runtime = int(input("Runtime in s (default 18000 - 5 hours): "))
def create_doe(bounds, parameters_level, log_space=True): """Functions that generates a fullfact DOE mesh using bounds and levels number. Parameters ---------- Bounds: [n*2] numpy.array of floats Defines the n parameters [lower, upper] bounds parameters_level: [1*n] numpy.array of int Defines the parameters levels log_space: bool Defines if fullfact has to be in log space or when false, linear (default is True) Returns ------- doe_values: [m*n] numpy.array of float A fullfact DOE, with n the number of parameters and m the number of experiments (linked to level repartition) spacing: [1*n] numpy.array Represents the DOE's points spacing on each paramater axis in the space Example ------- define bounds and parameters' levels: >>> In [1]: bounds = numpy.array([[10, 100], [100, 1000]], float) >>> In [2]: parameters_level = numpy.array([2, 3], int) generate doe in log space: >>> In [3]: doe_values, spacing = create_doe(bounds, parameters_level, True) returns: >>> In [4]: doe_values.tolist() >>> Out[4]: [[10, 100], [100, 100], [10, 316.228], [100, 316.228], [10, 1000], [100, 1000]] >>> In [5]: spacing.tolist() >>> Out[5]: [1.0, 0.5] """ if (isinstance(bounds, numpy.ndarray) and isinstance(parameters_level, numpy.ndarray) and isinstance(log_space, bool)): if log_space and numpy.amin(bounds) < 0: raise ValueError( "to translate on log space all bounds shoold be >0, else choose log_space = False." ) if numpy.issubdtype(bounds.dtype, numpy.float64) and numpy.issubdtype( parameters_level.dtype, numpy.integer): # Check that parameters levels syntax is correct if (numpy.size(parameters_level)) != (numpy.shape(bounds)[0]): raise ValueError( "parameters_level and bounds dimensions mismatch.") # Check that parameters levels>=2 if (sum(parameters_level >= 2) + sum(parameters_level == 0) ) != numpy.size(parameters_level): raise ValueError("parameters_level should be >=2.") # If log space transpose bounds in log space if log_space: bounds = numpy.log10(bounds) # Generate DOE on levels parameters_level = parameters_level + 1 * (parameters_level == 0) doe_levels = pyDOE2.fullfact(parameters_level).astype(int) for idx in range(numpy.shape(doe_levels)[1]): if sum(doe_levels[:, idx]) == 0: doe_levels[:, idx] = 1 # Init DOE doe_values = numpy.array([], float) # Translate levels into values x=xmin+level/max(level)*(xmax-xmin) doe_values = bounds[:, 0] + doe_levels / doe_levels.max( axis=0) * (bounds[:, 1] - bounds[:, 0]) # Calculate spacing in fullfact space (linear or log) spacing = 1 / doe_levels.max(axis=0) * (bounds[:, 1] - bounds[:, 0]) # Transform calculated value from log to linear if necessary doe_values = 10**doe_values if log_space else doe_values return doe_values, spacing elif not (numpy.issubdtype(bounds.dtype, numpy.float64)): raise TypeError("elements type in in bounds should be float.") else: raise TypeError( "elements type in in parameters_level should be integer.") elif not (isinstance(bounds, numpy.ndarray)): raise TypeError("bounds shoold be numpy array.") elif not (isinstance(parameters_level, numpy.ndarray)): raise TypeError("parameters_level shoold be numpy array.") else: raise TypeError("log_space shoold be boolean.")
def generateTradeStudy(tradeStudy): fileName = os.getcwd() + '\\Results\\' + tradeStudy.fileName runHPOP = tradeStudy.runHPOP epoch = tradeStudy.epoch a = tradeStudy.a e = tradeStudy.e i = tradeStudy.i RAAN = tradeStudy.RAAN AoP = tradeStudy.AoP TA = tradeStudy.TA Cd = tradeStudy.Cd Cr = tradeStudy.Cr DragArea = tradeStudy.DragArea SunArea = tradeStudy.SunArea Mass = tradeStudy.Mass OrbPerCal = tradeStudy.OrbPerCal GaussQuad = tradeStudy.GaussQuad SigLvl = tradeStudy.SigLvl SolFlxFile = tradeStudy.SolFlxFile AtmDen = tradeStudy.AtmDen SecondOrderOblateness = tradeStudy.SecondOrderOblateness numberOfRuns = tradeStudy.numberOfRuns howToVary = tradeStudy.howToVary varyCols = tradeStudy.varyCols varyValues = tradeStudy.varyValues setSunAreaEqualToDragArea = tradeStudy.setSunAreaEqualToDragArea np.random.seed(seed=1) # Generate Additional Columns Rp = a * (1 - e) Ra = a * (1 + e) p = a * (1 - e**2) rs, vs = coe2rv(GM_earth * 1e-9, p, e, i * np.pi / 180, RAAN * np.pi / 180, AoP * np.pi / 180, TA * np.pi / 180) x = rs[0] y = rs[1] z = rs[2] Vx = vs[0] Vy = vs[1] Vz = vs[2] CdAM = Cd * DragArea / Mass CrAM = Cr * SunArea / Mass # Generate Dataframe to store all of the runs data = [ epoch, a, e, i, RAAN, AoP, TA, Rp, Ra, p, x, y, z, Vx, Vy, Vz, Cd, Cr, DragArea, SunArea, Mass, CdAM, CrAM, OrbPerCal, GaussQuad, SigLvl, SolFlxFile, AtmDen, SecondOrderOblateness ] columns = [ 'epoch', 'a', 'e', 'i', 'RAAN', 'AoP', 'TA', 'Rp', 'Ra', 'p', 'x', 'y', 'z', 'Vx', 'Vy', 'Vz', 'Cd', 'Cr', 'Drag Area', 'Sun Area', 'Mass', 'Cd*Drag Area/Mass', 'Cr*Sun Area/Mass', 'Orb Per Calc', 'Gaussian Quad', 'Flux Sigma Level', 'SolarFluxFile', 'Density Model', '2nd Order Oblateness' ] df = pd.DataFrame(data=data, index=columns).T df[df.columns[:-3]] = df[df.columns[:-3]].astype(float) # Grid Search if howToVary.lower() == 'gridsearch': # Create grid search of parameters and update the Dataframe numOfLevels = [len(val) for val in varyValues] runs = fullfact(numOfLevels).astype(int) paramdf = pd.DataFrame() for ii in range(len(runs.T)): paramdf[varyCols[ii]] = varyValues[ii][runs[:, ii]] df = pd.concat([df] * len(runs), ignore_index=True) for col in paramdf.columns: df[col] = paramdf[col] # Latin Hypercube elif howToVary.lower() == 'latinhypercube': # Generate runs lhd = lhs(len(varyCols), samples=numberOfRuns) # lhd = stats.norm(loc=0, scale=1).ppf(lhd) # Convert to a normal distribution lhd = pd.DataFrame(lhd) adjustEpoch = False if 'epoch' in varyCols: date1 = yydddToDatetime(varyValues[0][0]) date2 = yydddToDatetime(varyValues[0][1]) deltaDays = lhd[0] * (date2 - date1).days minDate = [varyValues[0][0] for i in range(numberOfRuns)] varyCols.remove('epoch') varyValues = varyValues[1:] lhd = lhd.drop(0, axis=1) adjustEpoch = True lhd.columns = varyCols # Replace string columns with categories strii = [ ii for ii in range(len(varyValues)) if isinstance(varyValues[ii][0], str) ] for ii in strii: lhd.iloc[:, ii] = pd.cut(lhd.iloc[:, ii], len(varyValues[ii]), labels=varyValues[ii]) # Replace float columns with values in range varyValues = np.array(varyValues) floatii = lhd.dtypes == float lhsMinMax = varyValues[floatii] lhsMinMax = np.concatenate(lhsMinMax, axis=0).reshape(-1, 2) lhd.loc[:, floatii] = lhd.loc[:, floatii] * ( lhsMinMax[:, 1] - lhsMinMax[:, 0]) + lhsMinMax[:, 0] indxs = [ ii for ii in range(len(varyCols)) if varyCols[ii] in ['Orb Per Calc', 'Gaussian Quad', 'Flux Sigma Level'] ] lhd.iloc[:, indxs] = lhd.iloc[:, indxs].round() # Create df df = pd.concat([df] * len(lhd), ignore_index=True) if adjustEpoch == True: df['epoch'] = [ adjustDate(yyddd, deltaDay) for yyddd, deltaDay in zip(minDate, deltaDays) ] for col in lhd.columns: df[col] = lhd[col] # Perturb elif howToVary.lower() == 'perturb': # Sample from a normal distribution rv = stats.norm() rvVals = rv.rvs((numberOfRuns, len(varyCols))) # Create perturbation df pertdf = pd.DataFrame(rvVals) * varyValues pertdf.columns = varyCols # Duplicate original df by the number of runs df = pd.concat([df] * numberOfRuns, ignore_index=True) if 'epoch' in varyCols: df['epoch'] = [ adjustDate(yyddd, deltaDay) for yyddd, deltaDay in zip(df['epoch'], pertdf['epoch']) ] varyCols.remove('epoch') varyValues = varyValues[1:] for col in varyCols: df[col] = df[col] + pertdf[col] # Update dependant values df = updateDf(df, runHPOP, varyCols, setSunAreaEqualToDragArea) # Convert all columns to floats and round to the 10th decimal, otherwise there are some numerical rounding issues. cols = [ col for col in df.columns if col not in ['SolarFluxFile', 'Density Model', '2nd Order Oblateness'] ] df[cols] = df[cols].astype(float) for col in cols: df[col] = np.round(df[col], 10) # Add results df['LT Orbits'] = np.nan df['LT Years'] = np.nan df['LT Runtime'] = np.nan if runHPOP == True: df['HPOP Years'] = np.nan df['HPOP Runtime'] = np.nan df.index.name = 'Run ID' df = df.reset_index() df.to_csv(fileName) # Create a new csv to store the results return df
class ExperimentDesigner: _matrix_designers = { 'fullfactorial2levels': pyDOE2.ff2n, 'fullfactorial3levels': lambda n: pyDOE2.fullfact([3] * n), 'placketburman': pyDOE2.pbdesign, 'boxbehnken': lambda n: pyDOE2.bbdesign(n, 1), 'ccc': lambda n: pyDOE2.ccdesign(n, (0, 3), face='ccc'), 'ccf': lambda n: pyDOE2.ccdesign(n, (0, 3), face='ccf'), 'cci': lambda n: pyDOE2.ccdesign(n, (0, 3), face='cci'), } def __init__(self, factors, design_type, responses, skip_screening=True, at_edges='distort', relative_step=.25, gsd_reduction='auto', model_selection='brute', n_folds='loo', manual_formula=None, shrinkage=1.0, q2_limit=0.5, gsd_span_ratio=0.5): try: assert at_edges in ('distort', 'shrink'),\ 'unknown action at_edges: {0}'.format(at_edges) assert relative_step is None or 0 < relative_step < 1,\ 'relative_step must be float between 0 and 1 not {}'.format(relative_step) assert model_selection in ('brute', 'greedy', 'manual'), \ 'model_selection must be "brute", "greedy", "manual".' assert n_folds == 'loo' or (isinstance(n_folds, int) and n_folds > 0), \ 'n_folds must be "loo" or positive integer' assert 0.9 <= shrinkage <= 1, 'shrinkage must be float between 0.9 and 1.0, not {}'.format( shrinkage) assert 0 <= q2_limit <= 1, 'q2_limit must be float between 0 and 1, not {}'.format( q2_limit) if model_selection == 'manual': assert isinstance(manual_formula, str), \ 'If model_selection is "manual" formula must be provided.' except AssertionError as e: raise ValueError(str(e)) self.factors = OrderedDict() factor_types = list() for factor_name, f_spec in factors.items(): factor = factor_from_spec(f_spec) if isinstance(factor, CategoricalFactor) and skip_screening: raise DesignerError( 'Can\'t perform optimization with categorical ' 'variables without prior screening.') self.factors[factor_name] = factor logging.debug('Sets factor {}: {}'.format(factor_name, factor)) factor_types.append(f_spec.get('type', 'continuous')) self.skip_screening = skip_screening self.step_length = relative_step self.design_type = design_type self.responses = responses self.response_values = None self.gsd_reduction = gsd_reduction self.model_selection = model_selection self.n_folds = n_folds self.shrinkage = shrinkage self.q2_limit = q2_limit self._formula = manual_formula self._edge_action = at_edges self._allowed_phases = ['optimization', 'screening'] self._phase = 'optimization' if self.skip_screening else 'screening' self._n_screening_evaluations = 0 self._factor_types = factor_types self._gsd_span_ratio = gsd_span_ratio self._stored_transform = lambda x: x self._best_experiment = { 'optimal_x': pd.Series([]), 'optimal_y': None, 'weighted_y': None } n = len(self.factors) try: self._matrix_designers[self.design_type.lower()] except KeyError: raise UnsupportedDesign(self.design_type) if len(self.responses) > 1: self._desirabilites = { name: make_desirability_function(factor) for name, factor in self.responses.items() } else: self._desirabilites = None def new_design(self): """ :return: Experimental design-sheet. :rtype: pandas.DataFrame """ if self._phase == 'screening': return self._new_screening_design(reduction=self.gsd_reduction) else: return self._new_optimization_design() def write_factor_csv(self, out_file): factors = list() idx = pd.Index(['fixed_value', 'current_low', 'current_high']) for name, factor in self.factors.items(): current_min = None current_high = None fixed_value = None if issubclass(type(factor), NumericFactor): current_min = factor.current_low current_high = factor.current_high elif isinstance(factor, CategoricalFactor): fixed_value = factor.fixed_value else: raise NotImplementedError data = [fixed_value, current_min, current_high] factors.append(pd.Series(data, index=idx, name=name)) factors_df = pd.DataFrame(factors) logging.info('Saving factor settings to {}'.format(out_file)) factors_df.to_csv(out_file) def update_factors_from_csv(self, csv_file): factors_df = pd.DataFrame.from_csv(csv_file) logging.info('Reading factor settings from {}'.format(csv_file)) for name, factor in self.factors.items(): logging.info('Updating factor {}'.format(name)) if issubclass(type(factor), NumericFactor): current_low = factors_df.loc[name]['current_low'] current_high = factors_df.loc[name]['current_high'] logging.info('Factor: {}. Setting current_low to {}'.format( name, current_low)) logging.info('Factor: {}. Setting current_high to {}'.format( name, current_high)) factor.current_low = current_low factor.current_high = current_high elif isinstance(factor, CategoricalFactor): if pd.isnull(factors_df.loc[name]['fixed_value']): fixed_value = None logging.info( 'Factor: {}. Had no fixed_value.'.format(name)) else: fixed_value = factors_df.loc[name]['fixed_value'] logging.info( 'Factor: {}. Setting fixed_value to {}.'.format( name, fixed_value)) factor.fixed_value = fixed_value def get_optimal_settings(self, response): """ Calculate optimal factor settings given response. Returns calculated optimum. If the current phase is 'screening': returns the factor settings of the best run and updates the current factor settings. If the current phase is 'optimization': returns the factor settings of the predicted optimum, but doesn't update current factor settings in case a validation step is to be run first :param pandas.DataFrame response: Response sheet. :returns: Calculated optimum. :rtype: OptimizationResult """ self._response_values = response.copy() response = response.copy() # Perform any transformations or weigh together multiple responses: treated_response, criterion = self.treat_response(response) if self._phase == 'screening': # Find the best screening result and update factors accordingly self._screening_response = treated_response self._screening_criterion = criterion return self._evaluate_screening(treated_response, criterion, self._gsd_span_ratio) else: # Predict optimal parameter settings, but don't update factors return self._predict_optimum_settings(treated_response, criterion) def _update_best_experiment(self, result): update = False if self._best_experiment['optimal_x'].empty: update = True elif result['criterion'] == 'maximize': if result['weighted_response'] > self._best_experiment[ 'weighted_y']: update = True elif result['criterion'] == 'minimize': if result['weighted_response'] < self._best_experiment[ 'weighted_y']: update = True if update: self._best_experiment['optimal_x'] = result['factor_settings'] self._best_experiment['optimal_y'] = result['response'] self._best_experiment['weighted_y'] = result['weighted_response'] return update def get_best_experiment(self, experimental_sheet, response_sheet, use_index=1): """ Accepts an experimental design and the corresponding response values. Finds the best experiment and updates self._best_experiment. Returns the best experiment, to be used in fnc update_factors_from_optimum """ assert isinstance(experimental_sheet, pd.core.frame.DataFrame), \ 'The input experimental sheet must be a pandas DataFrame' assert isinstance(response_sheet, pd.core.frame.DataFrame), \ 'The input response sheet must be a pandas DataFrame' assert sorted(experimental_sheet.columns) == sorted(self.factors), \ 'The factors of the experimental sheet must match those in the \ pipeline. You input:\n{}\nThey should be:\n{}' .format( list(experimental_sheet.columns), list(self.factors.keys())) assert sorted(response_sheet.columns) == sorted(self.responses), \ 'The responses of the response sheet must match those in the \ pipeline. You input:\n{}\nThey should be:\n{}' .format( list(response_sheet.columns), list(self.responses.keys())) response = response_sheet.copy() treated_response, criterion = self.treat_response( response, perform_transform=False) treated_response = treated_response.iloc[:, 0] if criterion == 'maximize': optimum_i = treated_response.argsort().iloc[-use_index] elif criterion == 'minimize': optimum_i = treated_response.argsort().iloc[use_index - 1] else: raise NotImplementedError optimum_settings = experimental_sheet.iloc[optimum_i] results = OrderedDict() optimal_weighted_response = np.array(treated_response.iloc[optimum_i]) optimal_response = response_sheet.iloc[optimum_i] results['factor_settings'] = optimum_settings results['weighted_response'] = optimal_weighted_response results['response'] = optimal_response results['criterion'] = criterion results['new_best'] = False results['old_best'] = self._best_experiment has_multiple_responses = response_sheet.shape[1] > 1 logging.debug('The best response was found in experiment:\n{}'.format( optimum_settings.name)) logging.debug('The response values were:\n{}'.format( response_sheet.iloc[optimum_i])) if has_multiple_responses: logging.debug('The weighed response was:\n{}'.format( treated_response.iloc[optimum_i])) logging.debug('Will return optimum settings:\n{}'.format( results['factor_settings'])) logging.debug('And best response:\n{}'.format(results['response'])) if self._update_best_experiment(results): results['new_best'] = True return results def update_factors_from_optimum(self, optimal_experiment, tol=0.25, recovery=False): """ Updates the factor settings based on how far the current settings are from those supplied in optimal_experiment['factor_settings']. :param OrderedDict optimal_experiment: Output from get_best_experiment :param float tol: Accepted relative distance to design space edge. :returns: Calculated optimum. :rtype: OptimizationResult """ are_numeric = np.array(self._factor_types) != 'categorical' numeric_names = np.array(list(self.factors.keys()))[are_numeric] numeric_factors = np.array(list(self.factors.values()))[are_numeric] optimal_x = optimal_experiment['factor_settings'] optimal_y = optimal_experiment['weighted_response'] criterion = optimal_experiment['criterion'] # Get only numeric factors if recovery: optimal_x = optimal_x.iloc[optimal_x.index.isin(numeric_names)] centers = np.array([f.center for f in numeric_factors]) spans = np.array([f.span for f in numeric_factors]) ratios = (optimal_x - centers) / spans if not recovery: logging.debug( 'The distance of the factor optimas from the factor centers, ' 'expressed as the ratio of the step length:\n{}'.format( ratios)) if (abs(ratios) < tol).all(): converged = True if not recovery: logging.info('Convergence reached.') else: converged = False if not recovery: logging.info('Convergence not reached. Moves design.') for ratio, name, factor in zip(ratios, numeric_names, numeric_factors): if abs(ratio) < tol: if not recovery: logging.debug( ('Factor {} not updated - within tolerance ' 'limits.').format(name)) continue if not recovery: self._update_numeric_factor(factor, name, ratio) converged, reached_limits = self._check_convergence(centers, converged, criterion, optimal_y, numeric_factors, recovery=recovery) optimization_results = pd.Series(index=self._design_sheet.columns, dtype=object) for name, factor in self.factors.items(): if isinstance(factor, CategoricalFactor): optimization_results[name] = factor.fixed_value else: optimization_results[name] = optimal_x[name] results = OptimizationResult(optimization_results, converged, tol, reached_limits, empirically_found=True) return results def _predict_optimum_settings(self, response, criterion): """ Calculate a model from the response and find the optimum. :returns: Calculated optimum. :rtype: OptimizationResult """ logging.info('Predicting optimum') are_numeric = np.array(self._factor_types) != 'categorical' numeric_names = np.array(list(self.factors.keys()))[are_numeric] optimal_x, model, prediction = predict_optimum( self._design_sheet.loc[:, are_numeric], response.iloc[:, 0].values, numeric_names, criterion=criterion, n_folds=self.n_folds, model_selection=self.model_selection, manual_formula=self._formula, q2_limit=self.q2_limit) optimization_results = pd.Series(index=self._design_sheet.columns, dtype=object) if not optimal_x.empty: # If Q2 of model was above the limit and if an optimum was found for name, factor in self.factors.items(): if isinstance(factor, CategoricalFactor): optimization_results[name] = factor.fixed_value elif isinstance(factor, OrdinalFactor): optimization_results[name] = int(np.round(optimal_x[name])) else: optimization_results[name] = optimal_x[name] result = OptimizationResult(optimization_results, converged=False, tol=0, reached_limits=False, empirically_found=False) return result def treat_response(self, response, perform_transform=True): """ Perform any specified transformations on the response. If several responses are defined, combine them into one. The geometric mean of Derringer and Suich's desirability functions will be used for optimization, see: Derringer, G., and Suich, R., (1980), "Simultaneous Optimization of Several Response Variables," Journal of Quality Technology, 12, 4, 214-219. Returns a single response variable and the associated maximize/minimize criterion. """ has_multiple_responses = response.shape[1] > 1 for name, spec in self.responses.items(): transform = spec.get('transform', None) response_values = response[name] if perform_transform: if transform == 'log': logging.debug('Log-transforming response {}'.format(name)) response_values = np.log(response_values) self._stored_transform = np.log elif transform == 'box-cox': response_values, lambda_ = scipy.stats.boxcox( response_values) logging.debug('Box-cox transforming response {} ' '(lambda={:.4f})'.format(name, lambda_)) self._stored_transform = _make_stored_boxcox(lambda_) else: self._stored_transform = lambda x: x if has_multiple_responses: desirability_function = self._desirabilites[name] response_values = [ desirability_function(value) for value in response_values ] response[name] = response_values if has_multiple_responses: response = np.power(response.product(axis=1), (1 / response.shape[1])) response = response.to_frame('combined_response') criterion = 'maximize' else: criterion = list(self.responses.values())[0]['criterion'] return response, criterion def reevaluate_screening(self): if self._screening_response is None: raise DesignerError('screening must be run before re-evaluation') return self._evaluate_screening(self._screening_response, self._screening_criterion, self._gsd_span_ratio, self._n_screening_evaluations + 1) def _validate_new_factor_limits(self, factor, factor_name, low_limit, high_limit): # If the proposed step change takes us below or above min and max: logging.debug('Factor {}: Proposed new factor low is {}.'.format( factor_name, low_limit)) logging.debug('Factor {}: Proposed new factor high is {}.'.format( factor_name, high_limit)) adjusted_settings = False if low_limit < factor.min: nudge = abs(low_limit - factor.min) logging.debug( 'Factor {}: Minimum allowed setting ({}) would be exceeded by ' 'the proposed new factor low.'.format(factor_name, factor.min)) low_limit += nudge high_limit += nudge adjusted_settings = True elif high_limit > factor.max: nudge = abs(high_limit - factor.max) logging.debug( 'Factor {}: Maximum allowed setting ({}) would be exceeded by ' 'the proposed new factor high.'.format(factor_name, factor.max)) low_limit -= nudge high_limit -= nudge adjusted_settings = True if adjusted_settings: logging.debug('Factor {}: Adjusted the proposed new factor ' 'settings by {}.'.format(factor_name, nudge)) logging.debug('Factor {}: New factor low is {}.'.format( factor_name, low_limit)) logging.debug('Factor {}: New factor high is {}.'.format( factor_name, high_limit)) return (low_limit, high_limit) def _evaluate_screening(self, response, criterion, span_ratio, use_index=1): """ :param float span_ratio: The ratio of the span between gsd points that will be used in the following optimization design. """ self._n_screening_evaluations += 1 logging.info('Evaluating screening results.') response_series = response.iloc[:, 0] factor_items = sorted(self.factors.items()) if criterion == 'maximize': optimum_i = response_series.argsort().iloc[-use_index] elif criterion == 'minimize': optimum_i = response_series.argsort().iloc[use_index - 1] else: raise NotImplementedError optimum_design_row = self._design_matrix[optimum_i] optimum_settings = OrderedDict() # Update all factors according to current results. For each factor, # the current_high and current_low will be set to factors level above # and below the point in the screening design with the best response. for factor_level, (name, factor) in zip(optimum_design_row, factor_items): if isinstance(factor, CategoricalFactor): factor_levels = np.array(factor.values) factor.fixed_value = factor_levels[factor_level] else: factor_levels = sorted(self._design_sheet[name].unique()) min_ = factor_levels[max([0, factor_level - 1])] max_ = factor_levels[min( [factor_level + 1, len(factor_levels) - 1])] span = max_ - min_ # Shrink the span a bit logging.debug('Factor {} span: {}'.format(name, span)) logging.debug('Factor {}: adjusting span with ' 'gsd_span_ratio {}'.format(name, span_ratio)) span = span * span_ratio if isinstance(factor, OrdinalFactor) and span < 2.0: # Make sure ordinal factors' spans don't shrink to the # point where there's no spread in the exp. design logging.debug('Factor {}: span ({}) too small, adjusting ' 'to minimal span for ordinal factor.'.format( name, span)) span = 2.0 logging.debug('Factor {} span: {}'.format(name, span)) # center around best point best_point = factor_levels[factor_level] new_low = best_point - span / 2 new_high = best_point + span / 2 if isinstance(factor, OrdinalFactor): new_low = int(np.round(new_low)) new_high = int(np.round(new_high)) # nudge new high and low so we don't exceed the limits new_low, new_high = self._validate_new_factor_limits( factor, name, new_low, new_high) # update factors factor.current_low = new_low factor.current_high = new_high optimum_settings[name] = factor_levels[factor_level] logging.info('New settings for factor {}:\n{}'.format( name, factor)) results = OptimizationResult(pd.Series(optimum_settings), converged=False, tol=0, reached_limits=False, empirically_found=True) logging.info('Best screening result was exp no {}'.format(optimum_i)) logging.info('The corresponding response was:\n{}'.format( self._response_values.iloc[optimum_i])) if len(self._response_values.columns) > 1: logging.info('The combined response was:\n{}'.format( response.iloc[optimum_i])) logging.info('The factor settings were:\n{}'.format( results.predicted_optimum)) # update current best experiment self.get_best_experiment( self._design_sheet, self._response_values if len(self._response_values.columns) > 1 else response) self._phase = 'optimization' return results def set_phase(self, phase): assert phase in self._allowed_phases, 'phase must be one of {}'.format( self._allowed_phases) self._phase = phase def _update_numeric_factor(self, factor, name, ratio): logging.info('Factor {}: Updating settings.'.format(name)) logging.info('Factor {}: Current settings: {}'.format(name, factor)) step_length = self.step_length if self.step_length is not None \ else abs(ratio) step = factor.span * step_length * np.sign(ratio) logging.debug( 'Factor {}: Step by which settings are adjusted is {}.'.format( name, step)) logging.debug( 'Factor {}: Current span between high and low is {}.'.format( name, factor.span)) logging.debug('Factor {}: Will shrink the span by {}.'.format( name, self.shrinkage)) new_span = factor.span * self.shrinkage logging.debug('Factor {}: New span is {}.'.format(name, new_span)) if isinstance(factor, QuantitativeFactor): current_low_new = factor.center + step - new_span / 2 current_high_new = factor.center + step + new_span / 2 elif isinstance(factor, OrdinalFactor): current_low_new = np.round(factor.center + step - new_span / 2) current_high_new = np.round(factor.center + step + new_span / 2) else: raise NotImplementedError # If the proposed step change takes us below or above min and max: new_low, new_high = self._validate_new_factor_limits( factor, name, current_low_new, current_high_new) factor.current_low = new_low factor.current_high = new_high logging.info('Factor {}: New settings: {}'.format(name, factor)) logging.info('Factor {}: Done updating.'.format(name)) def _new_screening_design(self, reduction='auto'): factor_items = sorted(self.factors.items()) levels = list() names = list() dtypes = list() for name, factor in factor_items: names.append(name) if isinstance(factor, CategoricalFactor): levels.append(factor.values) dtypes.append(object) continue num_levels = factor.screening_levels spacing = getattr(factor, 'screening_spacing', 'linear') min_ = factor.min max_ = factor.max if not np.isfinite([min_, max_]).all(): raise ValueError( 'Can\'t perform screening with unbounded factors') space = np.linspace if spacing == 'linear' else np.logspace values = space(min_, max_, num_levels) if isinstance(factor, OrdinalFactor): values = sorted(np.unique(np.round(values))) dtypes.append(int) else: dtypes.append(float) levels.append(values) design_matrix = pyDOE2.gsd( [len(values) for values in levels], reduction if reduction is not 'auto' else len(levels)) factor_matrix = list() for i, (values, dtype) in enumerate(zip(levels, dtypes)): values = np.array(values)[design_matrix[:, i]] series = pd.Series(values, dtype=dtype) factor_matrix.append(series) self._design_matrix = design_matrix self._design_sheet = pd.concat(factor_matrix, axis=1, keys=names) return self._design_sheet def _new_optimization_design(self): matrix_designer = self._matrix_designers[self.design_type.lower()] numeric_factors = [(name, factor) for name, factor in self.factors.items() if isinstance(factor, NumericFactor)] numeric_factor_names = [name for name, factor in numeric_factors] design_matrix = matrix_designer(len(numeric_factors)) mins = np.array([f.min for _, f in numeric_factors]) maxes = np.array([f.max for _, f in numeric_factors]) span = np.array([f.span for _, f in numeric_factors]) centers = np.array([f.center for _, f in numeric_factors]) factor_matrix = design_matrix * (span / 2.0) + centers # Check if current settings are outside allowed design space. # Also, for factors that are specified as ordinal, adjust their values # in the design matrix to be rounded floats for i, (factor_name, factor) in enumerate(numeric_factors): if isinstance(factor, OrdinalFactor): factor_matrix[:, i] = np.round(factor_matrix[:, i]) logging.debug('Current setting {}: {}'.format(factor_name, factor)) if (factor_matrix < mins).any() or (factor_matrix > maxes).any(): logging.warning(('Out of design space factors. Adjusts factors' 'by {}.'.format(self._edge_action + 'ing'))) if self._edge_action == 'distort': # Simply cap out-of-boundary values at mins and maxes. capped_mins = np.maximum(factor_matrix, mins) capped_mins_and_maxes = np.minimum(capped_mins, maxes) factor_matrix = capped_mins_and_maxes elif self._edge_action == 'shrink': raise NotImplementedError factors = list() for name, factor in self.factors.items(): if isinstance(factor, CategoricalFactor): values = np.repeat(factor.fixed_value, len(design_matrix)) factors.append(pd.Series(values)) else: i = numeric_factor_names.index(name) dtype = int if isinstance(factor, OrdinalFactor) else float factors.append(pd.Series(factor_matrix[:, i].astype(dtype))) self._design_sheet = pd.concat(factors, axis=1, keys=self.factors.keys()) return self._design_sheet def _check_convergence(self, centers, converged, criterion, prediction, numeric_factors, recovery=False): # It's possible that the optimum is predicted to be at the edge of the allowed # min or max factor setting. This will produce a high 'ratio' and the algorithm # is not considered to have converged (above). However, in this situation we # can't move the space any further and we should stop iterating. new_centers = np.array([f.center for f in numeric_factors]) if (centers == new_centers).all(): if not recovery: logging.info( 'The design has not moved since last iteration. Converged.' ) converged = True reached_limits = True if len(self.responses) > 1 and prediction < 1: reached_limits = False elif len(self.responses) == 1: r_spec = list(self.responses.values())[0] low_limit = self._stored_transform(r_spec.get('low_limit', 1)) high_limit = self._stored_transform(r_spec.get( 'high_limit', 1)) if criterion == 'maximize' and 'low_limit' in r_spec: reached_limits = prediction >= low_limit elif criterion == 'minimize' and 'high_limit' in r_spec: reached_limits = prediction <= high_limit elif criterion == 'target' and 'low_limit' in r_spec and 'high_limit' in r_spec: reached_limits = low_limit <= prediction <= high_limit else: reached_limits = False return converged, reached_limits
def simulation_design(): #full factorial design for 7 factors levels = [2, 2, 3, 3, 3, 3, 3] design = pyDOE2.fullfact(levels) #Factor 1 corresponds to Yield Curve Component having two levels #Yield_Curve_Type 1 shows stressed system #Yield_Curve_Type 2 shows system with slow growth rate Yield_Curve = [] for i in design[:,0]: if i == 0: Yield_Curve_Type = 1 else: Yield_Curve_Type = 2 Yield_Curve.append(Yield_Curve_Type) #Factor 2 corresponds to Patient component having two levels #Level 1 shows mix of patients with 80% Average response, 10 % Good and 10% Bad response #Level 2 shows mix of patients with 50% Average response, 25 % Good and 25% Bad response Patient_Mix = [] for i in design[:,1]: if i == 0: Patient_Mix_Policy = 1 else: Patient_Mix_Policy = 2 Patient_Mix.append(Patient_Mix_Policy) #Factor 3 corresponds to Quality control policy related to tests with 3 levels #Level 1 shows the policy where every test is conducted in high fidelity #Level 2 shows the policy where every test is conducted in low fidelity and if test fails, a second high fidelity test is conducted #Level 3 Shows the policy where we test in high fidelity with some testing probability QM_Policy = [] for i in design[:,2]: if i == 0: Quality_Policy = 1 elif i == 1: Quality_Policy = 2 else: Quality_Policy = 3 QM_Policy.append(Quality_Policy) #Factor 4 corresponds to the harvesting operators count NUM_OPERATORS_HRV = [] for i in design[:,1]: if i == 0: OPERATOR_HRV = round(NUM_PATIENTS/15) elif i == 1: OPERATOR_HRV = round(NUM_PATIENTS/25) else: OPERATOR_HRV = round(NUM_PATIENTS/35) NUM_OPERATORS_HRV.append(OPERATOR_HRV) #Factor 5 corresponds to the available harvesting machines count NUM_MACHINES_HRV = [] for i in design[:,0]: if i == 0: MACHINES_HRV = round(NUM_PATIENTS/10) elif i == 1: MACHINES_HRV = round(NUM_PATIENTS/20) else: MACHINES_HRV = round(2* NUM_PATIENTS/30) NUM_MACHINES_HRV.append(MACHINES_HRV) #Factor 6 corresponds to the Mfg operators count NUM_OPERATORS_MFG = [] for i in design[:,4]: if i == 0: OPERATOR_MFG = round(NUM_PATIENTS/5) elif i == 1: OPERATOR_MFG = round(NUM_PATIENTS/10) else: OPERATOR_MFG = round(NUM_PATIENTS/20) NUM_OPERATORS_MFG.append(OPERATOR_MFG) #Factor 7 corresponds to the available Mfg machines(bio-reactors) count NUM_MACHINES_MFG = [] for i in design[:,3]: if i == 0: MACHINES_MFG = round(NUM_PATIENTS/2) elif i == 1: MACHINES_MFG = round(NUM_PATIENTS/5) else: MACHINES_MFG = round(NUM_PATIENTS) NUM_MACHINES_MFG.append(MACHINES_MFG) final_design = np.array((Yield_Curve, Patient_Mix, QM_Policy, NUM_OPERATORS_HRV, NUM_MACHINES_HRV, NUM_OPERATORS_MFG, NUM_MACHINES_MFG), dtype=float) final_design = np.transpose(final_design) return final_design
def generate_song_plan(nloops=10, ntracks=4, plantype="random", seed=0): """ This function drafts a layout for the song. Tracks 0--3 are: "bass", "drum", "fx", "melody". The layout for the example shown on https://www.audiolabs-erlangen.de/resources/MIR/2016-ISMIR-EMLoop is: Track 1 (bass): X XX Track 2 (drum): XXX XX Track 3 (f.x.): [empty] Track 4 (mel.): XXXX To make this, create a plan in an np.array as so: plan = np.array([[0, 0, 1, 0, 1, 1], [1, 1, 1, 0, 1, 1] [0, 0, 0, 0, 0, 0] [0, 1, 1, 1, 1, 0]]) The plan for the stimuli in Lopez-Serrano's paper is: plan = np.array([[0, 0, 1, 1, 0, 1, 0, 1], [1, 1, 1, 1, 0, 1, 1, 1], [0, 0, 0, 1, 0, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0]]) This is generated by generate_song_plan(plantype="lopez_serrano") The factorial plan is generated by generate_song_plan(plantype="factorial"): np.array([[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1], [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]]) And the factorial_random plan is generate_song_plan(plantype="factorial_random",seed=0): np.array([[0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1], [1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0], [0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1], [0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1]]) """ assert plantype in [ "random", "lopez_serrano", "factorial", "factorial_random" ] np.random.seed(seed) if plantype == "random": plan = np.random.randint(2, size=(ntracks, nloops)) # If any columns all 0, convert to all 1: empty_cols = np.where(np.sum(plan, 0) == 0) for i in empty_cols[0]: plan[:, i] = 1 # If any rows all 0, convert to all 1: empty_rows = np.where(np.sum(plan, 1) == 0) for i in empty_rows[0]: plan[i, :] = 1 elif plantype == "lopez_serrano": plan = np.array([[0, 0, 1, 1, 0, 1, 0, 1], [1, 1, 1, 1, 0, 1, 1, 1], [0, 0, 0, 1, 0, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0]]) elif plantype == "factorial": plan = pyDOE.fullfact([2] * ntracks).transpose() plan = plan.astype(int) plan = plan[:, 1:] elif plantype == "factorial_random": # Use seed = 0 to get plan used in the paper! plan = pyDOE.fullfact([2] * ntracks).transpose() plan = plan.astype(int) plan = plan[:, 1:] np.random.shuffle(plan.transpose()) return plan