experimental_design.experimental_designs

experimental_designs is a module that acts as a collection point for tools to create and manage design of experiments (DOE), or statistical design of experiments. Currently, it has functions to produce fully factorial designs, with or without a center point, and in the whole plot /split plot methods.

  1#-----------------------------------------------------------------------------
  2# Name:        experimental_designs
  3# Purpose:    To make design of experiments easy (DOE).
  4# Authors:     [email protected]
  5# Created:     4/20/2021
  6# License:     MIT License
  7#-----------------------------------------------------------------------------
  8"""experimental_designs is a module that acts as a collection point for tools to create and manage
  9design of experiments (DOE), or statistical design of experiments. Currently, it has
 10functions to produce fully factorial designs, with or without a center point, and in
 11the whole plot /split plot methods.
 12"""
 13#-----------------------------------------------------------------------------
 14# Standard Imports
 15import sys
 16import os
 17import random
 18import itertools
 19import yaml
 20import pandas as pd
 21
 22#-----------------------------------------------------------------------------
 23# Module Constants
 24RANDOM_SEED = 42
 25#-----------------------------------------------------------------------------
 26# Module Functions
 27def pretty_print_np(array):
 28    """prints a numpy array the way I think looks best"""
 29    outstring = ""
 30    for index, element in enumerate(array):
 31        if index == len(array) - 1:
 32            outstring += str(element) + ""
 33        else:
 34            outstring += str(element) + ", "
 35    return outstring
 36
 37
 38def create_factor_table(dataframe):
 39    """Given a dataframe prints off the unique values for the column names,
 40    make sure the configuration number is index."""
 41    out_dictionary = {}
 42    for column in dataframe.columns:
 43        out_dictionary.update({column: dataframe[column].unique()})
 44    return out_dictionary
 45
 46
 47def print_factor_table(dataframe):
 48    """Given a dataframe prints off the unique values for the column names,
 49    make sure the configuration number is index."""
 50    for column in dataframe.columns:
 51        print("{0} : {1}".format(column, pretty_print_np(dataframe[column].unique())))
 52
 53
 54def jupyter_print_factor_table(dataframe, column_names=["Factors", "Values"]):
 55    """Pretty prints a factor table in a jupyter notebook"""
 56    from IPython.display import display, Markdown
 57
 58    output_string = r"<table>" + "\n"
 59    heading = r"<TR><TH>{0}</TH><TH>{1}</TH></TR>".format(*column_names)
 60    output_string += heading + "\n"
 61    for column in dataframe.columns:
 62        output_string += r"<TR><TD>{0}</TD><TD>{1}</TD></TR>".format(column, pretty_print_np(
 63            sorted(dataframe[column].unique()))) + "\n"
 64    ending = r"</table>"
 65    output_string += ending
 66    display(Markdown(output_string))
 67
 68
 69def get_variable_factors(dataframe):
 70    """Given a dataframe, returns a list of factors that vary."""
 71    factors = [column for column in dataframe.columns if len(dataframe[column].unique()) > 1]
 72    return factors
 73
 74def condition_in_row (row,condition):
 75    """Truth function for filter.
 76    Determines if condition is in row, returning True if it is not and False otherwise. """
 77    for condition_key,condition_value in condition.items():
 78        if row[condition_key]!=condition_value:
 79            return True
 80    return False
 81
 82def filter_rows(design,exclusions):
 83    """Input a design of the form [{Row_1},...{RowN}] and an exclusions of the form [{exclusion_1}..
 84    {exclusion_N}] and returns a filter version of design."""
 85    out = design
 86    for excluded in exclusions:
 87        out = list(filter(lambda x: condition_in_row(x,excluded),out))
 88    return out
 89
 90def fully_factorial(design_dictionary, randomized=True, run_values="values",random_seed = RANDOM_SEED):
 91    """Given a design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
 92    'factor_name_N':{factor_level_N:factor_level_value_N}}
 93    returns a test_conditions run sheet. Optional parameters are randomized (True or False) and run_values
 94    ("keys" or "values"). The randomization process sets a random_seed = RANDOM_SEED to be reproducible. """
 95    factors = list(design_dictionary.keys())
 96    factor_values = []
 97    for factor in factors:
 98        factor_values_row = list(design_dictionary[factor].__getattribute__(run_values)())
 99        factor_values.append(factor_values_row)
