diff --git a/app/helpers/service_helper.py b/app/helpers/service_helper.py index c004175..4f7f23c 100644 --- a/app/helpers/service_helper.py +++ b/app/helpers/service_helper.py @@ -64,3 +64,15 @@ def solution_to_file(buffer, total_form_items, forms): def key_to_uuid(key): return re.split("_", key)[0] + +def solution_items(variables, solver_run): + form_items = [] + + for v in variables: + if v.varValue > 0: + item_id = v.name.replace('Item_', '') + item = solver_run.get_item(item_id) + # add item to list and then remove from master item list + form_items.append(item) + + return form_items diff --git a/app/helpers/solver_helper.py b/app/helpers/solver_helper.py new file mode 100644 index 0000000..b9f7fb0 --- /dev/null +++ b/app/helpers/solver_helper.py @@ -0,0 +1,23 @@ +from pulp import lpSum + +def build_constraints(solver_run, problem, items): + total_form_items = solver_run.total_form_items + constraints = solver_run.constraints + + for constraint in constraints: + attribute = constraint.reference_attribute + min = constraint.minimum + max = constraint.maximum + + con = dict(zip([item.id for item in solver_run.items], + [item.attribute_exists(attribute) + for item in solver_run.items])) + # print([con[item.id] * items[item.id] for item in solver_items]) + problem += lpSum([con[item.id] + * items[item.id] + for item in solver_run.items]) >= round(total_form_items * (min / 100)), f'{attribute.id} - {attribute.value} - min' + problem += lpSum([con[item.id] + * items[item.id] + for item in solver_run.items]) <= round(total_form_items * (max / 100)), f'{attribute.id} - {attribute.value} - max' + + return problem \ No newline at end of file diff --git a/app/models/item.py b/app/models/item.py index 71bffcf..9cb1d8d 100644 --- a/app/models/item.py +++ b/app/models/item.py @@ -17,14 +17,14 @@ class Item(BaseModel): def irf(self, solver_run, theta): return ItemResponseFunction(solver_run.irt_model).calculate(b_param=self.b_param,theta=theta) - def get_attribute(self, id, value): + def get_attribute(self, ref_attribute): for attribute in self.attributes: - if attribute.id == id and attribute.value == value: + if attribute.id == ref_attribute.id and attribute.value == ref_attribute.value: return attribute.value return False - def attribute_exists(self, id, value): + def attribute_exists(self, ref_attribute): for attribute in self.attributes: - if attribute.id == id and attribute.value == value: + if attribute.id == ref_attribute.id and attribute.value == ref_attribute.value: return True return False \ No newline at end of file diff --git a/app/models/solver_run.py b/app/models/solver_run.py index 22f49c7..1a97c8c 100644 --- a/app/models/solver_run.py +++ b/app/models/solver_run.py @@ -17,3 +17,13 @@ class SolverRun(BaseModel): theta_cut_score: float = 0.00 advanced_options: Optional[AdvancedOptions] engine: str + + def get_item(self, item_id): + for item in self.items: + if str(item.id) == item_id: + return item + return False + + def remove_items(self, items): + self.items = [item for item in self.items if item not in items] + return True diff --git a/app/services/loft_service.py b/app/services/loft_service.py index 364a68e..dea817a 100644 --- a/app/services/loft_service.py +++ b/app/services/loft_service.py @@ -2,7 +2,7 @@ import os, json, random, io, logging from pulp import * -from helpers import aws_helper, tar_helper, csv_helper, service_helper, irt_helper +from helpers import aws_helper, tar_helper, csv_helper, service_helper, solver_helper from models.solver_run import SolverRun from models.solution import Solution @@ -54,8 +54,6 @@ class LoftService(Base): # setup vars items = LpVariable.dicts( "Item", [item.id for item in self.solver_run.items], lowBound=1, upBound=1, cat='Binary') - used = dict(zip([item.id for item in self.solver_run.items], - [1 for item in self.solver_run.items])) problem_objection_functions = [] # create problem @@ -65,16 +63,8 @@ class LoftService(Base): problem += lpSum([items[item.id] for item in self.solver_run.items]) == self.solver_run.total_form_items, 'Total form items' - for constraint in self.solver_run.constraints: - con = dict(zip([item.id for item in self.solver_run.items], - [item.attribute_exists(constraint.reference_attribute.id, constraint.reference_attribute.value) - for item in self.solver_run.items])) - problem += lpSum([con[item.id] - * items[item.id] - for item in self.solver_run.items]) >= round(self.solver_run.total_form_items * (constraint.minimum / 100)), f'{constraint.reference_attribute.id} - {constraint.reference_attribute.value} - min' - problem += lpSum([con[item.id] - * items[item.id] - for item in self.solver_run.items]) <= round(self.solver_run.total_form_items * (constraint.maximum / 100)), f'{constraint.reference_attribute.id} - {constraint.reference_attribute.value} - max' + # generic constraints + problem = solver_helper.build_constraints(self.solver_run, problem, items) # multi-objective functions and constraints for target in self.solver_run.objective_function.tif_targets: @@ -96,18 +86,9 @@ class LoftService(Base): if LpStatus[problem.status] == 'Optimized': # add return items and create as a form - form_items = [] - for v in problem.variables(): - count = 0 - if v.varValue > 0: - item_id = v.name.replace('Item_', '') - for item in self.solver_run.items: - if str(item.id) == item_id: - # add item to list - form_items.append(item) - # remove ids from master items list - self.solver_run.items.remove(item) - + form_items = service_helper.solution_items(problem.variables(), self.solver_run) + # remove items + self.solver_run.remove_items(form_items) # add form to solution solution.forms.append(Form.create(form_items, self.solver_run))