from pulp import lpSum from random import randint, sample import logging from lib.errors.item_generation_error import ItemGenerationError def build_constraints(solver_run, problem, items): try: 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 if attribute.type == 'metadata': con = dict(zip([item.id for item in solver_run.items], [item.attribute_exists(attribute) for item in solver_run.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' elif attribute.type == 'bundle': # # TODO: account for many different bundle types, since the id condition in L33 could yield duplicates total_bundles = randint(constraint.minimum, constraint.maximum) selected_bundles = sample(solver_run.bundles, total_bundles) total_bundle_items = 0 for bundle in selected_bundles: con = dict(zip([item.id for item in solver_run.items], [(getattr(item, bundle.type, False) == bundle.id) for item in solver_run.items])) problem += lpSum([con[item.id] * items[item.id] for item in solver_run.items]) == bundle.count, f'Bundle constraint for {bundle.type} ({bundle.id})' total_bundle_items += bundle.count # make sure all other items added to the form # are not a part of any bundle # currently only supports single bundle constrains, will need refactoring for multiple bundle constraints con = dict(zip([item.id for item in solver_run.items], [(getattr(item, attribute.id, None) == None) for item in solver_run.items])) problem += lpSum([con[item.id] * items[item.id] for item in solver_run.items]) == solver_run.total_form_items - total_bundle_items, f'Remaining items are not of a bundle type' return problem except ValueError as error: logging.error(error) raise ItemGenerationError("Bundle min and/or max larger than bundle amount provided", error.args[0])