100    test_conditions = [dict(zip(factors, state)) for state in itertools.product(*factor_values)]
101    if randomized:
102        random.seed(random_seed)
103        random.shuffle(test_conditions)
104    return test_conditions
105
106
107def fully_factorial_default(design_dictionary, default_state, default_modulo=2,
108                            randomized=True, run_values="values",random_seed =42):
109    """Given a design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
110    'factor_name_N':{factor_level_N:factor_level_value_N}} and a default state in the same format,
111    returns a test_conditions run sheet. Optional parameters are default_modulo (how often do you want the state,
112    randomized (True or False) and run_values.
113    ("keys" or "values"). """
114
115    test_conditions = fully_factorial(design_dictionary,
116                                      randomized=randomized,
117                                      run_values=run_values,
118                                      random_seed=random_seed)
119    factors = list(design_dictionary.keys())
120    default_condition = {}
121    for factor in factors:
122        default_condition[factor] = list(default_state[factor].__getattribute__(run_values)())[0]
123    defaulted_test_conditions = []
124    for test_index, test_condition in enumerate(test_conditions):
125        if test_index % default_modulo == 0:
126            defaulted_test_conditions.append(default_condition)
127            defaulted_test_conditions.append(test_condition)
128        else:
129            defaulted_test_conditions.append(test_condition)
130    return defaulted_test_conditions
131
132
133def fully_factorial_split_plot(whole_plot_design_dictionary, split_plot_design_dictionary,
134                               randomized=True, run_values="values",random_seed_base = RANDOM_SEED):
135    """Given a whole_plot_design_dictionary and split_plot_design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
136    'factor_name_N':{factor_level_N:factor_level_value_N}} ,
137    returns a test_conditions run sheet. Optional parameters are
138    randomized (True or False) and run_values.
139    ("keys" or "values"). """
140    test_conditions = []
141    whole_plot_test_conditions = fully_factorial(whole_plot_design_dictionary,
142                                                 randomized=randomized,
143                                                 run_values=run_values)
144    for whole_plot_index,whole_plot in enumerate(whole_plot_test_conditions):
145        split_plot_test_condtions = fully_factorial(split_plot_design_dictionary,
146                                                    randomized=randomized,
147                                                    run_values=run_values,
148                                                    random_seed=random_seed_base+whole_plot_index)
149        for split_plot in split_plot_test_condtions:
150            new_row = dict(whole_plot)
151            new_row.update(split_plot)
152            test_conditions.append(new_row)
153    return test_conditions
154
155
156def fully_factorial_split_plot_default(whole_plot_design_dictionary, split_plot_design_dictionary,
157                                       whole_plot_default_dictionary, whole_plot_default_modulo=2,
158                                       randomized=True, run_values="values"):
159    """Given a whole_plot_design_dictionary and split_plot_design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
160    'factor_name_N':{factor_level_N:factor_level_value_N}} and a default state in the same format,
161    returns a test_conditions run sheet. It assumes that the split plot design remains the same
162    Optional parameters are default_modulo (how often do you want the state in whole plot iterations,
163    randomized (True or False) and run_values.
164    ("keys" or "values"). """
165    # Build the fully factorial test and default conditions
166    test_conditions = fully_factorial_split_plot(whole_plot_design_dictionary, split_plot_design_dictionary,
167                                                 randomized=randomized, run_values=run_values)
168
169    default_conditions = fully_factorial_split_plot(whole_plot_default_dictionary, split_plot_design_dictionary,
170                                                    randomized=randomized, run_values=run_values)
171
172    number_split_plot_states = 1
173    for factor in split_plot_design_dictionary.keys():
174        number_split_plot_states = number_split_plot_states * len(split_plot_design_dictionary[factor])
175    state_modulo = int(whole_plot_default_modulo * number_split_plot_states)
176
177    defaulted_test_conditions = []
178    for test_index, test_condition in enumerate(test_conditions):
179        if test_index % state_modulo == 0:
180            for default_state in default_conditions:
181                defaulted_test_conditions.append(default_state)
182            defaulted_test_conditions.append(test_condition)
183        else:
184            defaulted_test_conditions.append(test_condition)
185    return defaulted_test_conditions
186
187def fully_factorial_split_plot_interleaved(whole_plot_design_dictionary, split_plot_design_dictionary,
188                                       whole_plot_design_dictionary_interleaved,
189                                       split_plot_design_dictionary_interleaved,
190                                       interleave_modulo=2,
191                                       randomized=True, run_values="values"):
192    """Given whole_plot_design_dictionary, split_plot_design_dictionary,
193    whole_plot_design_dictionary_interleaved, split_plot_design_dictionary_interleaved in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
194    'factor_name_N':{factor_level_N:factor_level_value_N}},
195    returns a test_conditions run sheet. It assumes that the split plot design remains the same
196    Optional parameters are interleave_modulo (how often do you want the state in whole plot iterations,
197    randomized (True or False) and run_values.
198    ("keys" or "values"). """
199    # Build the fully factorial test and default conditions
200    test_conditions = fully_factorial_split_plot(whole_plot_design_dictionary, split_plot_design_dictionary,
201                                                 randomized=randomized, run_values=run_values)
202
203    # does this lead to a different randomization each time? -NO
204
205
206    number_split_plot_states = 1
207    for factor in split_plot_design_dictionary.keys():
208        number_split_plot_states = number_split_plot_states * len(split_plot_design_dictionary[factor])
209    state_modulo = int(interleave_modulo * number_split_plot_states)
210
211    interleaved_test_conditions = []
212    for test_index, test_condition in enumerate(test_conditions):
213        if test_index % state_modulo == 0:
214            interleave_conditions = fully_factorial_split_plot(whole_plot_design_dictionary_interleaved,
215                                                               split_plot_design_dictionary_interleaved,
216                                                               randomized=randomized,
217                                                               run_values=run_values,
218                                                               random_seed_base=test_index)
219            for interleave_state in interleave_conditions:
220                interleaved_test_conditions.append(interleave_state)
221            interleaved_test_conditions.append(test_condition)
222        else:
223            interleaved_test_conditions.append(test_condition)
224    return interleaved_test_conditions
225
226#-----------------------------------------------------------------------------
227# Module Scripts
228def test_fully_factorial():
229    """Tests the fully_factorial design"""
230    test_design = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
231    print("*"*80)
232    print("Testing the fully_factorial function")
233    print(f"The test design is {yaml.dump(test_design)}")
234    test_condtions  = pd.DataFrame(fully_factorial(test_design, randomized=False))
235    test_condtions_keys = pd.DataFrame(fully_factorial(test_design, randomized=False, run_values="keys"))
236    random_test_condtions = pd.DataFrame(fully_factorial(test_design, randomized=True))
237    print("The test_conditions or design when not randomized is:")
238    print(test_condtions)
239    print("*"*80)
240    print("The test_conditions or design in state numbers when not randomized is:")
241    print(test_condtions_keys)
242    print("*" * 80)
243    print("The test_conditions or design randomized is:")
244    print(random_test_condtions)
245    print("*" * 80)
246
247def test_fully_factorial_default():
248    """Tests the fully_factorial_default design"""
249    test_design = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
250    default = {'one': {-1: 'default'}, 'two': {-1: 'MEDIUM'}, 'three': {-1: 'OFF'}}
251    print("*"*80)
252    print("Testing the fully_factorial_default function")
253    print(f"The test design is {yaml.dump(test_design)}")
254    print(f"The default is {yaml.dump(default)}")
255    test_condtions  = pd.DataFrame(fully_factorial_default(test_design, default , randomized=False))
256    test_condtions_keys = pd.DataFrame(fully_factorial_default(test_design, default, randomized=False, run_values="keys"))
257    random_test_condtions = pd.DataFrame(fully_factorial_default(test_design, default, randomized=True))
258    print("The test_conditions or design when not randomized is:")
259    print(test_condtions)
260    print("*"*80)
261    print("The test_conditions or design in state numbers when not randomized is:")
262    print(test_condtions_keys)
263    print("*" * 80)
264    print("The test_conditions or design randomized is:")
265    print(random_test_condtions)
266    print("*" * 80)
267
268def test_fully_factorial_split_plot():
269    """Tests the fully_factorial_split_plot_default design"""
270    test_design = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
271    wp = {'whole_plot_1': {-1: "in my shoe", 0: 'In my Head'}, 'whole_plot_2': {0: 'WP OFF', 1: "WP ON"}}
272    print("*"*80)
273    print("Testing the test_fully_factorial_split_plot_default function")
274    print(f"The test design is {yaml.dump(test_design)}")
275    print(f"The whole plot design is {yaml.dump(wp)}")
276
277    test_condtions  = pd.DataFrame(fully_factorial_split_plot(whole_plot_design_dictionary=wp,
278                                                                      split_plot_design_dictionary = test_design,
279                                                                      randomized=False))
280    test_condtions_keys = pd.DataFrame(fully_factorial_split_plot(whole_plot_design_dictionary=wp,
281                                                                      split_plot_design_dictionary = test_design,
282                                                                      randomized=False,
283                                                                      run_values="keys"))
284    random_test_condtions = pd.DataFrame(fully_factorial_split_plot(whole_plot_design_dictionary=wp,
285                                                                      split_plot_design_dictionary = test_design,
286                                                                      randomized=True,
287                                                                      run_values="values"))
288    print("The test_conditions or design when not randomized is:")
289    print(test_condtions)
290    print("*"*80)
291    print("The test_conditions or design in state numbers when not randomized is:")
292    print(test_condtions_keys)
293    print("*" * 80)
294    print("The test_conditions or design randomized is:")
295    print(random_test_condtions)
296    print("*" * 80)
297
298def test_fully_factorial_split_plot_default():
299    """Tests the fully_factorial_split_plot_default design"""
300
301    test_design = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
302    wp = {'whole_plot_1': {-1: "in my shoe", 0: 'In my Head'}, 'whole_plot_2': {0: 'WP OFF', 1: "WP ON"}}
303    wp_default = {'whole_plot_1': {3: "default"}, 'whole_plot_2': {0: 'wp_2 default'}}
304    print("*"*80)
305    print("Testing the test_fully_factorial_split_plot_default function")
306    print(f"The test design is {yaml.dump(test_design)}")
307    print(f"The whole plot design is {yaml.dump(wp)}")
308    print(f"The whole plot default is {yaml.dump(wp_default)}")
309
310    test_condtions  = pd.DataFrame(fully_factorial_split_plot_default(whole_plot_design_dictionary=wp,
311                                                                      split_plot_design_dictionary = test_design,
312                                                                      whole_plot_default_dictionary=wp_default ,
313                                                                      randomized=False))
314    test_condtions_keys = pd.DataFrame(fully_factorial_split_plot_default(whole_plot_design_dictionary=wp,
315                                                                      split_plot_design_dictionary = test_design,
316                                                                      whole_plot_default_dictionary=wp_default ,
317                                                                      randomized=False,
318                                                                      run_values="keys"))
319    random_test_condtions = pd.DataFrame(fully_factorial_split_plot_default(whole_plot_design_dictionary=wp,
320                                                                      split_plot_design_dictionary = test_design,
321                                                                      whole_plot_default_dictionary=wp_default ,
322                                                                      randomized=True,
323                                                                      run_values="values"))
324    print("The test_conditions or design when not randomized is:")
325    print(test_condtions)
326    print("*"*80)
327    print("The test_conditions or design in state numbers when not randomized is:")
328    print(test_condtions_keys)
329    print("*" * 80)
330    print("The test_conditions or design randomized is:")
331    print(random_test_condtions)
332    print("*" * 80)
333
334def test_fully_factorial_split_plot_interleave():
335    """Tests the fully_factorial_split_plot_default design"""
336    sp = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
337    wp = {'whole_plot_1': {-1: "in my shoe", 0: 'In my Head'}, 'whole_plot_2': {0: 'WP OFF', 1: "WP ON"}}
338    wp_2 = {'whole_plot_1': {3: "default"}, 'whole_plot_2': {0: 'wp_2 default'}}
339    sp_2 = {'Atten': {0: 0, 1: 20, 2: 40}, 'two': {0: 'NEW', 1: 'OLD'}, 'three': {0: 'OFF'}}
340    print("*"*80)
341    print("Testing the test_fully_factorial_split_plot_default function")
342    print(f"The whole plot design is {yaml.dump(wp)}")
343    print(f"The split plot design is {yaml.dump(sp)}")
344
345    print(f"The second whole plot default is {yaml.dump(wp_2)}")
346    print(f"The second split plot default is {yaml.dump(sp_2)}")
347
348    test_condtions  = pd.DataFrame(fully_factorial_split_plot_interleaved(whole_plot_design_dictionary=wp,
349                                                                      split_plot_design_dictionary = sp,
350                                                                      whole_plot_design_dictionary_interleaved= wp_2 ,
351                                                                      split_plot_design_dictionary_interleaved = sp_2,
352                                                                      randomized=False))
353    test_condtions_keys = pd.DataFrame(fully_factorial_split_plot_interleaved(whole_plot_design_dictionary=wp,
354                                                                      split_plot_design_dictionary = sp,
355                                                                      whole_plot_design_dictionary_interleaved= wp_2 ,
356                                                                      split_plot_design_dictionary_interleaved = sp_2,
357                                                                      randomized=False,
358                                                                      run_values='keys'))
359    random_test_condtions = pd.DataFrame(fully_factorial_split_plot_interleaved(whole_plot_design_dictionary=wp,
360                                                                      split_plot_design_dictionary = sp,
361                                                                      whole_plot_design_dictionary_interleaved= wp_2 ,
362                                                                      split_plot_design_dictionary_interleaved = sp_2,
363                                                                      randomized=True,
364                                                                      run_values='values'))
365    print("The test_conditions or design when not randomized is:")
366    print(test_condtions)
367    print("*"*80)
368    print("The test_conditions or design in state numbers when not randomized is:")
369    print(test_condtions_keys)
370    print("*" * 80)
371    print("The test_conditions or design randomized is:")
372    print(random_test_condtions)
373    print("*" * 80)
374
375#-----------------------------------------------------------------------------
376# Module Runner
377if __name__ == '__main__':
378    test_fully_factorial()
379    test_fully_factorial_default()
380    test_fully_factorial_split_plot()
381    test_fully_factorial_split_plot_interleave()
382 
RANDOM_SEED = 42
def pretty_print_np(array):
28def pretty_print_np(array):
29    """prints a numpy array the way I think looks best"""
30    outstring = ""
31    for index, element in enumerate(array):
32        if index == len(array) - 1:
33            outstring += str(element) + ""
34        else:
35            outstring += str(element) + ", "
36    return outstring

