Skip to content

Commit f1f480d

Browse files
authored
refactor: move incremental back (#2256)
1 parent 9bf5ce4 commit f1f480d

20 files changed

Lines changed: 1179 additions & 110 deletions

File tree

.github/workflows/pull_request_secure.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ jobs:
118118
working-directory: ./timefold-solver-enterprise
119119
shell: bash
120120
env:
121-
TIMEFOLD_ENTERPRISE_LICENSE: ${{ secrets.TIMEFOLD_SOLVER_CI_PROD_LICENSE }}
121+
TIMEFOLD_LICENSE: ${{ secrets.TIMEFOLD_SOLVER_CI_PROD_LICENSE }}
122122
run: ./mvnw -B clean verify
123123
- name: Test Summary
124124
uses: test-summary/action@2920bc1b1b377c787227b204af6981e8f41bbef3

.github/workflows/release-changelog-template.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
_Timefold Solver Community Edition_ is an open source project, and you are more than welcome to contribute as well!
1313
For more, see [Contributing](https://github.com/TimefoldAI/timefold-solver/blob/main/CONTRIBUTING.adoc).
1414

15-
Should your business need to scale to truly massive data sets or require enterprise-grade support,
16-
check out [_Timefold Solver Enterprise Edition_](https://docs.timefold.ai/timefold-solver/latest/enterprise-edition/enterprise-edition).
17-
Enterprise Edition requires [a license](https://timefold.ai/pricing).
15+
Timefold also offers commercial editions of the solver, which include additional features such as explainability, the ability to scale out to the biggest datasets, and enterprise-grade support.
16+
Find out [which edition is right for you](https://licenses.timefold.ai/).
1817

1918
# How to use Timefold Solver
2019

README.adoc

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ image:https://img.shields.io/badge/Java-21+-brightgreen.svg?style=for-the-badge[
3535

3636
== Build from source
3737

38-
. Install JDK 21+ and Maven 3.9.11, for example with https://sdkman.io[Sdkman]:
38+
. Install JDK 21+ and Maven 3.9.11+, for example with https://sdkman.io[Sdkman]:
3939
+
4040
----
4141
$ sdk install java
@@ -61,25 +61,20 @@ $ ./mvnw clean install -Dquickly
6161
This is an open source project, and you are more than welcome to contribute!
6262
For more, see link:CONTRIBUTING.md[Contributing].
6363

64-
== Editions
6564

66-
There are two editions of Timefold Solver:
65+
== Editions
6766

68-
- _Timefold Solver Community Edition_ (this repo).
69-
- _Timefold Solver Enterprise Edition_, a https://timefold.ai/pricing[licensed version] of Timefold Solver.
67+
There are three editions of Timefold Solver:
7068

71-
=== Key Features of Timefold Solver Enterprise Edition
69+
- _Timefold Solver Community Edition_,
70+
- _Timefold Solver Plus_
71+
- and _Timefold Solver Enterprise_.
7272

73-
- **Multi-threaded Solving:** Experience enhanced performance with multi-threaded solving capabilities.
74-
- **Nearby Selection:** Get better solutions quicker, especially with spatial problems.
75-
- **Dedicated Support:** Get direct support from the Timefold team for all your questions and requirements.
73+
The Community Edition (this repo) is open-source and licensed under the Apache-2.0 license.
74+
The latter two are non-open-source commercial offerings and require a Timefold license to run.
7675

77-
=== Licensing and Usage
76+
https://licenses.timefold.ai/[See which edition is right for you.]
7877

79-
Unlike the Apache-2.0 licensed _Community Edition_ in this repo,
80-
the _Enterprise Edition_ is not open source.
81-
If you wish to use the Enterprise Edition in a production environment,
82-
please https://timefold.ai/contact[contact Timefold] to obtain the appropriate license.
8378

8479
== Legal notice
8580

@@ -91,5 +86,5 @@ which includes copyrights of the original creator, Red Hat Inc., affiliates, and
9186
that were all entirely licensed under the Apache-2.0 license.
9287
Every source file has been modified.
9388

94-
== Documentation icon libraries
89+
=== Documentation icon libraries
9590
- [tabler icons](https://tabler.io/icons) under [MIT license](https://docs.tabler.io/ui/getting-started/license)

core/src/main/java/ai/timefold/solver/core/api/score/calculator/AnalyzableIncrementalScoreCalculator.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
* Used for incremental java {@link Score} calculation with support for {@link ScoreAnalysis}
1111
* Any implementation is naturally stateful.
1212
* <p>
13-
* Note: Both incremental score calculation and score analysis are exclusive to Timefold Solver Enterprise Edition.
14-
* They are not available in the open-source version of Timefold Solver,
15-
* and attempts to use it without a valid license will throw exceptions at runtime.
13+
* Note: Explainability features are exclusive to Timefold Solver Enterprise Edition.
14+
* Implementing this interface in Community Edition may still bring benefits
15+
* in terms of score corruption analysis.
1616
*
1717
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
1818
* @param <Score_> the score type to go with the solution

core/src/main/java/ai/timefold/solver/core/api/score/calculator/ConstraintMatchRegistry.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import org.jspecify.annotations.NullMarked;
1111

1212
/**
13-
*
1413
* @param <Score_>
1514
* @see AnalyzableIncrementalScoreCalculator Adding explainability to incremental score calculator.
1615
*/

core/src/main/java/ai/timefold/solver/core/api/score/calculator/IncrementalScoreCalculator.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313
* This is much faster than {@link EasyScoreCalculator} but requires much more code to implement too.
1414
* <p>
1515
* Any implementation is naturally stateful.
16-
* <p>
17-
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition.
18-
* It is not available in the open-source version of Timefold Solver,
19-
* and attempts to use it without a valid license will throw exceptions at runtime.
2016
*
2117
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
2218
* @param <Score_> the score type to go with the solution

core/src/main/java/ai/timefold/solver/core/config/score/director/ScoreDirectorFactoryConfig.java

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -110,39 +110,19 @@ public void setConstraintStreamProfilingEnabled(Boolean constraintStreamProfilin
110110
this.constraintStreamProfilingEnabled = constraintStreamProfilingEnabled;
111111
}
112112

113-
/**
114-
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition
115-
* It is not available in the open-source version of Timefold Solver,
116-
* and attempts to use it without a valid license will throw an exception at runtime.
117-
*/
118113
public @Nullable Class<? extends IncrementalScoreCalculator> getIncrementalScoreCalculatorClass() {
119114
return incrementalScoreCalculatorClass;
120115
}
121116

122-
/**
123-
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition
124-
* It is not available in the open-source version of Timefold Solver,
125-
* and attempts to use it without a valid license will throw an exception at runtime.
126-
*/
127117
public void setIncrementalScoreCalculatorClass(
128118
@Nullable Class<? extends IncrementalScoreCalculator> incrementalScoreCalculatorClass) {
129119
this.incrementalScoreCalculatorClass = incrementalScoreCalculatorClass;
130120
}
131121

132-
/**
133-
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition
134-
* It is not available in the open-source version of Timefold Solver,
135-
* and attempts to use it without a valid license will throw an exception at runtime.
136-
*/
137122
public @Nullable Map<@NonNull String, @NonNull String> getIncrementalScoreCalculatorCustomProperties() {
138123
return incrementalScoreCalculatorCustomProperties;
139124
}
140125

141-
/**
142-
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition
143-
* It is not available in the open-source version of Timefold Solver,
144-
* and attempts to use it without a valid license will throw an exception at runtime.
145-
*/
146126
public void setIncrementalScoreCalculatorCustomProperties(
147127
@Nullable Map<@NonNull String, @NonNull String> incrementalScoreCalculatorCustomProperties) {
148128
this.incrementalScoreCalculatorCustomProperties = incrementalScoreCalculatorCustomProperties;
@@ -206,23 +186,13 @@ public void setAssertionScoreDirectorFactory(@Nullable ScoreDirectorFactoryConfi
206186
return this;
207187
}
208188

209-
/**
210-
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition
211-
* It is not available in the open-source version of Timefold Solver,
212-
* and attempts to use it without a valid license will throw an exception at runtime.
213-
*/
214189
public @NonNull ScoreDirectorFactoryConfig
215190
withIncrementalScoreCalculatorClass(
216191
@NonNull Class<? extends IncrementalScoreCalculator> incrementalScoreCalculatorClass) {
217192
this.incrementalScoreCalculatorClass = incrementalScoreCalculatorClass;
218193
return this;
219194
}
220195

221-
/**
222-
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition
223-
* It is not available in the open-source version of Timefold Solver,
224-
* and attempts to use it without a valid license will throw an exception at runtime.
225-
*/
226196
public @NonNull ScoreDirectorFactoryConfig
227197
withIncrementalScoreCalculatorCustomProperties(
228198
@NonNull Map<@NonNull String, @NonNull String> incrementalScoreCalculatorCustomProperties) {

core/src/main/java/ai/timefold/solver/core/enterprise/TimefoldSolverEnterpriseService.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,11 @@
2424
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListMultistageMoveSelectorConfig;
2525
import ai.timefold.solver.core.config.heuristic.selector.value.ValueSelectorConfig;
2626
import ai.timefold.solver.core.config.partitionedsearch.PartitionedSearchPhaseConfig;
27-
import ai.timefold.solver.core.config.score.director.ScoreDirectorFactoryConfig;
2827
import ai.timefold.solver.core.config.solver.EnvironmentMode;
2928
import ai.timefold.solver.core.impl.bavet.common.InnerConstraintProfiler;
3029
import ai.timefold.solver.core.impl.constructionheuristic.decider.ConstructionHeuristicDecider;
3130
import ai.timefold.solver.core.impl.constructionheuristic.decider.forager.ConstructionHeuristicForager;
3231
import ai.timefold.solver.core.impl.domain.entity.descriptor.EntityDescriptor;
33-
import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor;
3432
import ai.timefold.solver.core.impl.domain.variable.declarative.TopologicalOrderGraph;
3533
import ai.timefold.solver.core.impl.heuristic.HeuristicConfigPolicy;
3634
import ai.timefold.solver.core.impl.heuristic.selector.entity.EntitySelector;
@@ -46,7 +44,6 @@
4644
import ai.timefold.solver.core.impl.neighborhood.MoveRepository;
4745
import ai.timefold.solver.core.impl.partitionedsearch.PartitionedSearchPhase;
4846
import ai.timefold.solver.core.impl.score.constraint.ConstraintMatchTotal;
49-
import ai.timefold.solver.core.impl.score.director.AbstractScoreDirectorFactory;
5047
import ai.timefold.solver.core.impl.score.director.InnerScore;
5148
import ai.timefold.solver.core.impl.score.director.InnerScoreDirector;
5249
import ai.timefold.solver.core.impl.solver.DefaultSolverFactory;
@@ -68,7 +65,6 @@ final class InstanceCarrier {
6865
}
6966

7067
String COMMUNITY_NAME = "Timefold Solver Community Edition";
71-
String COMMUNITY_COORDINATES = "ai.timefold.solver:timefold-solver-core";
7268
String ENTERPRISE_NAME = "Timefold Solver Enterprise Edition";
7369
String ENTERPRISE_COORDINATES = "ai.timefold.solver.enterprise:timefold-solver-enterprise-core";
7470
String DEVELOPMENT_SNAPSHOT = "Development Snapshot";
@@ -118,19 +114,19 @@ static TimefoldSolverEnterpriseService loadOrFail(Feature feature) {
118114
return load();
119115
} catch (EnterpriseLicenseException cause) {
120116
throw new IllegalStateException("""
121-
No valid Timefold Enterprise License was found.
117+
No valid Timefold License was found.
122118
Please contact Timefold to obtain a valid license,
123119
or if you believe that this message was given in error.""", cause);
124120
} catch (EnterpriseProductException cause) {
125121
throw new IllegalStateException("""
126-
Valid Timefold Enterprise License was found, but it does not entitle you to run "%s".
122+
Valid Timefold License was found, but it does not entitle you to run "%s".
127123
Maybe %s.
128124
Please contact Timefold to obtain an applicable license,
129125
or if you believe that this message was given in error."""
130126
.formatted(feature.getName(), feature.getWorkaround()), cause);
131127
} catch (Exception cause) {
132128
throw new IllegalStateException("""
133-
A feature of Enterprise Edition "%s" was requested but it could not be loaded.
129+
A commercial feature "%s" was requested but it could not be loaded.
134130
Maybe add the %s dependency, or %s.
135131
Please contact Timefold to obtain an applicable license,
136132
or if you believe that this message was given in error."""
@@ -202,10 +198,6 @@ <Solution_> DestinationSelector<Solution_> applyNearbySelection(DestinationSelec
202198

203199
InnerConstraintProfiler buildConstraintProfiler();
204200

205-
<Solution_, Score_ extends Score<Score_>> AbstractScoreDirectorFactory<Solution_, Score_, ?>
206-
buildIncrementalScoreDirectorFactory(ScoreDirectorFactoryConfig config,
207-
SolutionDescriptor<Solution_> solutionDescriptor, EnvironmentMode environmentMode);
208-
209201
<Score_ extends Score<Score_>> ScoreAnalysis<Score_> analyze(InnerScore<Score_> state,
210202
Map<ConstraintRef, ConstraintMatchTotal<Score_>> constraintMatchTotalMap, ScoreAnalysisFetchPolicy fetchPolicy);
211203

@@ -227,9 +219,7 @@ enum Feature {
227219
"remove multistageMoveSelector and/or listMultistageMoveSelector from the solver configuration"),
228220
CONSTRAINT_PROFILING("Constraint profiling", "remove constraintStreamProfilingEnabled from the solver configuration"),
229221
SCORE_ANALYSIS("Score analysis", "do not use SolutionManager's analyze() method"),
230-
RECOMMENDATIONS("Recommendations", "do not use SolutionManager's recommendAssignment() method"),
231-
INCREMENTAL_SCORE_CALCULATOR("Incremental score calculator",
232-
"remove incrementalScoreCalculatorClass and incrementalScoreCalculatorCustomProperties from the solver configuration");
222+
RECOMMENDATIONS("Recommendations", "do not use SolutionManager's recommendAssignment() method");
233223

234224
private final String name;
235225
private final String workaround;

core/src/main/java/ai/timefold/solver/core/impl/score/director/ScoreDirectorFactoryFactory.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import ai.timefold.solver.core.config.score.director.ScoreDirectorFactoryConfig;
77
import ai.timefold.solver.core.config.score.trend.InitializingScoreTrendLevel;
88
import ai.timefold.solver.core.config.solver.EnvironmentMode;
9-
import ai.timefold.solver.core.enterprise.TimefoldSolverEnterpriseService;
109
import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor;
1110
import ai.timefold.solver.core.impl.score.director.easy.EasyScoreDirectorFactory;
11+
import ai.timefold.solver.core.impl.score.director.incremental.IncrementalScoreDirectorFactory;
1212
import ai.timefold.solver.core.impl.score.director.stream.BavetConstraintStreamScoreDirectorFactory;
1313
import ai.timefold.solver.core.impl.score.trend.InitializingScoreTrend;
1414

@@ -62,10 +62,7 @@ public ScoreDirectorFactory<Solution_, Score_> buildScoreDirectorFactory(Environ
6262
if (config.getEasyScoreCalculatorClass() != null) {
6363
return EasyScoreDirectorFactory.buildScoreDirectorFactory(solutionDescriptor, config, environmentMode);
6464
} else if (config.getIncrementalScoreCalculatorClass() != null) {
65-
var timefoldSolverEnterpriseService = TimefoldSolverEnterpriseService
66-
.loadOrFail(TimefoldSolverEnterpriseService.Feature.INCREMENTAL_SCORE_CALCULATOR);
67-
return timefoldSolverEnterpriseService.buildIncrementalScoreDirectorFactory(config, solutionDescriptor,
68-
environmentMode);
65+
return IncrementalScoreDirectorFactory.buildScoreDirectorFactory(solutionDescriptor, config, environmentMode);
6966
} else if (config.getConstraintProviderClass() != null) {
7067
return BavetConstraintStreamScoreDirectorFactory.buildScoreDirectorFactory(solutionDescriptor, config,
7168
environmentMode);

0 commit comments

Comments
 (0)