solve without enemies, initial impl. still requires factoring out
This commit is contained in:
parent
eb8138eaf9
commit
8667bec8d5
@ -1,8 +1,11 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
from lib.irt.test_response_function import TestResponseFunction
|
from lib.irt.test_response_function import TestResponseFunction
|
||||||
from lib.irt.test_information_function import TestInformationFunction
|
from lib.irt.test_information_function import TestInformationFunction
|
||||||
|
|
||||||
from models.targets.tif_target import TifTarget
|
from models.targets.tif_target import TifTarget
|
||||||
from models.targets.tcc_target import TccTarget
|
from models.targets.tcc_target import TccTarget
|
||||||
|
from models.item import Item
|
||||||
|
|
||||||
def generate_tif_results(items, solver_run):
|
def generate_tif_results(items, solver_run):
|
||||||
targets = []
|
targets = []
|
||||||
|
@ -14,6 +14,16 @@ class Bundle(BaseModel):
|
|||||||
items: List[Item]
|
items: List[Item]
|
||||||
type: str
|
type: str
|
||||||
|
|
||||||
|
def find_items(self, requested_items_ids: [int]) -> [Item]:
|
||||||
|
found_items = []
|
||||||
|
|
||||||
|
for item in self.items:
|
||||||
|
if item.id in requested_items_ids:
|
||||||
|
found_items.append(item)
|
||||||
|
|
||||||
|
return found_items
|
||||||
|
|
||||||
|
|
||||||
def tif(self, irt_model: IRTModel, theta: float) -> float:
|
def tif(self, irt_model: IRTModel, theta: float) -> float:
|
||||||
return TestInformationFunction(irt_model).calculate(self.items, theta=theta)
|
return TestInformationFunction(irt_model).calculate(self.items, theta=theta)
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ class Item(BaseModel):
|
|||||||
id: int
|
id: int
|
||||||
position: Optional[int] = None
|
position: Optional[int] = None
|
||||||
passage_id: Optional[int] = None
|
passage_id: Optional[int] = None
|
||||||
enemies: Optional[int] = None
|
enemies: List[int] = []
|
||||||
workflow_state: Optional[str] = None
|
workflow_state: Optional[str] = None
|
||||||
attributes: List[Attribute] = None
|
attributes: List[Attribute] = None
|
||||||
b_param: float = 0.00
|
b_param: float = 0.00
|
||||||
|
@ -3,10 +3,12 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import Any, List
|
from typing import Any, List
|
||||||
from pulp import LpProblem, LpVariable, lpSum
|
from pulp import LpProblem, LpVariable, LpStatus, lpSum
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from helpers import service_helper, irt_helper
|
||||||
|
|
||||||
from models.solution import Solution
|
from models.solution import Solution
|
||||||
from models.item import Item
|
from models.item import Item
|
||||||
from models.bundle import Bundle
|
from models.bundle import Bundle
|
||||||
@ -38,8 +40,71 @@ class Problem(BaseModel):
|
|||||||
upBound=1,
|
upBound=1,
|
||||||
cat='Binary')
|
cat='Binary')
|
||||||
|
|
||||||
def solve(self) -> LpProblem:
|
def solve(self, solver_run: SolverRun) -> LpProblem:
|
||||||
self.problem.solve()
|
logging.info('solving problem...')
|
||||||
|
# if we allow enemies, go through the normal solving process
|
||||||
|
if solver_run.allow_enemies:
|
||||||
|
logging.info('enemes allowed, so just solving')
|
||||||
|
self.problem.solve()
|
||||||
|
# otherwise begin the process of filtering enemies
|
||||||
|
else:
|
||||||
|
self.problem.solve()
|
||||||
|
|
||||||
|
# however, if the solve was infeasible, kick it back
|
||||||
|
# to the normal process
|
||||||
|
if LpStatus[self.problem.status] == 'Infeasible':
|
||||||
|
return self.problem
|
||||||
|
# otherwise continue
|
||||||
|
else:
|
||||||
|
# get items from solution
|
||||||
|
solved_items, _ = service_helper.solution_items(self.problem.variables(), solver_run)
|
||||||
|
|
||||||
|
sacred_ids = []
|
||||||
|
enemy_ids = []
|
||||||
|
|
||||||
|
# get all enemies
|
||||||
|
for item in solved_items:
|
||||||
|
# if it has enemies, check if it exists as part of the solved items
|
||||||
|
for enemy_id in item.enemies:
|
||||||
|
# if it does, it's a true enemy
|
||||||
|
if enemy_id in (item.id for item in solved_items):
|
||||||
|
enemy_ids.append(enemy_id)
|
||||||
|
# remove enemy from solved items,
|
||||||
|
# lest it has this sacred item added to enemies
|
||||||
|
solved_items = [i for i in solved_items if i.id != enemy_id]
|
||||||
|
|
||||||
|
# the item is cleansed, now it's sacred
|
||||||
|
sacred_ids.append(item.id)
|
||||||
|
|
||||||
|
if enemy_ids:
|
||||||
|
logging.info('enemies found, adding constraints...')
|
||||||
|
|
||||||
|
# remove old enemy/sacred constraints
|
||||||
|
self.problem.constrants.pop('Exclude_enemy_items')
|
||||||
|
self.problem.constrants.pop('Include_sacred_items')
|
||||||
|
|
||||||
|
# add constraint to not allow enemy items
|
||||||
|
self.problem += lpSum([
|
||||||
|
len(bundle.find_items(enemy_ids)) * self.solver_bundles_var[bundle.id]
|
||||||
|
for bundle in self.bundles
|
||||||
|
] + [
|
||||||
|
(item.id in enemy_ids) * self.solver_items_var[item.id]
|
||||||
|
for item in self.items
|
||||||
|
]) == 0, 'Exclude enemy items'
|
||||||
|
|
||||||
|
# add constraint to use sacred items
|
||||||
|
self.problem += lpSum([
|
||||||
|
len(bundle.find_items(sacred_ids)) * self.solver_bundles_var[bundle.id]
|
||||||
|
for bundle in self.bundles
|
||||||
|
] + [
|
||||||
|
(item.id in sacred_ids) * self.solver_items_var[item.id]
|
||||||
|
for item in self.items
|
||||||
|
]) == len(sacred_ids), 'Include sacred items'
|
||||||
|
|
||||||
|
# recursively solve until no enemies exist or infeasible
|
||||||
|
logging.info('recursively solving...')
|
||||||
|
self.solve(solver_run)
|
||||||
|
|
||||||
return self.problem
|
return self.problem
|
||||||
|
|
||||||
def generate(self, solution: Solution, solver_run: SolverRun) -> None:
|
def generate(self, solution: Solution, solver_run: SolverRun) -> None:
|
||||||
@ -63,5 +128,3 @@ class Problem(BaseModel):
|
|||||||
error.msg,
|
error.msg,
|
||||||
error.args[0])
|
error.args[0])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ class SolverRun(BaseModel):
|
|||||||
total_forms: int = 1
|
total_forms: int = 1
|
||||||
theta_cut_score: float = 0.00
|
theta_cut_score: float = 0.00
|
||||||
drift_style: Literal['constant', 'variable'] = 'constant'
|
drift_style: Literal['constant', 'variable'] = 'constant'
|
||||||
|
allow_enemies: bool = False
|
||||||
advanced_options: Optional[AdvancedOptions]
|
advanced_options: Optional[AdvancedOptions]
|
||||||
engine: str
|
engine: str
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import json, random, io, logging
|
import json, random, io, logging
|
||||||
|
|
||||||
from pulp import LpProblem, LpVariable, LpMinimize, LpStatus, lpSum
|
from pulp import LpProblem, LpMinimize, LpStatus
|
||||||
|
|
||||||
from lib.application_configs import ApplicationConfigs
|
from lib.application_configs import ApplicationConfigs
|
||||||
from helpers import aws_helper, tar_helper, csv_helper, service_helper
|
from helpers import aws_helper, tar_helper, csv_helper, service_helper
|
||||||
@ -82,7 +82,7 @@ class FormGenerationService(Base):
|
|||||||
# create problem
|
# create problem
|
||||||
problem_handler = Problem(items = self.solver_run.unbundled_items(), bundles = self.solver_run.bundles, problem = LpProblem('ata-form-generate', LpMinimize))
|
problem_handler = Problem(items = self.solver_run.unbundled_items(), bundles = self.solver_run.bundles, problem = LpProblem('ata-form-generate', LpMinimize))
|
||||||
problem_handler.generate(solution, self.solver_run)
|
problem_handler.generate(solution, self.solver_run)
|
||||||
problem = problem_handler.solve()
|
problem = problem_handler.solve(self.solver_run)
|
||||||
|
|
||||||
if LpStatus[problem.status] == 'Infeasible':
|
if LpStatus[problem.status] == 'Infeasible':
|
||||||
logging.info(
|
logging.info(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user