prints a numpy array the way I think looks best

def create_factor_table(dataframe):
39def create_factor_table(dataframe):
40    """Given a dataframe prints off the unique values for the column names,
41    make sure the configuration number is index."""
42    out_dictionary = {}
43    for column in dataframe.columns:
44        out_dictionary.update({column: dataframe[column].unique()})
45    return out_dictionary

Given a dataframe prints off the unique values for the column names, make sure the configuration number is index.

def jupyter_print_factor_table(dataframe, column_names=['Factors', 'Values']):
55def jupyter_print_factor_table(dataframe, column_names=["Factors", "Values"]):
56    """Pretty prints a factor table in a jupyter notebook"""
57    from IPython.display import display, Markdown
58
59    output_string = r"<table>" + "\n"
60    heading = r"<TR><TH>{0}</TH><TH>{1}</TH></TR>".format(*column_names)
61    output_string += heading + "\n"
62    for column in dataframe.columns:
63        output_string += r"<TR><TD>{0}</TD><TD>{1}</TD></TR>".format(column, pretty_print_np(
64            sorted(dataframe[column].unique()))) + "\n"
65    ending = r"</table>"
66    output_string += ending
67    display(Markdown(output_string))

Pretty prints a factor table in a jupyter notebook

def get_variable_factors(dataframe):
70def get_variable_factors(dataframe):
71    """Given a dataframe, returns a list of factors that vary."""
72    factors = [column for column in dataframe.columns if len(dataframe[column].unique()) > 1]
73    return factors

