diff --git a/app/helpers/solver_helper.py b/app/helpers/solver_helper.py index 8d0609f..e754a42 100644 --- a/app/helpers/solver_helper.py +++ b/app/helpers/solver_helper.py @@ -12,7 +12,7 @@ from models.item import Item from lib.errors.item_generation_error import ItemGenerationError def build_constraints(solver_run: SolverRun, problem: LpProblem, - items: list[Item], bundles: list[Bundle]) -> LpProblem: + items: list[Item], bundles: list[Bundle], selected_items, selected_bundles) -> LpProblem: logging.info('Creating Constraints...') try: @@ -29,28 +29,28 @@ def build_constraints(solver_run: SolverRun, problem: LpProblem, problem += lpSum( [ - len(bundle.items_with_attribute(attribute)) * bundles[bundle.id] for bundle in solver_run.bundles + len(bundle.items_with_attribute(attribute)) * bundles[bundle.id] for bundle in selected_bundles ] + [ - item.attribute_exists(attribute).real * items[item.id] for item in solver_run.unbundled_items() + item.attribute_exists(attribute).real * items[item.id] for item in selected_items ] ) >= round(total_form_items * (min / 100)), f'{attribute.id} - {attribute.value} - min' problem += lpSum( [ - len(bundle.items_with_attribute(attribute)) * bundles[bundle.id] for bundle in solver_run.bundles + len(bundle.items_with_attribute(attribute)) * bundles[bundle.id] for bundle in selected_bundles ] + [ - item.attribute_exists(attribute).real * items[item.id] for item in solver_run.unbundled_items() + item.attribute_exists(attribute).real * items[item.id] for item in selected_items ] ) <= round(total_form_items * (max / 100)), f'{attribute.id} - {attribute.value} - max' elif attribute.type == 'bundle': logging.info('Bundles Constraint Generating...') # TODO: account for many different bundle types, since the id condition in L33 could yield duplicates - if solver_run.bundles != None: + if selected_bundles != None: # make sure the total bundles used in generated form is limited between min-max set problem += lpSum([ - bundles[bundle.id] for bundle in solver_run.bundles + bundles[bundle.id] for bundle in selected_bundles ]) == randint(int(constraint.minimum), int(constraint.maximum)) diff --git a/app/models/solver_run.py b/app/models/solver_run.py index 7002cc9..a1a729b 100644 --- a/app/models/solver_run.py +++ b/app/models/solver_run.py @@ -108,7 +108,7 @@ class SolverRun(BaseModel): constraint.reference_attribute for constraint in self.constraints if constraint.reference_attribute.type == 'bundle') - if len(bundle_constraints) > 0: + if len(list(bundle_constraints)) > 0: return [item for item in self.items if item.passage_id == None] else: return self.items diff --git a/app/services/loft_service.py b/app/services/loft_service.py index a73d986..d854291 100644 --- a/app/services/loft_service.py +++ b/app/services/loft_service.py @@ -72,15 +72,9 @@ class LoftService(Base): form_number = form_count + 1 current_drift = 0 # FF Tokyo Drift - selected_items = [] - selected_bundles = [] - - if form_count == 1: - selected_items = self.solver_run.unbundled_items() - selected_bundles = self.solver_run.bundles - else: - selected_items = self.solver_run.select_items_by_percent(30) - selected_bundles = self.solver_run.select_bundles_by_percent( + # adding an element of randomness to the items and bundles used + selected_items = self.solver_run.select_items_by_percent(30) + selected_bundles = self.solver_run.select_bundles_by_percent( 30) # setup common Solver variables @@ -108,42 +102,42 @@ class LoftService(Base): # objective function problem += lpSum([ bundle.count * bundles[bundle.id] - for bundle in self.solver_run.bundles + for bundle in selected_bundles ] + [ items[item.id] - for item in self.solver_run.unbundled_items() + for item in selected_items ]) # Form Constraints problem += lpSum( [ bundle.count * bundles[bundle.id] - for bundle in self.solver_run.bundles + for bundle in selected_bundles ] + [ 1 * items[item.id] - for item in self.solver_run.unbundled_items() + for item in selected_items ] ) == self.solver_run.total_form_items, f'Total bundle form items for form {form_number}' # Dynamic constraints.. currently we only support Metadata and Bundles(Cases/Passages) problem = solver_helper.build_constraints( - self.solver_run, problem, items, bundles) + self.solver_run, problem, items, bundles, selected_items, selected_bundles) # form uniqueness constraints - for form in solution.forms: - form_item_options = [ - bundles[bundle.id] - for bundle in self.solver_run.bundles - ] + [ - items[item.id] - for item in self.solver_run.unbundled_items() - ] - problem += len( - set(form.solver_variables) - & set(form_item_options)) / float( - len( - set(form.solver_variables) - | set(form_item_options))) * 100 >= 10 + # for form in solution.forms: + # form_item_options = [ + # bundles[bundle.id] + # for bundle in selected_bundles + # ] + [ + # items[item.id] + # for item in selected_items + # ] + # problem += len( + # set(form.solver_variables) + # & set(form_item_options)) / float( + # len( + # set(form.solver_variables) + # | set(form_item_options))) * 100 >= 10 logging.info('Creating TIF and TCC Elastic constraints') @@ -152,21 +146,21 @@ class LoftService(Base): problem += lpSum([ bundle.tif(self.solver_run.irt_model, tif_target.theta) * bundles[bundle.id] - for bundle in self.solver_run.bundles + for bundle in selected_bundles ] + [ item.iif(self.solver_run, tif_target.theta) * items[item.id] - for item in self.solver_run.unbundled_items() + for item in selected_items ]) >= tif_target.minimum( ), f'Min TIF theta({tif_target.theta}) at target {tif_target.value} drift at {current_drift}%' problem += lpSum([ bundle.tif(self.solver_run.irt_model, tif_target.theta) * bundles[bundle.id] - for bundle in self.solver_run.bundles + for bundle in selected_bundles ] + [ item.iif(self.solver_run, tif_target.theta) * items[item.id] - for item in self.solver_run.unbundled_items() + for item in selected_items ]) <= tif_target.maximum( ), f'Max TIF theta({tif_target.theta}) at target {tif_target.value} drift at {current_drift}%' @@ -174,21 +168,21 @@ class LoftService(Base): problem += lpSum([ bundle.trf(self.solver_run.irt_model, tcc_target.theta) * bundles[bundle.id] - for bundle in self.solver_run.bundles + for bundle in selected_bundles ] + [ item.irf(self.solver_run, tcc_target.theta) * items[item.id] - for item in self.solver_run.unbundled_items() + for item in selected_items ]) >= tcc_target.minimum( ), f'Min TCC theta({tcc_target.theta}) at target {tcc_target.value} drift at {current_drift}%' problem += lpSum([ bundle.trf(self.solver_run.irt_model, tcc_target.theta) * bundles[bundle.id] - for bundle in self.solver_run.bundles + for bundle in selected_bundles ] + [ item.irf(self.solver_run, tcc_target.theta) * items[item.id] - for item in self.solver_run.unbundled_items() + for item in selected_items ]) <= tcc_target.maximum( ), f'Max TCC theta({tcc_target.theta}) at target {tcc_target.value} drift at {current_drift}%' diff --git a/app/services/solver_sandbox.py b/app/services/solver_sandbox.py index e00f294..97ac5fd 100644 --- a/app/services/solver_sandbox.py +++ b/app/services/solver_sandbox.py @@ -27,6 +27,10 @@ class SolverSandbox: # Latest CPNRE Item Bank with metadata and cases body = {'Records': [{'eventVersion': '2.1', 'eventSource': 'aws:s3', 'awsRegion': 'us-east-1', 'eventTime': '2022-03-24T15:47:54.652Z', 'eventName': 'ObjectCreated:Put', 'userIdentity': {'principalId': 'AIDAJDPLRKLG7UEXAMPLE'}, 'requestParameters': {'sourceIPAddress': '127.0.0.1'}, 'responseElements': {'x-amz-request-id': '1969b1ed', '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': 'ab40ca20-8db7-013a-a88f-0242ac120013_solver_run.tar.gz', 'size': 24111, 'eTag': '"718a1a17b5dd5219b8e179bfd1ddf1ca"', 'versionId': None, 'sequencer': '0055AED6DCD90281E5'}}}]} + + # Latest LOFT Item Bank with metadata and cases with target variance + body = {'Records': [{'eventVersion': '2.1', 'eventSource': 'aws:s3', 'awsRegion': 'us-east-1', 'eventTime': '2022-03-25T18:03:18.829Z', 'eventName': 'ObjectCreated:Put', 'userIdentity': {'principalId': 'AIDAJDPLRKLG7UEXAMPLE'}, 'requestParameters': {'sourceIPAddress': '127.0.0.1'}, 'responseElements': {'x-amz-request-id': '204c718f', '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': 'beb35dc0-8e93-013a-5807-0242ac120013_solver_run.tar.gz', 'size': 24112, 'eTag': '"a5a4aad0eb8c9d9af2aad9684437022a"', 'versionId': None, 'sequencer': '0055AED6DCD90281E5'}}}]} + LoftService(body).process() def yosh_loop():