diff --git a/app/services/loft_service.py b/app/services/loft_service.py index 3ad1bf7..1a20207 100644 --- a/app/services/loft_service.py +++ b/app/services/loft_service.py @@ -67,101 +67,113 @@ class LoftService(Base): solution = Solution(response_id=random.randint(100, 5000), forms=[]) # unsolved solution # setup common Solver variables - items = LpVariable.dicts("Item", [item.id for item in self.solver_run.items], cat='Binary') + items = LpVariable.dicts("Item", [item.id for item in self.solver_run.items], cat='Binary') bundles = LpVariable.dicts("Bundle", [bundle.id for bundle in self.solver_run.bundles], cat='Binary') - form_count = 0 # counter for number of forms - # iterate for number of forms that require creation - while form_count < self.solver_run.total_forms: - form_number = form_count + 1 - logging.info('Generating Solution for Form %s...', form_number) + for form_count in range(self.solver_run.total_forms): + form_number = form_count + 1 + current_drift = 0 # FF Tokyo Drift - # create problem - problem = LpProblem("ata-form-generate", LpMinimize) - problem_objective_functions = [] + logging.info(f'Generating Solution for Form {form_number}') - # dummy objective function, because it just makes things easierâ„¢ - problem += lpSum([items[item.id] for item in self.solver_run.items]) + while current_drift <= Target.max_drift(): + drift_percent = current_drift / 100 - # constraints - problem += lpSum([items[item.id] - for item in self.solver_run.items]) == self.solver_run.total_form_items, f'Total form items for form {form_number}' - problem += lpSum( - [ - bundle.count * bundles[bundle.id] - for bundle in self.solver_run.bundles - ] + [ - 1 * items[item.id] - for item in self.solver_run.unbundled_items() - ] - ) == self.solver_run.total_form_items, f'Total bundle form items for form {form_number}' + # create problem + problem = LpProblem('ata-form-generate', LpMinimize) - # Dynamic constraints.. currently we only support Metadata and Bundles(Cases/Passages) - problem = solver_helper.build_constraints(self.solver_run, problem, items, bundles) + # objective function + problem += lpSum( + [item.iif_irf_sum(self.solver_run) * items[item.id] for item in self.solver_run.items] + + + [bundle.tif_trf_sum(self.solver_run) * bundles[bundle.id] for bundle in self.solver_run.bundles] + ) - # multi-objective constraints - logging.info('Creating TIF and TCC constraints') - for target in self.solver_run.objective_function.tif_targets: - tif = lpSum([ - bundle.tif(self.solver_run.irt_model, target.theta) * - bundles[bundle.id] for bundle in self.solver_run.bundles - ] + [ - item.iif(self.solver_run, target.theta) * items[item.id] - for item in self.solver_run.items - ]) <= target.value, f'min tif theta {target.theta} target for form {form_number}' + # Form Constraints + problem += lpSum( + [items[item.id] for item in self.solver_run.items] + ) == self.solver_run.total_form_items, f'Total form items for form {form_number}' - problem += tif - problem_objective_functions.append(tif) + problem += lpSum( + [ + bundle.count * bundles[bundle.id] for bundle in self.solver_run.bundles + ] + + [ + 1 * items[item.id] for item in self.solver_run.unbundled_items() + ] + ) == self.solver_run.total_form_items, f'Total bundle form items for form {form_number}' - e = LpAffineExpression( - [(bundles[bundle.id], - bundle.tif(self.solver_run.irt_model, target.theta)) - for bundle in self.solver_run.bundles] + - [(items[item.id], item.iif(self.solver_run, target.theta)) - for item in self.solver_run.items]) - constraint = LpConstraint( - e=e, - sense=0, - name=f'tif theta ({target.theta}) @{target.value}', - rhs=target.value) + # Dynamic constraints.. currently we only support Metadata and Bundles(Cases/Passages) + problem = solver_helper.build_constraints(self.solver_run, problem, items, bundles) - elasticized_constraint = solver_helper.elasticize_constraint(constraint) - problem.extend(elasticized_constraint) - # if int(target.value) == 20: print(elasticized_constraint) - for target in self.solver_run.objective_function.tcc_targets: - tcc = lpSum([ - bundle.trf(self.solver_run.irt_model, target.theta) * - bundles[bundle.id] for bundle in self.solver_run.bundles - ] + [ - item.irf(self.solver_run, target.theta) * items[item.id] - for item in self.solver_run.items - ]) <= target.value, f'min tcc theta {target.theta} target for form {form_number}' + logging.info('Creating TIF and TCC Elastic constraints') - problem += tcc - problem_objective_functions.append(tcc) + # Behold our very own Elastic constraints! + for tif_target in self.solver_run.objective_function.tif_targets: + problem += lpSum( + [ + bundle.tif(self.solver_run.irt_model, tif_target.theta) * bundles[bundle.id] + for bundle in self.solver_run.bundles + ] + + [ + item.iif(self.solver_run, tif_target.theta) * items[item.id] + for item in self.solver_run.items + ] + ) >= tif_target.value - (tif_target.value * drift_percent) - e = LpAffineExpression( - [(bundles[bundle.id], - bundle.trf(self.solver_run.irt_model, target.theta)) - for bundle in self.solver_run.bundles] + - [(items[item.id], item.irf(self.solver_run, target.theta)) - for item in self.solver_run.items]) - constraint = LpConstraint( - e=e, - sense=-1, - name=f'tcc theta ({target.theta}) @{target.value} for form {form_number}', - rhs=target.value) + problem += lpSum( + [ + bundle.tif(self.solver_run.irt_model, tif_target.theta) * bundles[bundle.id] + for bundle in self.solver_run.bundles + ] + + [ + item.iif(self.solver_run, tif_target.theta) * items[item.id] + for item in self.solver_run.items + ] + ) <= tif_target.value + (tif_target.value * drift_percent) - elasticized_constraint = solver_helper.elasticize_constraint(constraint) - # problem.extend(elasticized_constraint) + for tcc_target in self.solver_run.objective_function.tcc_targets: + problem += lpSum( + [ + bundle.trf(self.solver_run.irt_model, tcc_target.theta) * bundles[bundle.id] + for bundle in self.solver_run.bundles + ] + + [ + item.irf(self.solver_run, tcc_target.theta) * items[item.id] + for item in self.solver_run.items + ] + ) >= tcc_target.value - (tcc_target.value * drift_percent) - # solve problem - logging.info('Solving for Form %s...', form_number) + problem += lpSum( + [ + bundle.trf(self.solver_run.irt_model, tcc_target.theta) * bundles[bundle.id] + for bundle in self.solver_run.bundles + ] + + [ + item.irf(self.solver_run, tcc_target.theta) * items[item.id] + for item in self.solver_run.items + ] + ) <= tcc_target.value + (tcc_target.value * drift_percent) - print(problem) - problem.solve() - # problem.sequentialSolve(problem_objective_functions) + # solve problem + logging.info(f'Solving for Form {form_number}') + + problem.solve() + + if LpStatus[problem.status] == 'Infeasible': + logging.info(f'attempt infeasible for drift of {current_drift}%') + + for v in problem.variables(): + print(v.name, "=", v.varValue) + + print(problem.objective.value()) + print(problem.objective) + + current_drift += Target.max_drift_increment() + else: + logging.info(f'solution found with drift of {current_drift}%!') + break logging.info(f'Solved for Form {form_number}...generating form and adding to solution') @@ -173,11 +185,8 @@ class LoftService(Base): logging.info('Form generated and added to solution...') - # successfull form, increment - form_count += 1 - logging.info('Solution Generated.') - # print(problem) + return solution def stream_to_s3_bucket(self, error=None): diff --git a/app/services/solver_sandbox.py b/app/services/solver_sandbox.py index c44442b..6f83a11 100644 --- a/app/services/solver_sandbox.py +++ b/app/services/solver_sandbox.py @@ -14,8 +14,7 @@ from pulp import LpProblem, LpVariable, LpInteger, LpMinimize, LpMaximize, LpAff from services.loft_service import LoftService class SolverSandbox: - def loft_service(): - body = {'Records': [{'eventVersion': '2.1', 'eventSource': 'aws:s3', 'awsRegion': 'us-east-1', 'eventTime': '2022-03-09T14:40:04.115Z', 'eventName': 'ObjectCreated:Put', 'userIdentity': {'principalId': 'AIDAJDPLRKLG7UEXAMPLE'}, 'requestParameters': {'sourceIPAddress': '127.0.0.1'}, 'responseElements': {'x-amz-request-id': '4629a38d', 'x-amz-id-2': 'eftixk72aD6Ap51TnqcoF8eFidJG9Z/2'}, 's3': {'s3SchemaVersion': '1.0', 'configurationId': 'testConfigRule', 'bucket': {'name': 'measure-local-solver-ingest', 'ownerIdentity': {'principalId': 'A3NL1KOZZKExample'}, 'arn': 'arn:aws:s3:::measure-local-solver-ingest'}, 'object': {'key': 'baf511b0-81e4-013a-6e98-0242ac120010_solver_run.tar.gz', 'size': 509, 'eTag': '"4c0911a335c6feca5493d63b58654e3a"', 'versionId': None, 'sequencer': '0055AED6DCD90281E5'}}}]} + def loft_service(body): LoftService(body).process() def yosh_loop():