Given a dataframe, returns a list of factors that vary.

def condition_in_row(row, condition):
75def condition_in_row (row,condition):
76    """Truth function for filter.
77    Determines if condition is in row, returning True if it is not and False otherwise. """
78    for condition_key,condition_value in condition.items():
79        if row[condition_key]!=condition_value:
80            return True
81    return False

Truth function for filter. Determines if condition is in row, returning True if it is not and False otherwise.

def filter_rows(design, exclusions):
83def filter_rows(design,exclusions):
84    """Input a design of the form [{Row_1},...{RowN}] and an exclusions of the form [{exclusion_1}..
85    {exclusion_N}] and returns a filter version of design."""
86    out = design
87    for excluded in exclusions:
88        out = list(filter(lambda x: condition_in_row(x,excluded),out))
89    return out

Input a design of the form [{Row_1},...{RowN}] and an exclusions of the form [{exclusion_1}.. {exclusion_N}] and returns a filter version of design.

def fully_factorial( design_dictionary, randomized=True, run_values='values', random_seed=42):
 91def fully_factorial(design_dictionary, randomized=True, run_values="values",random_seed = RANDOM_SEED):
 92    """Given a design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
 93    'factor_name_N':{factor_level_N:factor_level_value_N}}
 94    returns a test_conditions run sheet. Optional parameters are randomized (True or False) and run_values
 95    ("keys" or "values"). The randomization process sets a random_seed = RANDOM_SEED to be reproducible. """
 96    factors = list(design_dictionary.keys())
 97    factor_values = []
 98    for factor in factors:
 99        factor_values_row = list(design_dictionary[factor].__getattribute__(run_values)())
