11package ai .timefold .solver .core .impl .domain .variable .declarative ;
22
33import java .util .ArrayList ;
4- import java .util .Collections ;
54import java .util .HashMap ;
65import java .util .LinkedHashSet ;
76import java .util .List ;
@@ -41,33 +40,34 @@ public static <Solution_> VariableReferenceGraph<Solution_> buildGraph(
4140 }
4241 var variableIdToUpdater = new HashMap <VariableMetaModel <?, ?, ?>, VariableUpdaterInfo <Solution_ >>();
4342
43+ // Create graph node for each entity/declarative shadow variable pair.
4444 // Maps a variable id to it source aliases;
4545 // For instance, "previousVisit.startTime" is a source alias of "startTime"
4646 // One way to view this concept is "previousVisit.startTime" is a pointer
4747 // to "startTime" of some visit, and thus alias it.
48- Map <VariableMetaModel <?, ?, ?>, Set <VariableSourceReference >> declarativeShadowVariableToAliasMap = new HashMap <>();
49-
50- // Create graph node for each entity/declarative shadow variable pair
51- createGraphNodes (variableReferenceGraphBuilder , entities , declarativeShadowVariableDescriptors , variableIdToUpdater ,
52- declarativeShadowVariableToAliasMap );
48+ var declarativeShadowVariableToAliasMap = createGraphNodes (variableReferenceGraphBuilder , entities ,
49+ declarativeShadowVariableDescriptors , variableIdToUpdater );
5350
5451 // Create variable processors for each declarative shadow variable descriptor
5552 for (var declarativeShadowVariable : declarativeShadowVariableDescriptors ) {
56- final var fromVariableId = declarativeShadowVariable .getVariableMetaModel ();
53+ var fromVariableId = declarativeShadowVariable .getVariableMetaModel ();
5754 createSourceChangeProcessors (variableReferenceGraphBuilder , declarativeShadowVariable , fromVariableId );
58- createAliasToVariableChangeProcessors (variableReferenceGraphBuilder , declarativeShadowVariableToAliasMap ,
59- fromVariableId );
55+ var aliasSet = declarativeShadowVariableToAliasMap .get (fromVariableId );
56+ if (aliasSet != null ) {
57+ createAliasToVariableChangeProcessors (variableReferenceGraphBuilder , aliasSet , fromVariableId );
58+ }
6059 }
6160
6261 // Create the fixed edges in the graph
6362 createFixedVariableRelationEdges (variableReferenceGraphBuilder , entities , declarativeShadowVariableDescriptors );
6463 return variableReferenceGraphBuilder .build (graphCreator );
6564 }
6665
67- private static <Solution_ > void createGraphNodes (VariableReferenceGraphBuilder <Solution_ > graph , Object [] entities ,
66+ private static <Solution_ > Map <VariableMetaModel <?, ?, ?>, Set <VariableSourceReference >> createGraphNodes (
67+ VariableReferenceGraphBuilder <Solution_ > graph , Object [] entities ,
6868 List <DeclarativeShadowVariableDescriptor <Solution_ >> declarativeShadowVariableDescriptors ,
69- Map <VariableMetaModel <?, ?, ?>, VariableUpdaterInfo <Solution_ >> variableIdToUpdater ,
70- Map <VariableMetaModel <?, ?, ?>, Set <VariableSourceReference >> declarativeShadowVariableToAliasMap ) {
69+ Map <VariableMetaModel <?, ?, ?>, VariableUpdaterInfo <Solution_ >> variableIdToUpdater ) {
70+ var result = new HashMap <VariableMetaModel <?, ?, ?>, Set <VariableSourceReference >>();
7171 for (var entity : entities ) {
7272 for (var declarativeShadowVariableDescriptor : declarativeShadowVariableDescriptors ) {
7373 var entityClass = declarativeShadowVariableDescriptor .getEntityDescriptor ().getEntityClass ();
@@ -83,16 +83,16 @@ private static <Solution_> void createGraphNodes(VariableReferenceGraphBuilder<S
8383 for (var sourceRoot : declarativeShadowVariableDescriptor .getSources ()) {
8484 for (var source : sourceRoot .variableSourceReferences ()) {
8585 if (source .downstreamDeclarativeVariableMetamodel () != null ) {
86- declarativeShadowVariableToAliasMap
87- .computeIfAbsent (source .downstreamDeclarativeVariableMetamodel (),
88- ignored -> new LinkedHashSet <>())
86+ result .computeIfAbsent (source .downstreamDeclarativeVariableMetamodel (),
87+ ignored -> new LinkedHashSet <>())
8988 .add (source );
9089 }
9190 }
9291 }
9392 }
9493 }
9594 }
95+ return result ;
9696 }
9797
9898 private static <Solution_ > void createSourceChangeProcessors (
@@ -127,44 +127,50 @@ private static <Solution_> void createSourceChangeProcessors(
127127 }
128128
129129 private static <Solution_ > void createAliasToVariableChangeProcessors (
130- VariableReferenceGraphBuilder <Solution_ > variableReferenceGraphBuilder ,
131- Map <VariableMetaModel <?, ?, ?>, Set <VariableSourceReference >> declarativeShadowVariableToAliasMap ,
130+ VariableReferenceGraphBuilder <Solution_ > variableReferenceGraphBuilder , Set <VariableSourceReference > aliasSet ,
132131 VariableMetaModel <Solution_ , ?, ?> fromVariableId ) {
133- for (var alias : declarativeShadowVariableToAliasMap . getOrDefault ( fromVariableId , Collections . emptySet ()) ) {
132+ for (var alias : aliasSet ) {
134133 var toVariableId = alias .targetVariableMetamodel ();
135134 var sourceVariableId = alias .variableMetaModel ();
136135
137136 if (!alias .isDeclarative () && alias .affectGraphEdges ()) {
138137 // Exploit the same fact as above
139138 variableReferenceGraphBuilder .addBeforeProcessor (sourceVariableId ,
140- (graph , toEntity ) -> alias .targetEntityFunctionStartingFromVariableEntity ()
141- .accept (toEntity , fromEntity -> {
142- // from/to can be null in extended models
143- // ex: previous is used as a source, but only an extended class
144- // has the to variable
145- var from = graph .lookupOrNull (fromVariableId , fromEntity );
146- if (from == null ) {
147- return ;
148- }
149- var to = graph .lookupOrNull (toVariableId , toEntity );
150- if (to == null ) {
151- return ;
152- }
153- graph .removeEdge (from , to );
154- }));
139+ (graph , toEntity ) -> {
140+ // from/to can be null in extended models
141+ // ex: previous is used as a source, but only an extended class
142+ // has the to variable
143+ var to = graph .lookupOrNull (toVariableId , toEntity );
144+ if (to == null ) {
145+ return ;
146+ }
147+ var fromEntity = alias .targetEntityFunctionStartingFromVariableEntity ()
148+ .apply (toEntity );
149+ if (fromEntity == null ) {
150+ return ;
151+ }
152+ var from = graph .lookupOrNull (fromVariableId , fromEntity );
153+ if (from == null ) {
154+ return ;
155+ }
156+ graph .removeEdge (from , to );
157+ });
155158 variableReferenceGraphBuilder .addAfterProcessor (sourceVariableId ,
156- (graph , toEntity ) -> alias .targetEntityFunctionStartingFromVariableEntity ()
157- .accept (toEntity , fromEntity -> {
158- var from = graph .lookupOrNull (fromVariableId , fromEntity );
159- if (from == null ) {
160- return ;
161- }
162- var to = graph .lookupOrNull (toVariableId , toEntity );
163- if (to == null ) {
164- return ;
165- }
166- graph .addEdge (from , to );
167- }));
159+ (graph , toEntity ) -> {
160+ var to = graph .lookupOrNull (toVariableId , toEntity );
161+ if (to == null ) {
162+ return ;
163+ }
164+ var fromEntity = alias .findTargetEntity (toEntity );
165+ if (fromEntity == null ) {
166+ return ;
167+ }
168+ var from = graph .lookupOrNull (fromVariableId , fromEntity );
169+ if (from == null ) {
170+ return ;
171+ }
172+ graph .addEdge (from , to );
173+ });
168174 }
169175 // Note: it is impossible to have a declarative variable affect graph edges,
170176 // since accessing a declarative variable from another declarative variable is prohibited.
@@ -178,21 +184,21 @@ private static <Solution_> void createFixedVariableRelationEdges(
178184 for (var entity : entities ) {
179185 for (var declarativeShadowVariableDescriptor : declarativeShadowVariableDescriptors ) {
180186 var entityClass = declarativeShadowVariableDescriptor .getEntityDescriptor ().getEntityClass ();
181- if (entityClass .isInstance (entity )) {
182- var toVariableId = declarativeShadowVariableDescriptor . getVariableMetaModel () ;
183- for ( var sourceRoot : declarativeShadowVariableDescriptor . getSources ()) {
184- for ( var source : sourceRoot . variableSourceReferences ()) {
185- if ( source . isTopLevel () && source . isDeclarative ()) {
186- var fromVariableId = source . variableMetaModel ();
187-
188- sourceRoot . valueEntityFunction ()
189- . accept ( entity , fromEntity -> variableReferenceGraphBuilder . addFixedEdge (
190- variableReferenceGraphBuilder
191- . lookupOrError ( fromVariableId , fromEntity ),
192- variableReferenceGraphBuilder
193- . lookupOrError ( toVariableId , entity )) );
194- break ;
195- }
187+ if (! entityClass .isInstance (entity )) {
188+ continue ;
189+ }
190+ var toVariableId = declarativeShadowVariableDescriptor . getVariableMetaModel ();
191+ var to = variableReferenceGraphBuilder . lookupOrError ( toVariableId , entity );
192+ for ( var sourceRoot : declarativeShadowVariableDescriptor . getSources ()) {
193+ for ( var source : sourceRoot . variableSourceReferences ()) {
194+ if ( source . isTopLevel () && source . isDeclarative ()) {
195+ var fromVariableId = source . variableMetaModel ();
196+ sourceRoot . valueEntityFunction ()
197+ . accept ( entity , fromEntity -> {
198+ var from = variableReferenceGraphBuilder . lookupOrError ( fromVariableId , fromEntity );
199+ variableReferenceGraphBuilder . addFixedEdge ( from , to );
200+ }) ;
201+ break ;
196202 }
197203 }
198204 }
0 commit comments