Skip to content
This repository was archived by the owner on Jul 17, 2024. It is now read-only.

Commit e6bb0f7

Browse files
chore: Use long scores types instead of int scores (#96)
The score types Timefold solver supports are: - int - long - BigDecimal Techically speaking, Python int's have unlimited width, so only a BigDecimal would hold them all. Using long score types should be enough for now.
1 parent 13c1a9c commit e6bb0f7

13 files changed

+297
-180
lines changed

Diff for: tests/test_constraint_streams.py

+25
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,31 @@ def define_constraints(constraint_factory: ConstraintFactory):
558558
assert len(justifications) == 0
559559

560560

561+
def test_long_scores():
562+
@constraint_provider
563+
def define_constraints(constraint_factory: ConstraintFactory):
564+
return [
565+
constraint_factory.for_each(Entity)
566+
.reward(SimpleScore.ONE, lambda e: e.value.number)
567+
.as_constraint('Maximize value')
568+
]
569+
570+
score_manager = create_score_manager(define_constraints)
571+
entity_a: Entity = Entity('A')
572+
entity_b: Entity = Entity('B')
573+
574+
# Overflow an int
575+
value_1 = Value(3_000_000_000)
576+
value_2 = Value(6_000_000_000)
577+
578+
entity_a.value = value_1
579+
entity_b.value = value_2
580+
581+
problem = Solution([entity_a, entity_b], [value_1, value_2])
582+
583+
assert score_manager.explain(problem).score == SimpleScore.of(9_000_000_000)
584+
585+
561586
ignored_python_functions = {
562587
'_call_comparison_java_joiner',
563588
'__init__',

Diff for: timefold-solver-python-core/src/main/java/ai/timefold/solver/python/score/BendableScorePythonJavaTypeMapping.java

+14-14
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
import ai.timefold.jpyinterpreter.types.PythonLikeType;
1010
import ai.timefold.jpyinterpreter.types.collections.PythonLikeTuple;
1111
import ai.timefold.jpyinterpreter.types.numeric.PythonInteger;
12-
import ai.timefold.solver.core.api.score.buildin.bendable.BendableScore;
12+
import ai.timefold.solver.core.api.score.buildin.bendablelong.BendableLongScore;
1313

14-
public final class BendableScorePythonJavaTypeMapping implements PythonJavaTypeMapping<PythonLikeObject, BendableScore> {
14+
public final class BendableScorePythonJavaTypeMapping implements PythonJavaTypeMapping<PythonLikeObject, BendableLongScore> {
1515
private final PythonLikeType type;
1616
private final Constructor<?> constructor;
1717
private final Field initScoreField;
@@ -34,20 +34,20 @@ public PythonLikeType getPythonType() {
3434
}
3535

3636
@Override
37-
public Class<? extends BendableScore> getJavaType() {
38-
return BendableScore.class;
37+
public Class<? extends BendableLongScore> getJavaType() {
38+
return BendableLongScore.class;
3939
}
4040

41-
private static PythonLikeTuple<PythonInteger> toPythonList(int[] scores) {
41+
private static PythonLikeTuple<PythonInteger> toPythonList(long[] scores) {
4242
PythonLikeTuple<PythonInteger> out = new PythonLikeTuple<>();
43-
for (int score : scores) {
43+
for (long score : scores) {
4444
out.add(PythonInteger.valueOf(score));
4545
}
4646
return out;
4747
}
4848

4949
@Override
50-
public PythonLikeObject toPythonObject(BendableScore javaObject) {
50+
public PythonLikeObject toPythonObject(BendableLongScore javaObject) {
5151
try {
5252
var instance = constructor.newInstance();
5353
initScoreField.set(instance, PythonInteger.valueOf(javaObject.initScore()));
@@ -60,23 +60,23 @@ public PythonLikeObject toPythonObject(BendableScore javaObject) {
6060
}
6161

6262
@Override
63-
public BendableScore toJavaObject(PythonLikeObject pythonObject) {
63+
public BendableLongScore toJavaObject(PythonLikeObject pythonObject) {
6464
try {
6565
var initScore = ((PythonInteger) initScoreField.get(pythonObject)).value.intValue();
6666
var hardScoreTuple = ((PythonLikeTuple) hardScoresField.get(pythonObject));
6767
var softScoreTuple = ((PythonLikeTuple) softScoresField.get(pythonObject));
68-
int[] hardScores = new int[hardScoreTuple.size()];
69-
int[] softScores = new int[softScoreTuple.size()];
68+
long[] hardScores = new long[hardScoreTuple.size()];
69+
long[] softScores = new long[softScoreTuple.size()];
7070
for (int i = 0; i < hardScores.length; i++) {
71-
hardScores[i] = ((PythonInteger) hardScoreTuple.get(i)).value.intValue();
71+
hardScores[i] = ((PythonInteger) hardScoreTuple.get(i)).value.longValue();
7272
}
7373
for (int i = 0; i < softScores.length; i++) {
74-
softScores[i] = ((PythonInteger) softScoreTuple.get(i)).value.intValue();
74+
softScores[i] = ((PythonInteger) softScoreTuple.get(i)).value.longValue();
7575
}
7676
if (initScore == 0) {
77-
return BendableScore.of(hardScores, softScores);
77+
return BendableLongScore.of(hardScores, softScores);
7878
} else {
79-
return BendableScore.ofUninitialized(initScore, hardScores, softScores);
79+
return BendableLongScore.ofUninitialized(initScore, hardScores, softScores);
8080
}
8181
} catch (IllegalAccessException e) {
8282
throw new RuntimeException(e);

Diff for: timefold-solver-python-core/src/main/java/ai/timefold/solver/python/score/HardMediumSoftScorePythonJavaTypeMapping.java

+11-11
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
import ai.timefold.jpyinterpreter.types.PythonJavaTypeMapping;
99
import ai.timefold.jpyinterpreter.types.PythonLikeType;
1010
import ai.timefold.jpyinterpreter.types.numeric.PythonInteger;
11-
import ai.timefold.solver.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore;
11+
import ai.timefold.solver.core.api.score.buildin.hardmediumsoftlong.HardMediumSoftLongScore;
1212

1313
public final class HardMediumSoftScorePythonJavaTypeMapping
14-
implements PythonJavaTypeMapping<PythonLikeObject, HardMediumSoftScore> {
14+
implements PythonJavaTypeMapping<PythonLikeObject, HardMediumSoftLongScore> {
1515
private final PythonLikeType type;
1616
private final Constructor<?> constructor;
1717
private final Field initScoreField;
@@ -36,12 +36,12 @@ public PythonLikeType getPythonType() {
3636
}
3737

3838
@Override
39-
public Class<? extends HardMediumSoftScore> getJavaType() {
40-
return HardMediumSoftScore.class;
39+
public Class<? extends HardMediumSoftLongScore> getJavaType() {
40+
return HardMediumSoftLongScore.class;
4141
}
4242

4343
@Override
44-
public PythonLikeObject toPythonObject(HardMediumSoftScore javaObject) {
44+
public PythonLikeObject toPythonObject(HardMediumSoftLongScore javaObject) {
4545
try {
4646
var instance = constructor.newInstance();
4747
initScoreField.set(instance, PythonInteger.valueOf(javaObject.initScore()));
@@ -55,16 +55,16 @@ public PythonLikeObject toPythonObject(HardMediumSoftScore javaObject) {
5555
}
5656

5757
@Override
58-
public HardMediumSoftScore toJavaObject(PythonLikeObject pythonObject) {
58+
public HardMediumSoftLongScore toJavaObject(PythonLikeObject pythonObject) {
5959
try {
6060
var initScore = ((PythonInteger) initScoreField.get(pythonObject)).value.intValue();
61-
var hardScore = ((PythonInteger) hardScoreField.get(pythonObject)).value.intValue();
62-
var mediumScore = ((PythonInteger) mediumScoreField.get(pythonObject)).value.intValue();
63-
var softScore = ((PythonInteger) softScoreField.get(pythonObject)).value.intValue();
61+
var hardScore = ((PythonInteger) hardScoreField.get(pythonObject)).value.longValue();
62+
var mediumScore = ((PythonInteger) mediumScoreField.get(pythonObject)).value.longValue();
63+
var softScore = ((PythonInteger) softScoreField.get(pythonObject)).value.longValue();
6464
if (initScore == 0) {
65-
return HardMediumSoftScore.of(hardScore, mediumScore, softScore);
65+
return HardMediumSoftLongScore.of(hardScore, mediumScore, softScore);
6666
} else {
67-
return HardMediumSoftScore.ofUninitialized(initScore, hardScore, mediumScore, softScore);
67+
return HardMediumSoftLongScore.ofUninitialized(initScore, hardScore, mediumScore, softScore);
6868
}
6969
} catch (IllegalAccessException e) {
7070
throw new RuntimeException(e);

Diff for: timefold-solver-python-core/src/main/java/ai/timefold/solver/python/score/HardSoftScorePythonJavaTypeMapping.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
import ai.timefold.jpyinterpreter.types.PythonJavaTypeMapping;
99
import ai.timefold.jpyinterpreter.types.PythonLikeType;
1010
import ai.timefold.jpyinterpreter.types.numeric.PythonInteger;
11-
import ai.timefold.solver.core.api.score.buildin.hardsoft.HardSoftScore;
11+
import ai.timefold.solver.core.api.score.buildin.hardsoftlong.HardSoftLongScore;
1212

13-
public final class HardSoftScorePythonJavaTypeMapping implements PythonJavaTypeMapping<PythonLikeObject, HardSoftScore> {
13+
public final class HardSoftScorePythonJavaTypeMapping implements PythonJavaTypeMapping<PythonLikeObject, HardSoftLongScore> {
1414
private final PythonLikeType type;
1515
private final Constructor<?> constructor;
1616
private final Field initScoreField;
@@ -33,12 +33,12 @@ public PythonLikeType getPythonType() {
3333
}
3434

3535
@Override
36-
public Class<? extends HardSoftScore> getJavaType() {
37-
return HardSoftScore.class;
36+
public Class<? extends HardSoftLongScore> getJavaType() {
37+
return HardSoftLongScore.class;
3838
}
3939

4040
@Override
41-
public PythonLikeObject toPythonObject(HardSoftScore javaObject) {
41+
public PythonLikeObject toPythonObject(HardSoftLongScore javaObject) {
4242
try {
4343
var instance = constructor.newInstance();
4444
initScoreField.set(instance, PythonInteger.valueOf(javaObject.initScore()));
@@ -51,15 +51,15 @@ public PythonLikeObject toPythonObject(HardSoftScore javaObject) {
5151
}
5252

5353
@Override
54-
public HardSoftScore toJavaObject(PythonLikeObject pythonObject) {
54+
public HardSoftLongScore toJavaObject(PythonLikeObject pythonObject) {
5555
try {
5656
var initScore = ((PythonInteger) initScoreField.get(pythonObject)).value.intValue();
57-
var hardScore = ((PythonInteger) hardScoreField.get(pythonObject)).value.intValue();
58-
var softScore = ((PythonInteger) softScoreField.get(pythonObject)).value.intValue();
57+
var hardScore = ((PythonInteger) hardScoreField.get(pythonObject)).value.longValue();
58+
var softScore = ((PythonInteger) softScoreField.get(pythonObject)).value.longValue();
5959
if (initScore == 0) {
60-
return HardSoftScore.of(hardScore, softScore);
60+
return HardSoftLongScore.of(hardScore, softScore);
6161
} else {
62-
return HardSoftScore.ofUninitialized(initScore, hardScore, softScore);
62+
return HardSoftLongScore.ofUninitialized(initScore, hardScore, softScore);
6363
}
6464
} catch (IllegalAccessException e) {
6565
throw new RuntimeException(e);

Diff for: timefold-solver-python-core/src/main/java/ai/timefold/solver/python/score/SimpleScorePythonJavaTypeMapping.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
import ai.timefold.jpyinterpreter.types.PythonJavaTypeMapping;
99
import ai.timefold.jpyinterpreter.types.PythonLikeType;
1010
import ai.timefold.jpyinterpreter.types.numeric.PythonInteger;
11-
import ai.timefold.solver.core.api.score.buildin.simple.SimpleScore;
11+
import ai.timefold.solver.core.api.score.buildin.simplelong.SimpleLongScore;
1212

13-
public final class SimpleScorePythonJavaTypeMapping implements PythonJavaTypeMapping<PythonLikeObject, SimpleScore> {
13+
public final class SimpleScorePythonJavaTypeMapping implements PythonJavaTypeMapping<PythonLikeObject, SimpleLongScore> {
1414
private final PythonLikeType type;
1515
private final Constructor<?> constructor;
1616
private final Field initScoreField;
@@ -31,12 +31,12 @@ public PythonLikeType getPythonType() {
3131
}
3232

3333
@Override
34-
public Class<? extends SimpleScore> getJavaType() {
35-
return SimpleScore.class;
34+
public Class<? extends SimpleLongScore> getJavaType() {
35+
return SimpleLongScore.class;
3636
}
3737

3838
@Override
39-
public PythonLikeObject toPythonObject(SimpleScore javaObject) {
39+
public PythonLikeObject toPythonObject(SimpleLongScore javaObject) {
4040
try {
4141
var instance = constructor.newInstance();
4242
initScoreField.set(instance, PythonInteger.valueOf(javaObject.initScore()));
@@ -48,14 +48,14 @@ public PythonLikeObject toPythonObject(SimpleScore javaObject) {
4848
}
4949

5050
@Override
51-
public SimpleScore toJavaObject(PythonLikeObject pythonObject) {
51+
public SimpleLongScore toJavaObject(PythonLikeObject pythonObject) {
5252
try {
5353
var initScore = ((PythonInteger) initScoreField.get(pythonObject)).value.intValue();
54-
var score = ((PythonInteger) scoreField.get(pythonObject)).value.intValue();
54+
var score = ((PythonInteger) scoreField.get(pythonObject)).value.longValue();
5555
if (initScore == 0) {
56-
return SimpleScore.of(score);
56+
return SimpleLongScore.of(score);
5757
} else {
58-
return SimpleScore.ofUninitialized(initScore, score);
58+
return SimpleLongScore.ofUninitialized(initScore, score);
5959
}
6060
} catch (IllegalAccessException e) {
6161
throw new RuntimeException(e);

Diff for: timefold-solver-python-core/src/main/python/_jpype_type_conversions.py

+50
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,56 @@ def applyAsInt(self, argument1, argument2, argument3, argument4, argument5):
138138
return JInt(self.delegate(argument1, argument2, argument3, argument4, argument5))
139139

140140

141+
@JImplements('java.util.function.ToLongFunction', deferred=True)
142+
class PythonToLongFunction:
143+
def __init__(self, delegate):
144+
self.delegate = delegate
145+
146+
@JOverride
147+
def applyAsLong(self, argument):
148+
return JLong(self.delegate(argument))
149+
150+
151+
@JImplements('java.util.function.ToLongBiFunction', deferred=True)
152+
class PythonToLongBiFunction:
153+
def __init__(self, delegate):
154+
self.delegate = delegate
155+
156+
@JOverride
157+
def applyAsLong(self, argument1, argument2):
158+
return JLong(self.delegate(argument1, argument2))
159+
160+
161+
@JImplements('ai.timefold.solver.core.api.function.ToLongTriFunction', deferred=True)
162+
class PythonToLongTriFunction:
163+
def __init__(self, delegate):
164+
self.delegate = delegate
165+
166+
@JOverride
167+
def applyAsLong(self, argument1, argument2, argument3):
168+
return JLong(self.delegate(argument1, argument2, argument3))
169+
170+
171+
@JImplements('ai.timefold.solver.core.api.function.ToLongQuadFunction', deferred=True)
172+
class PythonToLongQuadFunction:
173+
def __init__(self, delegate):
174+
self.delegate = delegate
175+
176+
@JOverride
177+
def applyAsLong(self, argument1, argument2, argument3, argument4):
178+
return JLong(self.delegate(argument1, argument2, argument3, argument4))
179+
180+
181+
@JImplements('ai.timefold.solver.core.api.function.ToLongPentaFunction', deferred=True)
182+
class PythonToLongPentaFunction:
183+
def __init__(self, delegate):
184+
self.delegate = delegate
185+
186+
@JOverride
187+
def applyAsLong(self, argument1, argument2, argument3, argument4, argument5):
188+
return JLong(self.delegate(argument1, argument2, argument3, argument4, argument5))
189+
190+
141191

142192
@JImplements('java.util.function.Predicate', deferred=True)
143193
class PythonPredicate:

Diff for: timefold-solver-python-core/src/main/python/_timefold_java_interop.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ def register_score_python_java_type_mappings():
106106
_scores_registered = True
107107

108108
from .score._score import SimpleScore, HardSoftScore, HardMediumSoftScore, BendableScore
109-
from ai.timefold.solver.core.api.score.buildin.simple import SimpleScore as _SimpleScore
110-
from ai.timefold.solver.core.api.score.buildin.hardsoft import HardSoftScore as _HardSoftScore
111-
from ai.timefold.solver.core.api.score.buildin.hardmediumsoft import HardMediumSoftScore as _HardMediumSoftScore
112-
from ai.timefold.solver.core.api.score.buildin.bendable import BendableScore as _BendableScore
109+
from ai.timefold.solver.core.api.score.buildin.simplelong import SimpleLongScore as _SimpleScore
110+
from ai.timefold.solver.core.api.score.buildin.hardsoftlong import HardSoftLongScore as _HardSoftScore
111+
from ai.timefold.solver.core.api.score.buildin.hardmediumsoftlong import HardMediumSoftLongScore as _HardMediumSoftScore
112+
from ai.timefold.solver.core.api.score.buildin.bendablelong import BendableLongScore as _BendableScore
113113

114114
from ai.timefold.solver.python.score import (SimpleScorePythonJavaTypeMapping,
115115
HardSoftScorePythonJavaTypeMapping,

0 commit comments

Comments
 (0)