100        factor_values.append(factor_values_row)
101    test_conditions = [dict(zip(factors, state)) for state in itertools.product(*factor_values)]
102    if randomized:
103        random.seed(random_seed)
104        random.shuffle(test_conditions)
105    return test_conditions

Given a design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ... 'factor_name_N':{factor_level_N:factor_level_value_N}} returns a test_conditions run sheet. Optional parameters are randomized (True or False) and run_values ("keys" or "values"). The randomization process sets a random_seed = RANDOM_SEED to be reproducible.

def fully_factorial_default( design_dictionary, default_state, default_modulo=2, randomized=True, run_values='values', random_seed=42):
108def fully_factorial_default(design_dictionary, default_state, default_modulo=2,
109                            randomized=True, run_values="values",random_seed =42):
110    """Given a design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
111    'factor_name_N':{factor_level_N:factor_level_value_N}} and a default state in the same format,
112    returns a test_conditions run sheet. Optional parameters are default_modulo (how often do you want the state,
113    randomized (True or False) and run_values.
114    ("keys" or "values"). """
115
116    test_conditions = fully_factorial(design_dictionary,
117                                      randomized=randomized,
118                                      run_values=run_values,
119                                      random_seed=random_seed)
120    factors = list(design_dictionary.keys())
121    default_condition = {}
122    for factor in factors:
123        default_condition[factor] = list(default_state[factor].__getattribute__(run_values)())[0]
124    defaulted_test_conditions = []
125    for test_index, test_condition in enumerate(test_conditions):
126        if test_index % default_modulo == 0:
127            defaulted_test_conditions.append(default_condition)
128            defaulted_test_conditions.append(test_condition)
129        else:
130            defaulted_test_conditions.append(test_condition)
131    return defaulted_test_conditions

