TimefoldAI / TimefoldAI/timefold-solver

VariableListener corruption: Impossible VariableListener corruption(-1hard)…but all shadow variables is the same …

Open
#370 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

process/needs triage
Dominant language
Java
Stars
1.8k
Forks
228
Avg merge
1d 13h
Merged PRs (30d)
46

Description

Describe the bug
I think I set the variable listener trigger order correctly, and defined a seemly correct constraint.but it told me I have a variable listener corruption.

To Reproduce

This is my Assign class
@PlanningEntity
public class Assign extends AbstractPersistable{

    @PlanningVariable(valueRangeProviderRefs = "customerList",nullable = true)
    protected Customer customer;

    @PlanningVariable(valueRangeProviderRefs = "serverStationList",nullable = true)
    protected ServerStation station;

    @PlanningVariable(valueRangeProviderRefs = "demandChoices",nullable = true)
    protected Long assignedDemand;

    ...
}
----------------------------
This is my Customer class
@PlanningEntity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Customer extends AbstractPersistable{
    
    protected long maxDemand;
    protected Location location;

    /**
     * 需求等级,对应服务站可服务等级。没确定上限,按越高越好
     */
    protected int demandLevel;

    @InverseRelationShadowVariable(sourceVariableName = "customer")
    @Schema(hidden = true)
    protected List<Assign> assignedStations=new ArrayList<>();

    @ShadowVariable(sourceEntityClass = Customer.class,sourceVariableName = "assignedStations",variableListenerClass = RemainingDemandListener.class)
    // @Schema(hidden = true)
    protected Long remainingDemand;

    …
}

There is also a ServerStation class (Omitted)

Now this is key parts in my RemainingDemandListener.class
@Override
    public void afterVariableChanged(ScoreDirector<FacilityLocationSolution> scoreDirector, Customer customer) {
        updateRemainingDemand(scoreDirector, customer);
    }

    private void updateRemainingDemand(ScoreDirector<FacilityLocationSolution> scoreDirector, Customer customer){
        // if(customer==null){
        //     return;
        // }
        
        long remainingDemand=customer.getMaxDemand();
        for (Assign assign : customer.getAssignedStations()) {
            if(assign.getStation()!=null && assign.getAssignedDemand()!=null){
                remainingDemand-=assign.getAssignedDemand();
            }
        }
        remainingDemand=remainingDemand<0?0:remainingDemand;
        scoreDirector.beforeVariableChanged(customer, "remainingDemand");
        customer.setRemainingDemand(remainingDemand);
        scoreDirector.afterVariableChanged(customer, "remainingDemand");
        
    }

Finally, my constraints about this variable:
Constraint noRestDemand(ConstraintFactory constraintFactory) {
        return constraintFactory.forEach(Customer.class)
                .filter(c->c.getRemainingDemand()!=0)
                .penalizeConfigurable()
                .asConstraint(FacilityLocationConstraintConfig.NO_REST_DEMAND);
    }

Environment

timefold 1.3:

Output of java -version:17

Output of uname -a or ver:

Additional information

Provide any and all other information which might be relevant to the issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the corruption with the provided Assign and Customer planning entities and the RemainingDemandListener implementation. Inspect the shadow-variable declaration, listener trigger order, and the before/after notifications around remainingDemand, then compare the reproduced failure with the reported corruption message. Done means the supplied model no longer reports variable-listener corruption, or the issue has a documented minimal cause and reproduction.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
ai
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.