Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pull_request_secure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ jobs:
working-directory: ./timefold-solver-enterprise
shell: bash
env:
TIMEFOLD_ENTERPRISE_LICENSE: ${{ secrets.TIMEFOLD_SOLVER_CI_PROD_LICENSE }}
TIMEFOLD_LICENSE: ${{ secrets.TIMEFOLD_SOLVER_CI_PROD_LICENSE }}
run: ./mvnw -B clean verify
- name: Test Summary
uses: test-summary/action@2920bc1b1b377c787227b204af6981e8f41bbef3
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/release-changelog-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
_Timefold Solver Community Edition_ is an open source project, and you are more than welcome to contribute as well!
For more, see [Contributing](https://github.com/TimefoldAI/timefold-solver/blob/main/CONTRIBUTING.adoc).

Should your business need to scale to truly massive data sets or require enterprise-grade support,
check out [_Timefold Solver Enterprise Edition_](https://docs.timefold.ai/timefold-solver/latest/enterprise-edition/enterprise-edition).
Enterprise Edition requires [a license](https://timefold.ai/pricing).
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.
Find out [which edition is right for you](https://licenses.timefold.ai/).

# How to use Timefold Solver

Expand Down
25 changes: 10 additions & 15 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ image:https://img.shields.io/badge/Java-21+-brightgreen.svg?style=for-the-badge[

== Build from source

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

== Editions

There are two editions of Timefold Solver:
== Editions

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

=== Key Features of Timefold Solver Enterprise Edition
- _Timefold Solver Community Edition_,
- _Timefold Solver Plus_
- and _Timefold Solver Enterprise_.

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

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

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

== Legal notice

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

== Documentation icon libraries
=== Documentation icon libraries
- [tabler icons](https://tabler.io/icons) under [MIT license](https://docs.tabler.io/ui/getting-started/license)
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
* Used for incremental java {@link Score} calculation with support for {@link ScoreAnalysis}
* Any implementation is naturally stateful.
* <p>
* Note: Both incremental score calculation and score analysis are exclusive to Timefold Solver Enterprise Edition.
* They are not available in the open-source version of Timefold Solver,
* and attempts to use it without a valid license will throw exceptions at runtime.
* Note: Explainability features are exclusive to Timefold Solver Enterprise Edition.
Comment thread
triceo marked this conversation as resolved.
* Implementing this interface in Community Edition may still bring benefits
* in terms of score corruption analysis.
*
Comment thread
triceo marked this conversation as resolved.
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
* @param <Score_> the score type to go with the solution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.jspecify.annotations.NullMarked;

/**
*
* @param <Score_>
* @see AnalyzableIncrementalScoreCalculator Adding explainability to incremental score calculator.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@
* This is much faster than {@link EasyScoreCalculator} but requires much more code to implement too.
* <p>
* Any implementation is naturally stateful.
* <p>
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition.
* It is not available in the open-source version of Timefold Solver,
* and attempts to use it without a valid license will throw exceptions at runtime.
*
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
* @param <Score_> the score type to go with the solution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,39 +110,19 @@ public void setConstraintStreamProfilingEnabled(Boolean constraintStreamProfilin
this.constraintStreamProfilingEnabled = constraintStreamProfilingEnabled;
}

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

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

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

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

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

/**
* Note: Incremental score calculation is exclusive to Timefold Solver Enterprise Edition
* It is not available in the open-source version of Timefold Solver,
* and attempts to use it without a valid license will throw an exception at runtime.
*/
public @NonNull ScoreDirectorFactoryConfig
withIncrementalScoreCalculatorCustomProperties(
@NonNull Map<@NonNull String, @NonNull String> incrementalScoreCalculatorCustomProperties) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@
import ai.timefold.solver.core.config.heuristic.selector.move.generic.list.ListMultistageMoveSelectorConfig;
import ai.timefold.solver.core.config.heuristic.selector.value.ValueSelectorConfig;
import ai.timefold.solver.core.config.partitionedsearch.PartitionedSearchPhaseConfig;
import ai.timefold.solver.core.config.score.director.ScoreDirectorFactoryConfig;
import ai.timefold.solver.core.config.solver.EnvironmentMode;
import ai.timefold.solver.core.impl.bavet.common.InnerConstraintProfiler;
import ai.timefold.solver.core.impl.constructionheuristic.decider.ConstructionHeuristicDecider;
import ai.timefold.solver.core.impl.constructionheuristic.decider.forager.ConstructionHeuristicForager;
import ai.timefold.solver.core.impl.domain.entity.descriptor.EntityDescriptor;
import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor;
import ai.timefold.solver.core.impl.domain.variable.declarative.TopologicalOrderGraph;
import ai.timefold.solver.core.impl.heuristic.HeuristicConfigPolicy;
import ai.timefold.solver.core.impl.heuristic.selector.entity.EntitySelector;
Expand All @@ -46,7 +44,6 @@
import ai.timefold.solver.core.impl.neighborhood.MoveRepository;
import ai.timefold.solver.core.impl.partitionedsearch.PartitionedSearchPhase;
import ai.timefold.solver.core.impl.score.constraint.ConstraintMatchTotal;
import ai.timefold.solver.core.impl.score.director.AbstractScoreDirectorFactory;
import ai.timefold.solver.core.impl.score.director.InnerScore;
import ai.timefold.solver.core.impl.score.director.InnerScoreDirector;
import ai.timefold.solver.core.impl.solver.DefaultSolverFactory;
Expand All @@ -68,7 +65,6 @@ final class InstanceCarrier {
}

String COMMUNITY_NAME = "Timefold Solver Community Edition";
String COMMUNITY_COORDINATES = "ai.timefold.solver:timefold-solver-core";
String ENTERPRISE_NAME = "Timefold Solver Enterprise Edition";
String ENTERPRISE_COORDINATES = "ai.timefold.solver.enterprise:timefold-solver-enterprise-core";
String DEVELOPMENT_SNAPSHOT = "Development Snapshot";
Expand Down Expand Up @@ -118,19 +114,19 @@ static TimefoldSolverEnterpriseService loadOrFail(Feature feature) {
return load();
} catch (EnterpriseLicenseException cause) {
throw new IllegalStateException("""
No valid Timefold Enterprise License was found.
No valid Timefold License was found.
Please contact Timefold to obtain a valid license,
or if you believe that this message was given in error.""", cause);
} catch (EnterpriseProductException cause) {
throw new IllegalStateException("""
Valid Timefold Enterprise License was found, but it does not entitle you to run "%s".
Valid Timefold License was found, but it does not entitle you to run "%s".
Maybe %s.
Please contact Timefold to obtain an applicable license,
or if you believe that this message was given in error."""
.formatted(feature.getName(), feature.getWorkaround()), cause);
} catch (Exception cause) {
throw new IllegalStateException("""
A feature of Enterprise Edition "%s" was requested but it could not be loaded.
A commercial feature "%s" was requested but it could not be loaded.
Maybe add the %s dependency, or %s.
Please contact Timefold to obtain an applicable license,
or if you believe that this message was given in error."""
Expand Down Expand Up @@ -202,10 +198,6 @@ <Solution_> DestinationSelector<Solution_> applyNearbySelection(DestinationSelec

InnerConstraintProfiler buildConstraintProfiler();

<Solution_, Score_ extends Score<Score_>> AbstractScoreDirectorFactory<Solution_, Score_, ?>
buildIncrementalScoreDirectorFactory(ScoreDirectorFactoryConfig config,
SolutionDescriptor<Solution_> solutionDescriptor, EnvironmentMode environmentMode);

<Score_ extends Score<Score_>> ScoreAnalysis<Score_> analyze(InnerScore<Score_> state,
Map<ConstraintRef, ConstraintMatchTotal<Score_>> constraintMatchTotalMap, ScoreAnalysisFetchPolicy fetchPolicy);

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

private final String name;
private final String workaround;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import ai.timefold.solver.core.config.score.director.ScoreDirectorFactoryConfig;
import ai.timefold.solver.core.config.score.trend.InitializingScoreTrendLevel;
import ai.timefold.solver.core.config.solver.EnvironmentMode;
import ai.timefold.solver.core.enterprise.TimefoldSolverEnterpriseService;
import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor;
import ai.timefold.solver.core.impl.score.director.easy.EasyScoreDirectorFactory;
import ai.timefold.solver.core.impl.score.director.incremental.IncrementalScoreDirectorFactory;
import ai.timefold.solver.core.impl.score.director.stream.BavetConstraintStreamScoreDirectorFactory;
import ai.timefold.solver.core.impl.score.trend.InitializingScoreTrend;

Expand Down Expand Up @@ -62,10 +62,7 @@ public ScoreDirectorFactory<Solution_, Score_> buildScoreDirectorFactory(Environ
if (config.getEasyScoreCalculatorClass() != null) {
return EasyScoreDirectorFactory.buildScoreDirectorFactory(solutionDescriptor, config, environmentMode);
} else if (config.getIncrementalScoreCalculatorClass() != null) {
var timefoldSolverEnterpriseService = TimefoldSolverEnterpriseService
.loadOrFail(TimefoldSolverEnterpriseService.Feature.INCREMENTAL_SCORE_CALCULATOR);
return timefoldSolverEnterpriseService.buildIncrementalScoreDirectorFactory(config, solutionDescriptor,
environmentMode);
return IncrementalScoreDirectorFactory.buildScoreDirectorFactory(solutionDescriptor, config, environmentMode);
} else if (config.getConstraintProviderClass() != null) {
Comment thread
triceo marked this conversation as resolved.
return BavetConstraintStreamScoreDirectorFactory.buildScoreDirectorFactory(solutionDescriptor, config,
environmentMode);
Expand Down
Loading
Loading