Given a design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ... 'factor_name_N':{factor_level_N:factor_level_value_N}} and a default state in the same format, returns a test_conditions run sheet. Optional parameters are default_modulo (how often do you want the state, randomized (True or False) and run_values. ("keys" or "values").

def fully_factorial_split_plot( whole_plot_design_dictionary, split_plot_design_dictionary, randomized=True, run_values='values', random_seed_base=42):
134def fully_factorial_split_plot(whole_plot_design_dictionary, split_plot_design_dictionary,
135                               randomized=True, run_values="values",random_seed_base = RANDOM_SEED):
136    """Given a whole_plot_design_dictionary and split_plot_design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
137    'factor_name_N':{factor_level_N:factor_level_value_N}} ,
138    returns a test_conditions run sheet. Optional parameters are
139    randomized (True or False) and run_values.
140    ("keys" or "values"). """
141    test_conditions = []
142    whole_plot_test_conditions = fully_factorial(whole_plot_design_dictionary,
143                                                 randomized=randomized,
144                                                 run_values=run_values)
145    for whole_plot_index,whole_plot in enumerate(whole_plot_test_conditions):
146        split_plot_test_condtions = fully_factorial(split_plot_design_dictionary,
147                                                    randomized=randomized,
148                                                    run_values=run_values,
149                                                    random_seed=random_seed_base+whole_plot_index)
150        for split_plot in split_plot_test_condtions:
151            new_row = dict(whole_plot)
152            new_row.update(split_plot)
153            test_conditions.append(new_row)
154    return test_conditions

Given a whole_plot_design_dictionary and split_plot_design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ... 'factor_name_N':{factor_level_N:factor_level_value_N}} , returns a test_conditions run sheet. Optional parameters are randomized (True or False) and run_values. ("keys" or "values").

def fully_factorial_split_plot_default( whole_plot_design_dictionary, split_plot_design_dictionary, whole_plot_default_dictionary, whole_plot_default_modulo=2, randomized=True, run_values='values'):
157def fully_factorial_split_plot_default(whole_plot_design_dictionary, split_plot_design_dictionary,
158                                       whole_plot_default_dictionary, whole_plot_default_modulo=2,
159                                       randomized=True, run_values="values"):
160    """Given a whole_plot_design_dictionary and split_plot_design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
161    'factor_name_N':{factor_level_N:factor_level_value_N}} and a default state in the same format,
162    returns a test_conditions run sheet. It assumes that the split plot design remains the same
163    Optional parameters are default_modulo (how often do you want the state in whole plot iterations,
164    randomized (True or False) and run_values.
165    ("keys" or "values"). """
166    # Build the fully factorial test and default conditions
167    test_conditions = fully_factorial_split_plot(whole_plot_design_dictionary, split_plot_design_dictionary,
168                                                 randomized=randomized, run_values=run_values)
169
170    default_conditions = fully_factorial_split_plot(whole_plot_default_dictionary, split_plot_design_dictionary,
171                                                    randomized=randomized, run_values=run_values)
172
173    number_split_plot_states = 1
174    for factor in split_plot_design_dictionary.keys():
175        number_split_plot_states = number_split_plot_states * len(split_plot_design_dictionary[factor])
176    state_modulo = int(whole_plot_default_modulo * number_split_plot_states)
177
178    defaulted_test_conditions = []
179    for test_index, test_condition in enumerate(test_conditions):
180        if test_index % state_modulo == 0:
181            for default_state in default_conditions:
182                defaulted_test_conditions.append(default_state)
183            defaulted_test_conditions.append(test_condition)
184        else:
185            defaulted_test_conditions.append(test_condition)
186    return defaulted_test_conditions

