def test_modeling_plus(self): exponents = [(0, 1, 1), (0, 1, 2), (1, 4, 0), (1, 3, 0), (1, 4, 1), (1, 3, 1), (1, 4, 2), (1, 3, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 3, 0), (3, 4, 0), (2, 3, 1), (3, 4, 1), (4, 5, 0), (2, 3, 2), (3, 4, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (5, 4, 0), (5, 4, 1), (4, 3, 0), (4, 3, 1), (3, 2, 0), (3, 2, 1), (3, 2, 2), (5, 3, 0), (7, 4, 0), (2, 1, 0), (2, 1, 1), (2, 1, 2), (9, 4, 0), (7, 3, 0), (5, 2, 0), (5, 2, 1), (5, 2, 2), (8, 3, 0), (11, 4, 0), (3, 1, 0), (3, 1, 1)] for expo1, expo2 in zip(exponents, exponents[1:]): termX = CompoundTerm.create(*expo1) termY = CompoundTerm.create(*expo2) term1 = MultiParameterTerm((0, termX)) term1.coefficient = 10 term2 = MultiParameterTerm((1, termY)) term2.coefficient = 20 function = MultiParameterFunction(term1, term2) function.constant_coefficient = 200 points = [np.array([2, 4, 8, 16, 32, 2, 4, 8, 16, 32, 2, 4, 8, 16, 32, 2, 4, 8, 16, 32, 2, 4, 8, 16, 32]), np.array([2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32])] values = function.evaluate(np.array(points)) measurements = [Measurement(Coordinate(p), None, None, v) for p, v in zip(zip(*points), values)] modeler = MultiParameterModeler() models = modeler.model([measurements]) self.assertEqual(1, len(models)) self.assertApproxFunction(function, models[0].hypothesis.function)
def test_modeling_4p(self): exponents = [(0, 1, 1), (0, 1, 2), (1, 4, 0), (1, 3, 0), (1, 4, 1), (1, 3, 1), (1, 4, 2), (1, 3, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 3, 0), (3, 4, 0), (2, 3, 1), (3, 4, 1), (4, 5, 0), (2, 3, 2), (3, 4, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (5, 4, 0), (5, 4, 1), (4, 3, 0), (4, 3, 1), (3, 2, 0), (3, 2, 1), (3, 2, 2), (5, 3, 0), (7, 4, 0), (2, 1, 0), (2, 1, 1), (2, 1, 2), (9, 4, 0), (7, 3, 0), (5, 2, 0), (5, 2, 1), (5, 2, 2), (8, 3, 0), (11, 4, 0), (3, 1, 0), (3, 1, 1)] points = np.array( list(zip(*itertools.product([2, 4, 8, 10, 12], repeat=4)))) for expo1, expo2, expo3, expo4 in zip(exponents, exponents[1:], exponents[2:], exponents[3:]): termX = CompoundTerm.create(*expo1) termY = CompoundTerm.create(*expo2) termZ = CompoundTerm.create(*expo3) termW = CompoundTerm.create(*expo4) term = MultiParameterTerm((0, termX), (1, termY), (2, termZ), (3, termW)) term.coefficient = 10 function = MultiParameterFunction(term) function.constant_coefficient = 20000 values = function.evaluate(points) measurements = [ Measurement(Coordinate(p), None, None, v) for p, v in zip(zip(*points), values) ] modeler = MultiParameterModeler() models = modeler.model([measurements]) self.assertEqual(1, len(models)) self.assertApproxFunction(function, models[0].hypothesis.function)
def deserialize_MultiParameterFunction(id_mappings, ioHelper): function = MultiParameterFunction() function.constant_coefficient = ioHelper.readValue() size = ioHelper.readInt() for i in range(0, size): term = deserialize_MultiParameterTerm(id_mappings, ioHelper) function.add_compound_term(term) return function
def create_model(self, measurements: Sequence[Measurement]): """ Create a multi-parameter model using the given measurements. """ if self.single_parameter_point_selection == 'auto' \ or self.single_parameter_point_selection == 'all': measurements_sp = self.find_best_measurement_points(measurements) else: # use the first base points found for each parameter for modeling of the single parameter functions measurements_sp = self.find_first_measurement_points(measurements) # print(coordinates_list) # model all single parameter experiments using only the selected points from the step before # parameters = list(range(measurements[0].coordinate.dimensions)) models = self.single_parameter_modeler.model(measurements_sp) functions = [m.hypothesis.function for m in models] # check if the number of measurements satisfies the reuqirements of the modeler (>=5) if len(measurements) < self.min_measurement_points: warnings.warn("Number of measurements for each parameter needs to be at least 5" " in order to create a performance model.") # return None # get the coordinates for modeling # coordinates = list(dict.fromkeys(m.coordinate for m in measurements).keys()) # use all available additional points for modeling the multi-parameter models constantCost = 0 meanModel = 0 for m in measurements: meanModel += m.value(self.use_median) / float(len(measurements)) for m in measurements: constantCost += (m.value(self.use_median) - meanModel) * (m.value(self.use_median) - meanModel) # find out which parameters should be kept compound_term_pairs = [] for i, function in enumerate(functions): terms = function.compound_terms if len(terms) > 0: compound_term = terms[0] compound_term.coefficient = 1 compound_term_pairs.append((i, compound_term)) # see if the function is constant if len(compound_term_pairs) == 0: constant_function = ConstantFunction() constant_function.constant_coefficient = meanModel constant_hypothesis = ConstantHypothesis(constant_function, self.use_median) constant_hypothesis.compute_cost(measurements) return Model(constant_hypothesis) # in case is only one parameter, make a single parameter function elif len(compound_term_pairs) == 1: param, compound_term = compound_term_pairs[0] multi_parameter_function = MultiParameterFunction() multi_parameter_term = MultiParameterTerm(compound_term_pairs[0]) multi_parameter_term.coefficient = compound_term.coefficient multi_parameter_function.add_compound_term(multi_parameter_term) # constant_coefficient = functions[param].get_constant_coefficient() # multi_parameter_function.set_constant_coefficient(constant_coefficient) multi_parameter_hypothesis = MultiParameterHypothesis(multi_parameter_function, self.use_median) multi_parameter_hypothesis.compute_coefficients(measurements) multi_parameter_hypothesis.compute_cost(measurements) return Model(multi_parameter_hypothesis) # create multiplicative multi parameter term mult = MultiParameterTerm(*compound_term_pairs) # create additive multi parameter terms add = [MultiParameterTerm(ctp) for ctp in compound_term_pairs] # create multi parameter functions mp_functions = [ # create f1 function a*b MultiParameterFunction(mult), # create f4 function a+b MultiParameterFunction(*add) ] if not self.allow_combinations_of_sums_and_products: pass # add Hypotheses for 2 parameter models elif len(compound_term_pairs) == 2: mp_functions += [ # create f2 function a*b+a MultiParameterFunction(add[0], mult), # create f3 function a*b+b MultiParameterFunction(add[1], mult) ] # add Hypotheses for 3 parameter models elif len(compound_term_pairs) == 3: # create multiplicative multi parameter terms # x*y mult_x_y = MultiParameterTerm(compound_term_pairs[0], compound_term_pairs[1]) # y*z mult_y_z = MultiParameterTerm(compound_term_pairs[1], compound_term_pairs[2]) # x*z mult_x_z = MultiParameterTerm(compound_term_pairs[0], compound_term_pairs[2]) # create multi parameter functions mp_functions += [ # x*y*z+x MultiParameterFunction(mult, add[0]), # x*y*z+y MultiParameterFunction(mult, add[1]), # x*y*z+z MultiParameterFunction(mult, add[2]), # x*y*z+x*y MultiParameterFunction(mult, mult_x_y), # x*y*z+y*z MultiParameterFunction(mult, mult_y_z), # x*y*z+x*z MultiParameterFunction(mult, mult_x_z), # x*y*z+x*y+z MultiParameterFunction(mult, mult_x_y, add[2]), # x*y*z+y*z+x MultiParameterFunction(mult, mult_y_z, add[0]), # x*y*z+x*z+y MultiParameterFunction(mult, mult_x_z, add[1]), # x*y*z+x+y MultiParameterFunction(mult, add[0], add[1]), # x*y*z+x+z MultiParameterFunction(mult, add[0], add[2]), # x*y*z+y+z MultiParameterFunction(mult, add[1], add[2]), # x*y+z MultiParameterFunction(mult_x_y, add[2]), # x*y+z+y MultiParameterFunction(mult_x_y, add[2], add[1]), # x*y+z+x MultiParameterFunction(mult_x_y, add[2], add[0]), # x*z+y MultiParameterFunction(mult_x_z, add[1]), # x*z+y+x MultiParameterFunction(mult_x_z, add[1], add[0]), # x*z+y+z MultiParameterFunction(mult_x_z, add[1], add[2]), # y*z+x MultiParameterFunction(mult_y_z, add[0]), # y*z+x+y MultiParameterFunction(mult_y_z, add[0], add[1]), # y*z+x+z MultiParameterFunction(mult_y_z, add[0], add[2]) ] # create the hypotheses from the functions hypotheses = [MultiParameterHypothesis(f, self.use_median) for f in mp_functions] # select one function as the bestHypothesis for the start best_hypothesis = copy.deepcopy(hypotheses[0]) best_hypothesis.compute_coefficients(measurements) best_hypothesis.compute_cost(measurements) best_hypothesis.compute_adjusted_rsquared(constantCost, measurements) logging.info(f"hypothesis 0: {best_hypothesis.function} --- smape: {best_hypothesis.SMAPE} " f"--- ar2: {best_hypothesis.AR2} --- rss: {best_hypothesis.RSS} " f"--- rrss: {best_hypothesis.rRSS} --- re: {best_hypothesis.RE}") # find the best hypothesis for i, hypothesis in enumerate(hypotheses): hypothesis.compute_coefficients(measurements) hypothesis.compute_cost(measurements) hypothesis.compute_adjusted_rsquared(constantCost, measurements) logging.info(f"hypothesis {i}: {hypothesis.function} --- smape: {hypothesis.SMAPE} " f"--- ar2: {hypothesis.AR2} --- rss: {hypothesis.RSS} " f"--- rrss: {hypothesis.rRSS} --- re: {hypothesis.RE}") term_contribution_big_enough = True # for all compound terms check if they are smaller than minimum allowed contribution for term in hypothesis.function.compound_terms: # ignore this hypothesis, since one of the terms contributes less than epsilon to the function if term.coefficient == 0 or hypothesis.calc_term_contribution(term, measurements) < self.epsilon: term_contribution_big_enough = False break if not term_contribution_big_enough: continue elif self.compare_with_RSS: if hypotheses[i].RSS < best_hypothesis.RSS: best_hypothesis = copy.deepcopy(hypotheses[i]) elif hypotheses[i].SMAPE < best_hypothesis.SMAPE: best_hypothesis = copy.deepcopy(hypotheses[i]) # add the best found hypothesis to the model list model = Model(best_hypothesis) logging.info(f"best hypothesis: {best_hypothesis.function} --- smape: {best_hypothesis.SMAPE} " f"--- ar2: {best_hypothesis.AR2} --- rss: {best_hypothesis.RSS} " f"--- rrss: {best_hypothesis.rRSS} --- re: {best_hypothesis.RE}") return model