Skip to content

Commit bc6eb76

Browse files
committed
Implement mapping
1 parent c671912 commit bc6eb76

File tree

9 files changed

+360
-23
lines changed

9 files changed

+360
-23
lines changed

core/src/main/java/ai/timefold/solver/core/impl/move/streams/dataset/AbstractBiDataStream.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package ai.timefold.solver.core.impl.move.streams.dataset;
22

3+
import ai.timefold.solver.core.impl.move.streams.dataset.common.bridge.AftBridgeBiDataStream;
4+
import ai.timefold.solver.core.impl.move.streams.dataset.common.bridge.AftBridgeUniDataStream;
35
import ai.timefold.solver.core.impl.move.streams.maybeapi.BiDataFilter;
46
import ai.timefold.solver.core.impl.move.streams.maybeapi.BiDataMapper;
57
import ai.timefold.solver.core.impl.move.streams.maybeapi.stream.BiDataStream;
6-
78
import ai.timefold.solver.core.impl.move.streams.maybeapi.stream.UniDataStream;
9+
810
import org.jspecify.annotations.NullMarked;
911
import org.jspecify.annotations.Nullable;
1012

@@ -28,17 +30,22 @@ public final BiDataStream<Solution_, A, B> filter(BiDataFilter<Solution_, A, B>
2830

2931
@Override
3032
public <ResultA_> UniDataStream<Solution_, ResultA_> map(BiDataMapper<Solution_, A, B, ResultA_> mapping) {
31-
return null;
33+
var stream = shareAndAddChild(new BiMapUniDataStream<>(dataStreamFactory, this, mapping));
34+
return dataStreamFactory.share(new AftBridgeUniDataStream<>(dataStreamFactory, stream), stream::setAftBridge);
3235
}
3336

3437
@Override
3538
public <ResultA_, ResultB_> BiDataStream<Solution_, ResultA_, ResultB_> map(BiDataMapper<Solution_, A, B, ResultA_> mappingA, BiDataMapper<Solution_, A, B, ResultB_> mappingB) {
36-
return null;
39+
var stream = shareAndAddChild(new BiMapBiDataStream<>(dataStreamFactory, this, mappingA, mappingB));
40+
return dataStreamFactory.share(new AftBridgeBiDataStream<>(dataStreamFactory, stream), stream::setAftBridge);
3741
}
3842

3943
@Override
4044
public BiDataStream<Solution_, A, B> distinct() {
41-
return null;
45+
if (guaranteesDistinct()) {
46+
return this; // Already distinct, no need to create a new stream.
47+
}
48+
throw new UnsupportedOperationException();
4249
}
4350

4451
public BiDataset<Solution_, A, B> createDataset() {

core/src/main/java/ai/timefold/solver/core/impl/move/streams/dataset/AbstractDataStream.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package ai.timefold.solver.core.impl.move.streams.dataset;
22

3-
import java.util.ArrayList;
4-
import java.util.List;
5-
import java.util.Set;
6-
73
import ai.timefold.solver.core.impl.bavet.common.BavetStream;
84
import ai.timefold.solver.core.impl.bavet.common.TupleSource;
95
import ai.timefold.solver.core.impl.move.streams.dataset.common.DataNodeBuildHelper;
10-
116
import org.jspecify.annotations.NullMarked;
127
import org.jspecify.annotations.Nullable;
138

9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.Set;
12+
1413
@NullMarked
1514
public abstract class AbstractDataStream<Solution_>
1615
implements BavetStream {
@@ -29,6 +28,10 @@ public final <Stream_ extends AbstractDataStream<Solution_>> Stream_ shareAndAdd
2928
return dataStreamFactory.share(stream, childStreamList::add);
3029
}
3130

31+
boolean guaranteesDistinct() {
32+
return true; // Default implementation, can be overridden by subclasses.
33+
}
34+
3235
// ************************************************************************
3336
// Node creation
3437
// ************************************************************************

core/src/main/java/ai/timefold/solver/core/impl/move/streams/dataset/AbstractUniDataStream.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package ai.timefold.solver.core.impl.move.streams.dataset;
22

3+
import ai.timefold.solver.core.impl.move.streams.dataset.common.bridge.AftBridgeBiDataStream;
4+
import ai.timefold.solver.core.impl.move.streams.dataset.common.bridge.AftBridgeUniDataStream;
35
import ai.timefold.solver.core.impl.move.streams.dataset.common.bridge.ForeBridgeUniDataStream;
46
import ai.timefold.solver.core.impl.move.streams.dataset.joiner.BiDataJoinerComber;
57
import ai.timefold.solver.core.impl.move.streams.maybeapi.BiDataJoiner;
@@ -8,7 +10,6 @@
810
import ai.timefold.solver.core.impl.move.streams.maybeapi.stream.BiDataStream;
911
import ai.timefold.solver.core.impl.move.streams.maybeapi.stream.UniDataStream;
1012

11-
import org.jspecify.annotations.NonNull;
1213
import org.jspecify.annotations.NullMarked;
1314
import org.jspecify.annotations.Nullable;
1415

@@ -31,8 +32,7 @@ public final UniDataStream<Solution_, A> filter(UniDataFilter<Solution_, A> filt
3132
}
3233

3334
@Override
34-
public @NonNull <B> BiDataStream<Solution_, A, B> join(@NonNull UniDataStream<Solution_, B> otherStream,
35-
@NonNull BiDataJoiner<A, B>... joiners) {
35+
public <B> BiDataStream<Solution_, A, B> join(UniDataStream<Solution_, B> otherStream, BiDataJoiner<A, B>... joiners) {
3636
var other = (AbstractUniDataStream<Solution_, B>) otherStream;
3737
var leftBridge = new ForeBridgeUniDataStream<Solution_, A>(dataStreamFactory, this);
3838
var rightBridge = new ForeBridgeUniDataStream<Solution_, B>(dataStreamFactory, other);
@@ -47,8 +47,7 @@ public final UniDataStream<Solution_, A> filter(UniDataFilter<Solution_, A> filt
4747
}
4848

4949
@Override
50-
public @NonNull <B> BiDataStream<Solution_, A, B> join(@NonNull Class<B> otherClass,
51-
@NonNull BiDataJoiner<A, B>... joiners) {
50+
public <B> BiDataStream<Solution_, A, B> join(Class<B> otherClass, BiDataJoiner<A, B>... joiners) {
5251
return join(dataStreamFactory.forEachNonDiscriminating(otherClass, false), joiners);
5352
}
5453

@@ -89,17 +88,23 @@ private <B> UniDataStream<Solution_, A> ifExistsOrNot(boolean shouldExist, UniDa
8988

9089
@Override
9190
public <ResultA_> UniDataStream<Solution_, ResultA_> map(UniDataMapper<Solution_, A, ResultA_> mapping) {
92-
return null;
91+
var stream = shareAndAddChild(new UniMapUniDataStream<>(dataStreamFactory, this, mapping));
92+
return dataStreamFactory.share(new AftBridgeUniDataStream<>(dataStreamFactory, stream), stream::setAftBridge);
9393
}
9494

9595
@Override
96-
public <ResultA_, ResultB_> BiDataStream<Solution_, ResultA_, ResultB_> map(UniDataMapper<Solution_, A, ResultA_> mappingA, UniDataMapper<Solution_, A, ResultB_> mappingB) {
97-
return null;
96+
public <ResultA_, ResultB_> BiDataStream<Solution_, ResultA_, ResultB_> map(UniDataMapper<Solution_, A, ResultA_> mappingA,
97+
UniDataMapper<Solution_, A, ResultB_> mappingB) {
98+
var stream = shareAndAddChild(new UniMapBiDataStream<>(dataStreamFactory, this, mappingA, mappingB));
99+
return dataStreamFactory.share(new AftBridgeBiDataStream<>(dataStreamFactory, stream), stream::setAftBridge);
98100
}
99101

100102
@Override
101-
public UniDataStream<Solution_, A> distinct() {
102-
return null;
103+
public AbstractUniDataStream<Solution_, A> distinct() {
104+
if (guaranteesDistinct()) {
105+
return this; // Already distinct, no need to create a new stream.
106+
}
107+
throw new UnsupportedOperationException();
103108
}
104109

105110
public UniDataset<Solution_, A> createDataset() {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package ai.timefold.solver.core.impl.move.streams.dataset;
2+
3+
import ai.timefold.solver.core.impl.bavet.bi.MapBiToBiNode;
4+
import ai.timefold.solver.core.impl.move.streams.dataset.common.DataNodeBuildHelper;
5+
import ai.timefold.solver.core.impl.move.streams.dataset.common.bridge.AftBridgeBiDataStream;
6+
import ai.timefold.solver.core.impl.move.streams.maybeapi.BiDataMapper;
7+
import org.jspecify.annotations.NullMarked;
8+
import org.jspecify.annotations.Nullable;
9+
10+
import java.util.Objects;
11+
12+
@NullMarked
13+
final class BiMapBiDataStream<Solution_, A, B, NewA, NewB>
14+
extends AbstractBiDataStream<Solution_, NewA, NewB> {
15+
16+
private final BiDataMapper<Solution_, A, B, NewA> mappingFunctionA;
17+
private final BiDataMapper<Solution_, A, B, NewB> mappingFunctionB;
18+
private @Nullable AftBridgeBiDataStream<Solution_, NewA, NewB> aftStream;
19+
20+
public BiMapBiDataStream(DataStreamFactory<Solution_> constraintFactory, AbstractBiDataStream<Solution_, A, B> parent,
21+
BiDataMapper<Solution_, A, B, NewA> mappingFunctionA, BiDataMapper<Solution_, A, B, NewB> mappingFunctionB) {
22+
super(constraintFactory, parent);
23+
this.mappingFunctionA = mappingFunctionA;
24+
this.mappingFunctionB = mappingFunctionB;
25+
}
26+
27+
public void setAftBridge(AftBridgeBiDataStream<Solution_, NewA, NewB> aftStream) {
28+
this.aftStream = aftStream;
29+
}
30+
31+
@Override
32+
public boolean guaranteesDistinct() {
33+
return false;
34+
}
35+
36+
@Override
37+
public void buildNode(DataNodeBuildHelper<Solution_> buildHelper) {
38+
assertEmptyChildStreamList();
39+
int inputStoreIndex = buildHelper.reserveTupleStoreIndex(parent.getTupleSource());
40+
int outputStoreSize = buildHelper.extractTupleStoreSize(aftStream);
41+
var node = new MapBiToBiNode<>(inputStoreIndex,
42+
mappingFunctionA.toBiFunction(buildHelper.getSessionContext().solutionView()),
43+
mappingFunctionB.toBiFunction(buildHelper.getSessionContext().solutionView()),
44+
buildHelper.getAggregatedTupleLifecycle(aftStream.getChildStreamList()), outputStoreSize);
45+
buildHelper.addNode(node, this);
46+
}
47+
48+
@Override
49+
public boolean equals(Object object) {
50+
if (this == object)
51+
return true;
52+
if (object == null || getClass() != object.getClass())
53+
return false;
54+
BiMapBiDataStream<?, ?, ?, ?, ?> that = (BiMapBiDataStream<?, ?, ?, ?, ?>) object;
55+
return Objects.equals(parent, that.parent) &&
56+
Objects.equals(mappingFunctionA, that.mappingFunctionA) &&
57+
Objects.equals(mappingFunctionB, that.mappingFunctionB);
58+
}
59+
60+
@Override
61+
public int hashCode() {
62+
return Objects.hash(parent, mappingFunctionA, mappingFunctionB);
63+
}
64+
65+
@Override
66+
public String toString() {
67+
return "BiMap()";
68+
}
69+
70+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package ai.timefold.solver.core.impl.move.streams.dataset;
2+
3+
import ai.timefold.solver.core.impl.bavet.bi.MapBiToUniNode;
4+
import ai.timefold.solver.core.impl.move.streams.dataset.common.DataNodeBuildHelper;
5+
import ai.timefold.solver.core.impl.move.streams.dataset.common.bridge.AftBridgeUniDataStream;
6+
import ai.timefold.solver.core.impl.move.streams.maybeapi.BiDataMapper;
7+
import org.jspecify.annotations.NullMarked;
8+
import org.jspecify.annotations.Nullable;
9+
10+
import java.util.Objects;
11+
12+
@NullMarked
13+
final class BiMapUniDataStream<Solution_, A, B, NewA, NewB>
14+
extends AbstractUniDataStream<Solution_, NewA> {
15+
16+
private final BiDataMapper<Solution_, A, B, NewA> mappingFunction;
17+
private @Nullable AftBridgeUniDataStream<Solution_, NewA> aftStream;
18+
19+
public BiMapUniDataStream(DataStreamFactory<Solution_> constraintFactory, AbstractBiDataStream<Solution_, A, B> parent,
20+
BiDataMapper<Solution_, A, B, NewA> mappingFunction) {
21+
super(constraintFactory, parent);
22+
this.mappingFunction = mappingFunction;
23+
}
24+
25+
public void setAftBridge(AftBridgeUniDataStream<Solution_, NewA> aftStream) {
26+
this.aftStream = aftStream;
27+
}
28+
29+
@Override
30+
public boolean guaranteesDistinct() {
31+
return false;
32+
}
33+
34+
@Override
35+
public void buildNode(DataNodeBuildHelper<Solution_> buildHelper) {
36+
assertEmptyChildStreamList();
37+
int inputStoreIndex = buildHelper.reserveTupleStoreIndex(parent.getTupleSource());
38+
int outputStoreSize = buildHelper.extractTupleStoreSize(aftStream);
39+
var node = new MapBiToUniNode<>(inputStoreIndex,
40+
mappingFunction.toBiFunction(buildHelper.getSessionContext().solutionView()),
41+
buildHelper.getAggregatedTupleLifecycle(aftStream.getChildStreamList()), outputStoreSize);
42+
buildHelper.addNode(node, this);
43+
}
44+
45+
@Override
46+
public boolean equals(Object object) {
47+
if (this == object)
48+
return true;
49+
if (object == null || getClass() != object.getClass())
50+
return false;
51+
BiMapUniDataStream<?, ?, ?, ?, ?> that = (BiMapUniDataStream<?, ?, ?, ?, ?>) object;
52+
return Objects.equals(parent, that.parent) &&
53+
Objects.equals(mappingFunction, that.mappingFunction);
54+
}
55+
56+
@Override
57+
public int hashCode() {
58+
return Objects.hash(parent, mappingFunction);
59+
}
60+
61+
@Override
62+
public String toString() {
63+
return "BiMap()";
64+
}
65+
66+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package ai.timefold.solver.core.impl.move.streams.dataset;
2+
3+
import ai.timefold.solver.core.impl.bavet.uni.MapUniToBiNode;
4+
import ai.timefold.solver.core.impl.move.streams.dataset.common.DataNodeBuildHelper;
5+
import ai.timefold.solver.core.impl.move.streams.dataset.common.bridge.AftBridgeBiDataStream;
6+
import ai.timefold.solver.core.impl.move.streams.maybeapi.UniDataMapper;
7+
import org.jspecify.annotations.NullMarked;
8+
import org.jspecify.annotations.Nullable;
9+
10+
import java.util.Objects;
11+
12+
@NullMarked
13+
final class UniMapBiDataStream<Solution_, A, NewA, NewB>
14+
extends AbstractBiDataStream<Solution_, NewA, NewB> {
15+
16+
private final UniDataMapper<Solution_, A, NewA> mappingFunctionA;
17+
private final UniDataMapper<Solution_, A, NewB> mappingFunctionB;
18+
private @Nullable AftBridgeBiDataStream<Solution_, NewA, NewB> aftStream;
19+
20+
public UniMapBiDataStream(DataStreamFactory<Solution_> constraintFactory, AbstractUniDataStream<Solution_, A> parent, UniDataMapper<Solution_, A, NewA> mappingFunctionA, UniDataMapper<Solution_, A, NewB> mappingFunctionB) {
21+
super(constraintFactory, parent);
22+
this.mappingFunctionA = mappingFunctionA;
23+
this.mappingFunctionB = mappingFunctionB;
24+
}
25+
26+
public void setAftBridge(AftBridgeBiDataStream<Solution_, NewA, NewB> aftStream) {
27+
this.aftStream = aftStream;
28+
}
29+
30+
@Override
31+
public boolean guaranteesDistinct() {
32+
return false;
33+
}
34+
35+
@Override
36+
public void buildNode(DataNodeBuildHelper<Solution_> buildHelper) {
37+
assertEmptyChildStreamList();
38+
int inputStoreIndex = buildHelper.reserveTupleStoreIndex(parent.getTupleSource());
39+
int outputStoreSize = buildHelper.extractTupleStoreSize(aftStream);
40+
var node = new MapUniToBiNode<>(inputStoreIndex,
41+
mappingFunctionA.toFunction(buildHelper.getSessionContext().solutionView()),
42+
mappingFunctionB.toFunction(buildHelper.getSessionContext().solutionView()),
43+
buildHelper.getAggregatedTupleLifecycle(aftStream.getChildStreamList()), outputStoreSize);
44+
buildHelper.addNode(node, this);
45+
}
46+
47+
@Override
48+
public boolean equals(Object object) {
49+
if (this == object)
50+
return true;
51+
if (object == null || getClass() != object.getClass())
52+
return false;
53+
UniMapBiDataStream<?, ?, ?, ?> that = (UniMapBiDataStream<?, ?, ?, ?>) object;
54+
return Objects.equals(parent, that.parent) &&
55+
Objects.equals(mappingFunctionA, that.mappingFunctionA) &&
56+
Objects.equals(mappingFunctionB, that.mappingFunctionB);
57+
}
58+
59+
@Override
60+
public int hashCode() {
61+
return Objects.hash(parent, mappingFunctionA, mappingFunctionB);
62+
}
63+
64+
@Override
65+
public String toString() {
66+
return "UniMap()";
67+
}
68+
69+
}

0 commit comments

Comments
 (0)