Given a whole_plot_design_dictionary and split_plot_design_dictionary in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ... 'factor_name_N':{factor_level_N:factor_level_value_N}} and a default state in the same format, returns a test_conditions run sheet. It assumes that the split plot design remains the same Optional parameters are default_modulo (how often do you want the state in whole plot iterations, randomized (True or False) and run_values. ("keys" or "values").

def fully_factorial_split_plot_interleaved( whole_plot_design_dictionary, split_plot_design_dictionary, whole_plot_design_dictionary_interleaved, split_plot_design_dictionary_interleaved, interleave_modulo=2, randomized=True, run_values='values'):
188def fully_factorial_split_plot_interleaved(whole_plot_design_dictionary, split_plot_design_dictionary,
189                                       whole_plot_design_dictionary_interleaved,
190                                       split_plot_design_dictionary_interleaved,
191                                       interleave_modulo=2,
192                                       randomized=True, run_values="values"):
193    """Given whole_plot_design_dictionary, split_plot_design_dictionary,
194    whole_plot_design_dictionary_interleaved, split_plot_design_dictionary_interleaved in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ...
195    'factor_name_N':{factor_level_N:factor_level_value_N}},
196    returns a test_conditions run sheet. It assumes that the split plot design remains the same
197    Optional parameters are interleave_modulo (how often do you want the state in whole plot iterations,
198    randomized (True or False) and run_values.
199    ("keys" or "values"). """
200    # Build the fully factorial test and default conditions
201    test_conditions = fully_factorial_split_plot(whole_plot_design_dictionary, split_plot_design_dictionary,
202                                                 randomized=randomized, run_values=run_values)
203
204    # does this lead to a different randomization each time? -NO
205
206
207    number_split_plot_states = 1
208    for factor in split_plot_design_dictionary.keys():
209        number_split_plot_states = number_split_plot_states * len(split_plot_design_dictionary[factor])
210    state_modulo = int(interleave_modulo * number_split_plot_states)
211
212    interleaved_test_conditions = []
213    for test_index, test_condition in enumerate(test_conditions):
214        if test_index % state_modulo == 0:
215            interleave_conditions = fully_factorial_split_plot(whole_plot_design_dictionary_interleaved,
216                                                               split_plot_design_dictionary_interleaved,
217                                                               randomized=randomized,
218                                                               run_values=run_values,
219                                                               random_seed_base=test_index)
220            for interleave_state in interleave_conditions:
221                interleaved_test_conditions.append(interleave_state)
222            interleaved_test_conditions.append(test_condition)
223        else:
224            interleaved_test_conditions.append(test_condition)
225    return interleaved_test_conditions

Given whole_plot_design_dictionary, split_plot_design_dictionary, whole_plot_design_dictionary_interleaved, split_plot_design_dictionary_interleaved in the form {'factor_name_1':{factor_level_1:factor_level_value_1}, ... 'factor_name_N':{factor_level_N:factor_level_value_N}}, returns a test_conditions run sheet. It assumes that the split plot design remains the same Optional parameters are interleave_modulo (how often do you want the state in whole plot iterations, randomized (True or False) and run_values. ("keys" or "values").

def test_fully_factorial():
229def test_fully_factorial():
230    """Tests the fully_factorial design"""
231    test_design = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
232    print("*"*80)
233    print("Testing the fully_factorial function")
234    print(f"The test design is {yaml.dump(test_design)}")
235    test_condtions  = pd.DataFrame(fully_factorial(test_design, randomized=False))
236    test_condtions_keys = pd.DataFrame(fully_factorial(test_design, randomized=False, run_values="keys"))
237    random_test_condtions = pd.DataFrame(fully_factorial(test_design, randomized=True))
238    print("The test_conditions or design when not randomized is:")
239    print(test_condtions)
240    print("*"*80)
241    print("The test_conditions or design in state numbers when not randomized is:")
242    print(test_condtions_keys)
243    print("*" * 80)
244    print("The test_conditions or design randomized is:")
245    print(random_test_condtions)
246    print("*" * 80)

Tests the fully_factorial design

def test_fully_factorial_default():
248def test_fully_factorial_default():
249    """Tests the fully_factorial_default design"""
250    test_design = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
251    default = {'one': {-1: 'default'}, 'two': {-1: 'MEDIUM'}, 'three': {-1: 'OFF'}}
252    print("*"*80)
253    print("Testing the fully_factorial_default function")
254    print(f"The test design is {yaml.dump(test_design)}")
255    print(f"The default is {yaml.dump(default)}")
256    test_condtions  = pd.DataFrame(fully_factorial_default(test_design, default , randomized=False))
257    test_condtions_keys = pd.DataFrame(fully_factorial_default(test_design, default, randomized=False, run_values="keys"))
258    random_test_condtions = pd.DataFrame(fully_factorial_default(test_design, default, randomized=True))
259    print("The test_conditions or design when not randomized is:")
260    print(test_condtions)
261    print("*"*80)
262    print("The test_conditions or design in state numbers when not randomized is:")
263    print(test_condtions_keys)
264    print("*" * 80)
265    print("The test_conditions or design randomized is:")
266    print(random_test_condtions)
267    print("*" * 80)

Tests the fully_factorial_default design

def test_fully_factorial_split_plot():
269def test_fully_factorial_split_plot():
270    """Tests the fully_factorial_split_plot_default design"""
271    test_design = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
272    wp = {'whole_plot_1': {-1: "in my shoe", 0: 'In my Head'}, 'whole_plot_2': {0: 'WP OFF', 1: "WP ON"}}
273    print("*"*80)
274    print("Testing the test_fully_factorial_split_plot_default function")
275    print(f"The test design is {yaml.dump(test_design)}")
276    print(f"The whole plot design is {yaml.dump(wp)}")
277
278    test_condtions  = pd.DataFrame(fully_factorial_split_plot(whole_plot_design_dictionary=wp,
279                                                                      split_plot_design_dictionary = test_design,
280                                                                      randomized=False))
281    test_condtions_keys = pd.DataFrame(fully_factorial_split_plot(whole_plot_design_dictionary=wp,
282                                                                      split_plot_design_dictionary = test_design,
283                                                                      randomized=False,
284                                                                      run_values="keys"))
285    random_test_condtions = pd.DataFrame(fully_factorial_split_plot(whole_plot_design_dictionary=wp,
286                                                                      split_plot_design_dictionary = test_design,
287                                                                      randomized=True,
288                                                                      run_values="values"))
289    print("The test_conditions or design when not randomized is:")
290    print(test_condtions)
291    print("*"*80)
292    print("The test_conditions or design in state numbers when not randomized is:")
293    print(test_condtions_keys)
294    print("*" * 80)
295    print("The test_conditions or design randomized is:")
296    print(random_test_condtions)
297    print("*" * 80)

Tests the fully_factorial_split_plot_default design

def test_fully_factorial_split_plot_default():
299def test_fully_factorial_split_plot_default():
300    """Tests the fully_factorial_split_plot_default design"""
301
302    test_design = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
303    wp = {'whole_plot_1': {-1: "in my shoe", 0: 'In my Head'}, 'whole_plot_2': {0: 'WP OFF', 1: "WP ON"}}
304    wp_default = {'whole_plot_1': {3: "default"}, 'whole_plot_2': {0: 'wp_2 default'}}
305    print("*"*80)
306    print("Testing the test_fully_factorial_split_plot_default function")
307    print(f"The test design is {yaml.dump(test_design)}")
308    print(f"The whole plot design is {yaml.dump(wp)}")
309    print(f"The whole plot default is {yaml.dump(wp_default)}")
310
311    test_condtions  = pd.DataFrame(fully_factorial_split_plot_default(whole_plot_design_dictionary=wp,
312                                                                      split_plot_design_dictionary = test_design,
313                                                                      whole_plot_default_dictionary=wp_default ,
314                                                                      randomized=False))
315    test_condtions_keys = pd.DataFrame(fully_factorial_split_plot_default(whole_plot_design_dictionary=wp,
316                                                                      split_plot_design_dictionary = test_design,
317                                                                      whole_plot_default_dictionary=wp_default ,
318                                                                      randomized=False,
319                                                                      run_values="keys"))
320    random_test_condtions = pd.DataFrame(fully_factorial_split_plot_default(whole_plot_design_dictionary=wp,
321                                                                      split_plot_design_dictionary = test_design,
322                                                                      whole_plot_default_dictionary=wp_default ,
323                                                                      randomized=True,
324                                                                      run_values="values"))
325    print("The test_conditions or design when not randomized is:")
326    print(test_condtions)
327    print("*"*80)
328    print("The test_conditions or design in state numbers when not randomized is:")
329    print(test_condtions_keys)
330    print("*" * 80)
331    print("The test_conditions or design randomized is:")
332    print(random_test_condtions)
333    print("*" * 80)

Tests the fully_factorial_split_plot_default design

def test_fully_factorial_split_plot_interleave():
335def test_fully_factorial_split_plot_interleave():
336    """Tests the fully_factorial_split_plot_default design"""
337    sp = {'one': {0: 'LOW', 1: 'HIGH', 2: 'zest'}, 'two': {0: 'FAST', 1: 'SLOW'}, 'three': {0: 'ON'}}
338    wp = {'whole_plot_1': {-1: "in my shoe", 0: 'In my Head'}, 'whole_plot_2': {0: 'WP OFF', 1: "WP ON"}}
339    wp_2 = {'whole_plot_1': {3: "default"}, 'whole_plot_2': {0: 'wp_2 default'}}
340    sp_2 = {'Atten': {0: 0, 1: 20, 2: 40}, 'two': {0: 'NEW', 1: 'OLD'}, 'three': {0: 'OFF'}}
341    print("*"*80)
342    print("Testing the test_fully_factorial_split_plot_default function")
343    print(f"The whole plot design is {yaml.dump(wp)}")
344    print(f"The split plot design is {yaml.dump(sp)}")
345
346    print(f"The second whole plot default is {yaml.dump(wp_2)}")
347    print(f"The second split plot default is {yaml.dump(sp_2)}")
348
349    test_condtions  = pd.DataFrame(fully_factorial_split_plot_interleaved(whole_plot_design_dictionary=wp,
350                                                                      split_plot_design_dictionary = sp,
351                                                                      whole_plot_design_dictionary_interleaved= wp_2 ,
352                                                                      split_plot_design_dictionary_interleaved = sp_2,
353                                                                      randomized=False))
354    test_condtions_keys = pd.DataFrame(fully_factorial_split_plot_interleaved(whole_plot_design_dictionary=wp,
355                                                                      split_plot_design_dictionary = sp,
356                                                                      whole_plot_design_dictionary_interleaved= wp_2 ,
357                                                                      split_plot_design_dictionary_interleaved = sp_2,
358                                                                      randomized=False,
359                                                                      run_values='keys'))
360    random_test_condtions = pd.DataFrame(fully_factorial_split_plot_interleaved(whole_plot_design_dictionary=wp,
361                                                                      split_plot_design_dictionary = sp,
362                                                                      whole_plot_design_dictionary_interleaved= wp_2 ,
363                                                                      split_plot_design_dictionary_interleaved = sp_2,
364                                                                      randomized=True,
365                                                                      run_values='values'))
366    print("The test_conditions or design when not randomized is:")
367    print(test_condtions)
368    print("*"*80)
369    print("The test_conditions or design in state numbers when not randomized is:")
370    print(test_condtions_keys)
371    print("*" * 80)
372    print("The test_conditions or design randomized is:")
373    print(random_test_condtions)
374    print("*" * 80)

Tests the fully_factorial_split_plot_default design