Annotation Interface ShadowVariablesInconsistent


@Target({METHOD,FIELD}) @Retention(RUNTIME) public @interface ShadowVariablesInconsistent
Specifies that a boolean property (or field) of a PlanningEntity tracks if any of its supplier variables are inconsistent.

A supplier variable is inconsistent if:

  • One of its source variables include it as a source (for example, `a` depends on `b` and `b` depends on `a`).
  • One of its source variables is inconsistent (for example, `c` depends on `a`, which depends on `b`, and `b` depends on `a`).

Should be used in a filter for a hard Constraint to penalize inconsistent entities, since PlanningSolution with inconsistent entities are typically not valid.

There are three ways an inconsistency may be introduced:

  • Source-induced, when two declarative shadow variables' sources refer to each other:
     @PlanningEntity
     public class Entity {
         @ShadowVariable(supplierName = "variable1Supplier")
         String variable1;
    
         @ShadowVariable(supplierName = "variable2Supplier")
         String variable2;
    
         // ...
    
         @ShadowSources("variable2")
         String variable1Supplier() {
             // ...
         }
    
         @ShadowSources("variable1")
         String variable2Supplier() {
             // ...
         }
     }
     
  • Fact-induced, when a shadow variable has itself as a direct or transitive dependency via a fact:
     @PlanningEntity
     public class Entity {
         Entity dependency;
    
         @ShadowVariable(supplierName = "variableSupplier")
         String variable;
    
         @ShadowSources("dependency.variable")
         String variableSupplier() {
             // ...
         }
         // ...
     }
    
     Entity a = new Entity();
     Entity b = new Entity();
     a.setDependency(b);
     b.setDependency(a);
     // a depends on b, and b depends on a, which is invalid.
     
  • Variable-induced, when a shadow variable has itself as a direct or transitive dependency via a variable:
     @PlanningEntity
     public class Entity {
         Entity dependency;
    
         @PreviousElementShadowVariable()
         Entity previous;
    
         @ShadowVariable(supplierName = "variableSupplier")
         String variable;
    
         @ShadowSources({ "previous.variable", "dependency.variable" })
         String variableSupplier() {
             // ...
         }
         // ...
     }
    
     Entity a = new Entity();
     Entity b = new Entity();
     b.setDependency(a);
     a.setPrevious(b);
     // b depends on a via a fact, and a depends on b via a variable
     // The solver can break this loop by moving a after b.
     
Source-induced and fact-induced loops cannot be broken by the solver, and represents an issue in either the input problem or the domain model. The solver will fail-fast if it detects a source-induced or fact-induced loop.

Important: Do not use a ShadowVariablesInconsistent property in a method annotated with ShadowSources. ShadowSources marked methods do not need to check ShadowVariablesInconsistent properties, since they are only called if all their dependencies are consistent.