87 lines
3.1 KiB
Python
87 lines
3.1 KiB
Python
import re
|
|
from typing import List, Dict, Any, Callable
|
|
|
|
class ParameterConstraintEngine:
|
|
def __init__(self):
|
|
self.constraints = []
|
|
self.condition_functions = []
|
|
|
|
def add_constraint(self, name: str, condition: str, error_message: str = ''):
|
|
self.constraints.append({
|
|
'name': name,
|
|
'condition': condition,
|
|
'error_message': error_message or 'Constraint violated: ' + name
|
|
})
|
|
|
|
def add_condition_from_config(self, param_name: str, condition_str: str):
|
|
if not condition_str:
|
|
return
|
|
|
|
condition_str = condition_str.strip()
|
|
self.constraints.append({
|
|
'name': param_name,
|
|
'condition': condition_str,
|
|
'error_message': 'Parameter constraint violated: ' + param_name
|
|
})
|
|
|
|
def _parse_condition(self, condition: str) -> Callable[[Dict], bool]:
|
|
condition = condition.strip()
|
|
|
|
patterns = [
|
|
(r'^(\w+)\s*>\s*(\w+)$', lambda m, p: p.get(m.group(1), 0) > p.get(m.group(2), 0)),
|
|
(r'^(\w+)\s*<\s*(\w+)$', lambda m, p: p.get(m.group(1), 0) < p.get(m.group(2), 0)),
|
|
(r'^(\w+)\s*>=\s*(\w+)$', lambda m, p: p.get(m.group(1), 0) >= p.get(m.group(2), 0)),
|
|
(r'^(\w+)\s*<=\s*(\w+)$', lambda m, p: p.get(m.group(1), 0) <= p.get(m.group(2), 0)),
|
|
(r'^(\w+)\s*==\s*(\w+)$', lambda m, p: p.get(m.group(1), 0) == p.get(m.group(2), 0)),
|
|
(r'^(\w+)\s*!=\s*(\w+)$', lambda m, p: p.get(m.group(1), 0) != p.get(m.group(2), 0)),
|
|
(r'^(\w+)\s*>\s*(\d+)$', lambda m, p: p.get(m.group(1), 0) > int(m.group(2))),
|
|
(r'^(\w+)\s*<\s*(\d+)$', lambda m, p: p.get(m.group(1), 0) < int(m.group(2))),
|
|
]
|
|
|
|
for pattern, func in patterns:
|
|
match = re.match(pattern, condition)
|
|
if match:
|
|
return lambda params, m=match, f=func: f(m, params)
|
|
|
|
return lambda params: True
|
|
|
|
def _is_valid_combination(self, params: Dict) -> bool:
|
|
for constraint in self.constraints:
|
|
condition = constraint['condition']
|
|
if not condition:
|
|
continue
|
|
|
|
parse_func = self._parse_condition(condition)
|
|
if not parse_func(params):
|
|
return False
|
|
|
|
return True
|
|
|
|
def filter_valid_combinations(self, combinations: List[Dict]) -> List[Dict]:
|
|
valid = []
|
|
invalid_count = 0
|
|
for combo in combinations:
|
|
if self._is_valid_combination(combo):
|
|
valid.append(combo)
|
|
else:
|
|
invalid_count += 1
|
|
|
|
if invalid_count > 0:
|
|
print('Filtered ' + str(invalid_count) + ' invalid combinations')
|
|
|
|
return valid
|
|
|
|
def get_constraint_count(self) -> int:
|
|
return len(self.constraints)
|
|
|
|
|
|
def create_constraint_engine(ea_config) -> ParameterConstraintEngine:
|
|
engine = ParameterConstraintEngine()
|
|
|
|
for param_name, param in ea_config.parameters.items():
|
|
if param.condition:
|
|
engine.add_condition_from_config(param_name, param.condition)
|
|
|
|
return engine
|
|
|