diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/DefaultShadowVariableSessionFactory.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/DefaultShadowVariableSessionFactory.java index b9b010c004..14fb214bd8 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/DefaultShadowVariableSessionFactory.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/DefaultShadowVariableSessionFactory.java @@ -61,7 +61,7 @@ yield buildSingleDirectionalParentGraph(solutionDescriptor, graphStructureAndDirection, entities); } - case ARBITRARY_SINGLE_ENTITY_SINGLE_DIRECTIONAL_PARENT_TYPE -> + case ARBITRARY_SINGLE_ENTITY_AT_MOST_ONE_DIRECTIONAL_PARENT_TYPE -> buildArbitrarySingleEntityGraph(solutionDescriptor, variableReferenceGraphBuilder, entities, graphCreator); case NO_DYNAMIC_EDGES, ARBITRARY -> buildArbitraryGraph(solutionDescriptor, variableReferenceGraphBuilder, entities, graphCreator); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/GraphStructure.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/GraphStructure.java index d25afeecbe..ca3d3e4df2 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/GraphStructure.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/GraphStructure.java @@ -42,7 +42,7 @@ public enum GraphStructure { * entity that uses declarative shadow variables with all directional * parents being the same type. */ - ARBITRARY_SINGLE_ENTITY_SINGLE_DIRECTIONAL_PARENT_TYPE, + ARBITRARY_SINGLE_ENTITY_AT_MOST_ONE_DIRECTIONAL_PARENT_TYPE, /** * A graph structure that accepts all graphs. @@ -73,7 +73,7 @@ public static GraphStructureAndDirection determineGraphStructure( .distinct().count() > 1; final var arbitraryGraphStructure = new GraphStructureAndDirection( - multipleDeclarativeEntityClasses ? ARBITRARY : ARBITRARY_SINGLE_ENTITY_SINGLE_DIRECTIONAL_PARENT_TYPE, + multipleDeclarativeEntityClasses ? ARBITRARY : ARBITRARY_SINGLE_ENTITY_AT_MOST_ONE_DIRECTIONAL_PARENT_TYPE, null, null); var rootVariableSources = declarativeShadowVariableDescriptors.stream() diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/RootVariableSource.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/RootVariableSource.java index 6822a1d2d7..39fe27fc8c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/RootVariableSource.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/declarative/RootVariableSource.java @@ -192,7 +192,7 @@ public static RootVariableSource from( assertIsValidVariableReference(rootEntityClass, variablePath, variableSourceReference); } - if (parentVariableType != ParentVariableType.GROUP && variableSourceReferences.size() == 1) { + if (!parentVariableType.isIndirect() && variableSourceReferences.size() == 1) { // No variables are accessed from the parent, so there no // parent variable. parentVariableType = ParentVariableType.NO_PARENT; diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/variable/declarative/GraphStructureTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/variable/declarative/GraphStructureTest.java index 0ad5504fa8..0d8035bc46 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/variable/declarative/GraphStructureTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/variable/declarative/GraphStructureTest.java @@ -1,9 +1,8 @@ package ai.timefold.solver.core.impl.domain.variable.declarative; import static ai.timefold.solver.core.impl.domain.variable.declarative.GraphStructure.ARBITRARY; -import static ai.timefold.solver.core.impl.domain.variable.declarative.GraphStructure.ARBITRARY_SINGLE_ENTITY_SINGLE_DIRECTIONAL_PARENT_TYPE; +import static ai.timefold.solver.core.impl.domain.variable.declarative.GraphStructure.ARBITRARY_SINGLE_ENTITY_AT_MOST_ONE_DIRECTIONAL_PARENT_TYPE; import static ai.timefold.solver.core.impl.domain.variable.declarative.GraphStructure.EMPTY; -import static ai.timefold.solver.core.impl.domain.variable.declarative.GraphStructure.NO_DYNAMIC_EDGES; import static ai.timefold.solver.core.impl.domain.variable.declarative.GraphStructure.SINGLE_DIRECTIONAL_PARENT; import static org.assertj.core.api.Assertions.assertThat; @@ -53,7 +52,7 @@ void simpleChainedStructure() { var entity = new TestdataChainedSimpleVarValue(); assertThat(GraphStructure.determineGraphStructure( TestdataChainedSimpleVarSolution.buildSolutionDescriptor(), entity)) - .hasFieldOrPropertyWithValue("structure", ARBITRARY_SINGLE_ENTITY_SINGLE_DIRECTIONAL_PARENT_TYPE); + .hasFieldOrPropertyWithValue("structure", ARBITRARY_SINGLE_ENTITY_AT_MOST_ONE_DIRECTIONAL_PARENT_TYPE); } @Test @@ -94,7 +93,7 @@ void concurrentValuesStructureWithGroups() { assertThat(GraphStructure.determineGraphStructure( TestdataConcurrentSolution.buildSolutionDescriptor(), value1, value2)) - .hasFieldOrPropertyWithValue("structure", ARBITRARY_SINGLE_ENTITY_SINGLE_DIRECTIONAL_PARENT_TYPE); + .hasFieldOrPropertyWithValue("structure", ARBITRARY_SINGLE_ENTITY_AT_MOST_ONE_DIRECTIONAL_PARENT_TYPE); } @Test @@ -102,7 +101,7 @@ void followerStructure() { var entity = new TestdataFollowerEntity(); assertThat(GraphStructure.determineGraphStructure( TestdataFollowerSolution.buildSolutionDescriptor(), entity)) - .hasFieldOrPropertyWithValue("structure", NO_DYNAMIC_EDGES); + .hasFieldOrPropertyWithValue("structure", ARBITRARY_SINGLE_ENTITY_AT_MOST_ONE_DIRECTIONAL_PARENT_TYPE); } @Test diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/variable/declarative/RootVariableSourceTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/variable/declarative/RootVariableSourceTest.java index ba760c92f6..7652d290df 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/variable/declarative/RootVariableSourceTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/variable/declarative/RootVariableSourceTest.java @@ -78,6 +78,7 @@ void pathUsingBuiltinShadow() { assertThat(rootVariableSource.rootEntity()).isEqualTo(TestdataInvalidDeclarativeValue.class); assertThat(rootVariableSource.variableSourceReferences()).hasSize(1); + assertThat(rootVariableSource.parentVariableType()).isEqualTo(ParentVariableType.NO_PARENT); var source = rootVariableSource.variableSourceReferences().get(0); assertEmptyChainToVariableEntity(source); @@ -112,6 +113,7 @@ void pathUsingDeclarativeShadow() { assertThat(rootVariableSource.rootEntity()).isEqualTo(TestdataInvalidDeclarativeValue.class); assertThat(rootVariableSource.variableSourceReferences()).hasSize(1); + assertThat(rootVariableSource.parentVariableType()).isEqualTo(ParentVariableType.NO_PARENT); var source = rootVariableSource.variableSourceReferences().get(0); assertEmptyChainToVariableEntity(source); @@ -145,6 +147,7 @@ void pathUsingDeclarativeShadowAfterGroup() { assertThat(rootVariableSource.rootEntity()).isEqualTo(TestdataInvalidDeclarativeValue.class); assertThat(rootVariableSource.variableSourceReferences()).hasSize(1); + assertThat(rootVariableSource.parentVariableType()).isEqualTo(ParentVariableType.GROUP); var source = rootVariableSource.variableSourceReferences().get(0); assertEmptyChainToVariableEntity(source); @@ -183,6 +186,7 @@ void pathUsingBuiltinShadowAfterGroup() { assertThat(rootVariableSource.rootEntity()).isEqualTo(TestdataInvalidDeclarativeValue.class); assertThat(rootVariableSource.variableSourceReferences()).hasSize(1); + assertThat(rootVariableSource.parentVariableType()).isEqualTo(ParentVariableType.GROUP); var source = rootVariableSource.variableSourceReferences().get(0); assertEmptyChainToVariableEntity(source); @@ -221,6 +225,7 @@ void pathUsingDeclarativeShadowAfterGroupAfterFact() { assertThat(rootVariableSource.rootEntity()).isEqualTo(TestdataInvalidDeclarativeValue.class); assertThat(rootVariableSource.variableSourceReferences()).hasSize(1); + assertThat(rootVariableSource.parentVariableType()).isEqualTo(ParentVariableType.GROUP); var source = rootVariableSource.variableSourceReferences().get(0); assertEmptyChainToVariableEntity(source); @@ -261,6 +266,7 @@ void pathUsingDeclarativeShadowAfterBuiltinShadow() { assertThat(rootVariableSource.rootEntity()).isEqualTo(TestdataInvalidDeclarativeValue.class); assertThat(rootVariableSource.variableSourceReferences()).hasSize(2); + assertThat(rootVariableSource.parentVariableType()).isEqualTo(ParentVariableType.PREVIOUS); var previousSource = rootVariableSource.variableSourceReferences().get(0); assertEmptyChainToVariableEntity(previousSource); @@ -305,6 +311,7 @@ void pathUsingBuiltinShadowAfterFact() { assertThat(rootVariableSource.rootEntity()).isEqualTo(TestdataInvalidDeclarativeValue.class); assertThat(rootVariableSource.variableSourceReferences()).hasSize(1); + assertThat(rootVariableSource.parentVariableType()).isEqualTo(ParentVariableType.INDIRECT); var previousSource = rootVariableSource.variableSourceReferences().get(0); assertChainToVariableEntity(previousSource, "fact"); @@ -344,6 +351,7 @@ void pathUsingDeclarativeShadowAfterBuiltinShadowAfterGroup() { assertThat(rootVariableSource.rootEntity()).isEqualTo(TestdataInvalidDeclarativeValue.class); assertThat(rootVariableSource.variableSourceReferences()).hasSize(2); + assertThat(rootVariableSource.parentVariableType()).isEqualTo(ParentVariableType.GROUP); var previousSource = rootVariableSource.variableSourceReferences().get(0); assertEmptyChainToVariableEntity(previousSource);