Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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