diff --git a/app/helpers/solver_helper.py b/app/helpers/solver_helper.py index dce9b0c..e5f2009 100644 --- a/app/helpers/solver_helper.py +++ b/app/helpers/solver_helper.py @@ -56,6 +56,22 @@ def build_constraints(solver_run: SolverRun, problem: LpProblem, items: list[Ite logging.error(error) raise ItemGenerationError("Bundle min and/or max larger than bundle amount provided", error.args[0]) +def get_random_bundles(total_form_items: int, total_bundles: int, bundles: list[Bundle], found_bundles = False) -> list[Bundle]: + selected_bundles = None + total_bundle_items = 0 + + while found_bundles == False: + selected_bundles = sample(bundles, total_bundles) + total_bundle_items = sum(bundle.count for bundle in selected_bundles) + + if total_bundle_items <= total_form_items: + found_bundles = True + + if found_bundles == True: + return selected_bundles + else: + return get_random_bundles(total_form_items, total_bundles - 1, bundles) + def valid_bundle_combinations(total_form_items: int, total_bundles: int, min_bundles: int, bundles: list[Bundle], selected_bundle_combinations: list[list[Bundle]] = []) -> list[list[Bundle]]: if total_bundles < min_bundles: return selected_bundle_combinations diff --git a/app/services/loft_service.py b/app/services/loft_service.py index bd330c5..fc391d1 100644 --- a/app/services/loft_service.py +++ b/app/services/loft_service.py @@ -74,33 +74,36 @@ class LoftService(Base): response_id=random.randint(100, 5000), forms=[] ) - + # initiate problem problem = None count = 0 + if bundle_constraint: - # generate valid bundle combinations - bundle_combinations = solver_helper.valid_bundle_combinations( - self.solver_run.total_form_items, - int(bundle_constraint.maximum), - int(bundle_constraint.minimum), - self.solver_run.bundles) + # # generate valid bundle combinations + # bundle_combinations = solver_helper.valid_bundle_combinations( + # self.solver_run.total_form_items, + # int(bundle_constraint.maximum), + # int(bundle_constraint.minimum), + # self.solver_run.bundles) - # scramble bundle_combinations to ensure distinctiveness for each form generated - random.shuffle(bundle_combinations) + # # scramble bundle_combinations to ensure distinctiveness for each form generated + # random.shuffle(bundle_combinations) - for bundles in bundle_combinations: - problem = self.solve_problem(items, bundles) - - # if optimal solution found, break loop - if LpStatus[problem.status] == 'Optimal': - break + # for bundles in bundle_combinations: + # problem = self.solve(items, bundles) + + # # if optimal solution found, break loop + # if LpStatus[problem.status] == 'Optimal': + # break + bundles_amount = random.randint(int(bundle_constraint.minimum), int(bundle_constraint.maximum)) + problem = self.recursive_solve(items, bundles_amount) else: # no bundles - problem = self.solve_problem(items) - + problem = self.solve(items) + # successfull form, increment and exit out of loop f += 1 - + # add return items and create as a form form_items = service_helper.solution_items(problem.variables(), self.solver_run) @@ -108,8 +111,22 @@ class LoftService(Base): solution.forms.append(Form.create(form_items, self.solver_run, LpStatus[problem.status])) return solution - - def solve_problem(self, items: list[Item], bundles: list[Bundle] or None = None) -> LpProblem: + + def recursive_solve(self, items, bundles_amount, attempts = 1000) -> LpProblem: + selected_bundles = solver_helper.get_random_bundles( + self.solver_run.total_form_items, + bundles_amount, + self.solver_run.bundles) + + problem = self.solve(items, selected_bundles) + + # if optimal solution found, break loop + if LpStatus[problem.status] == 'Optimal' or attempts == 0: + return problem + else: + return self.recursive_solve(items, max, attempts - 1) + + def solve(self, items: list[Item], bundles: list[Bundle] or None = None) -> LpProblem: # create problem problem = LpProblem("ata-form-generate", LpMinimize)