Search code examples
pythonoptapy

How to define a constraint in OptaPy for a list of element


I have some difficult to create one of my constraint. The structure of my problem is something like this

class ToolFact:
    id : str
    type : str
    
@planning_entity
class SubObjectFact:
    id : str
    tool : ToolFact

@planning_entity
class ObjectFact:
    id : str
    sub_objects : list[SubObjectFact]
    

And I want a constraint that will do something like this

for each ObjectFact -> object
   for each SubOjectFact in object.sub_object -> sub_object 
       penalize if sub_object.tool is None 

But I can't find a way to do this with the constraint_factory. Does anyone know how please ?


Solution

  • This is how you would do it with constraint streams:

    from java.util import ArrayList
    
    def penalize_subs_without_tools(constraint_factory: ConstraintFactory):
        return constraint_factory.forEach(get_class(ObjectFact)) \
            .flattenLast(lambda fact: ArrayList(fact.sub_objects)) \
            .filter(lambda sub_object: sub_object.tool is None) \
            .penalize("SubObjectFact without tool", HardSoftScore.ONE_HARD)
    

    I will try to make it so the ArrayList is not necessary in a later version.