Optaplanner: manual grouping / group into multiple groups - java

I have the following dataset, and am trying to work out how to best write a specific constraint.
My PlanningEntity looks (roughly) as follows:
#PlanningEntity
public class Participation {
#PlanningId
private long id;
private Student student;
private Lesson lesson;
#PlanningVariable(valueRangeProviderRefs = "possibleEnrollments")
private Boolean enrolled;
}
whereby a Lesson has a public List<Subject> getSubjects() (note: a list of multiple subjects).
What I would like to do in my penalize method is look at all participations of a student/subject (single subject!) combination. In other words, if I have lesson A with subject 1, lesson B with subject 2 and lesson C with subjects 1 and 2, I would like to do a grouping in such a way that in my penalize function I get two (Student, List<Participation>) callbacks: one for subject 1 and one for subject 2, whereby the first lists contains lessons A and C, and the second list has lessons B and C. So, C is contained in two lists.
The following does not work:
constraintFactory
.forEach(Participation.class)
.groupBy(Participation::getStudent, Participation::getSubjects, toList())
since this groups on the entire List returned by Participation::getSubject and the set 1 and 2 attached to lesson C becomes a separate group.
I have currently 'solved' the problem as follows, with a custom UniConstraintCollection:
return constraintFactory
.forEach(Participation.class)
.groupBy(Participation::getStudent, new UniConstraintCollector<Participation, Map<Subject, List<Participation>>, Map<Subject, List<Participation>>>() {
#Override
public Supplier<Map<Subject, List<Participation>>> supplier() {
return HashMap::new;
}
#Override
public BiFunction<Map<Subject, List<Participation>>, Participation, Runnable> accumulator() {
return (map, participation) -> {
for(Subject s : participation.getSubjects()) {
if(!map.containsKey(s)) {
map.put(s, new ArrayList<>());
}
map.get(s).add(participation);
}
return () -> {
for(Map.Entry<Subject, List<Participation>> entry: map.entrySet()) {
entry.getValue().remove(participation);
}
};
};
}
#Override
public Function<Map<Subject, List<Participation>>, Map<Subject, List<Participation>>> finisher() {
return Function.identity();
}
}).penalize(("name", HardSoftScore.ONE_SOFT, (student, participationMap) -> {
...
});)
This works, in that I receive a map of Subject to Participations and allows me to calculate the penalty I want.
However, this means that I calculate one penalty value for all subject/list combinations 'together'. From a usability perspective, I would like to penalize each subject/list separately. Is there a way to do this? (Maybe by rewriting the UniConstraintCollector to provide multiple lists of Participations, instead of one single Map<Subject, List<Participation>>?)
P.S. Another approach I have tried to achieve the same goal is to work from the perspective of the Subject. So, making Subjects a ProblemFact on the PlanningSolution, and working with something like
return constraintFactory
.forEach(Subject.class)
.join(constraintFactory.forEach(Participation.class),
JoinerSupport.getJoinerService().newBiJoiner(List::of, JoinerType.INTERSECTING, Participation::getSubjects)
)
I assume this is the way I would need to go, using the JoinerType INTERSECTING, but this gives me an "Unsupported Joiner Type" exception in AbstractLeftHandSide.

What if you start from Subject?
constraintFactory
.forEach(Subject.class)
.join(Participation.class,
// Joiners.containedBy() would do this far more efficient
filtering((s, p) -> p.getSubjects().contains(s))
.groupBy((s, p) -> s, toList((s, p) -> p))
This could be an expensive constraint performance wise. Benchmark it.

This isn't really an answer, but it might solve your problem too. It's too long to add as a comment.
The Boolean planning variable is typically an anti-pattern.
If you improve your model, the constraint might become easier to implement.
Instead, you could model it like this:
#PlanningEntity
public class Participation {
#PlanningId long id;
Student student;
#PlanningVariable(...) Lesson lesson;
}
This simpler model (on the right) will solve far more efficiently. But in this case, how many Participation instances should you create?
If the numbers of lessons for each student is fixed, that's obvious: that number per student.
If the numbers of lessons for each student is a planning decision, use overconstrainted planning: #PlanningVariable(nullable=true,...) Lesson lesson and create one participation for the maximum number of lessons of each student. This will allow the solver to leave some participation instances unassigned.
See also the Domain Modeling Guide in the docs.

Related

Validating an object with a long list of predicates

I have an object, Bill, with a number of fields. In the method below, I get the bill with a function. I want to validate it with a list of Predicate<Bill>, which are paired with the appropriate error message to be applied if the predicate test fails. How can I accumulate the error messages given a list of tests, given that I can have more than eight conditions, and therefore won't be able to use Validation.combine?
default Validation<Seq<String>, Long> validate(
Long id,
Long, Bill> getBill,
List<Pair<Predicate<Bill>,String>> tests){
Bill bill = getBill.apply(id);
//I want to do the same thing
//but using the list I passed in,
//without the limitation of eight validations.
return Validation.combine(
validateBill(bill, Pair.of(hasDateInsurerReceivedBill, "Date Insurer Received Bill absent")),
validateBill(bill, Pair.of(EventValidation.hasEmployeeIdNumber, "Employee ID Number absent"))
).ap((x, y) -> id);
}
default Validation<String,Long> validateBill(
Bill bill, Pair<Predicate<Bill>, String> condition)
{
return condition.getFirst().test(bill) ?
Validation.valid(bill.getIntId())
: Validation.invalid(condition.getSecond());
}
I'm brand new to this library and I'm not terribly familiar with functional programming yet, so please use examples and the simplest terminology possible in any explanations.
I would do a nested combine and then flatten the results.
In our project we always have Seq<ValidationError> on the left side of a Validation, you don't have to but it is good to understand the code I'll show you.
With the first 8 Validations you return a new Validation in the .ap
When you return a Validation inside .ap you will end up with something like this:
Validation<Seq<ValidationError>, Validation<Seq<ValidationError>, String>> x = ...
The needs to be flattened with the following piece of code:
Validation
.combine(step1, step2, step3, step4, step5, step6, step7, step8)
.ap((a, b, c, d, e, f ,g, h) -> {
// do important stuff and
return Validation......
})
.mapError(Util::flattenErrors)
.fold(Validation::invalid, Function.identity());
The Util class:
public static Seq<ValidationError> flattenErrors(final Seq<Seq<ValidationError>> nested) {
return nested
.flatMap(Function.identity())
.distinct(); //optional duplicate filtering
}
With this new validation you can do the same trick again (you can add 7 new validations every time or create a few and do another combine, depends a bit on the number of validations you have).

Data Structure for saving Requirements for courses

i'm struggling with an efficient way to store requirements for a course inside of a course.
e.g.:
You can take part at course A when you passed B
You can take part at course A too when you passed course C and D
I hoped to be able to use a tree structure so I can easily check if a Person passed all requirements but because of the multiple options to pass requirements it is not possible.
Do you know any technique or Data structure to solve this?
A Course object has a list of Prerequisite objects, only one of which needs to be fulfilled. A Prerequisite object has a list of required Course objects, all of which needs to be passed for the Prerequisite object to be fulfilled.
public class Course {
private List<Prerequisite> prerequisites;
public boolean canBeTakenBy(Student student) {
return prerequisites.isEmpty() ||
prerequisites.stream().anyMatch(p -> p.isFulfilledBy(student));
}
}
public class Prerequisite {
private List<Course> requiredCourses;
public boolean isFulfilledBy(Student student) {
return requiredCourses.stream().allMatch(student::hasPassed);
}
}
public class Student {
private Set<Course> passedCourses;
public boolean hasPassed(Course course) {
return passedCourses.contains(course);
}
}
There are many ways you can accomplish what you want, personally, I think the easiest is having an ArrayList< ArrayList < Course > >
So for example, if you want to add a possible requirement option, you could create an ArrayList with the courses and push it to the end of the requirements.
Later to check it, just run the combinations, complexity shouldn't be a problem, if you have for example 10 possible requirements with 10 courses each, worst case scenario it would be a 10x10 loop, 10² to the computer is the same as nothing at all.
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html

In Java, a "decorate and sort" concise implementation?

I'm learning Java for the first time (my prior experience is Python and Haskell). I have a situation that would, in Python, require a "decorate and sort" idiom. Such as the following (code not tested but this is roughly correct):
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
By choosing a different evalFunc you can choose how this is sorted.
In Java, I'm writing a program that composes music by choosing from among a list of notes, evaluating the "fitness" of each note, and picking the best. I have a class representing musical notes:
class Note {
...
}
I have a class that represents the fitness of a note as two values, its goodness and badness (yes, these are separate concepts in my program). Note: in Python or Haskell, this would simply be a 2-tuple, but my understanding is that Java doesn't have tuples in the usual sense. I could make it a pair, but it gets unwieldy to declare variables all over the place like List<Pair<Type1,Pair<Type2,Type3>>>. (As an aside, I don't think Java has type aliases either, which would let me shorten the declarations.)
class Fitness {
double goodness;
double badness;
}
The function that evaluates the fitness needs access to several pieces of data other than the Note. We'll say it's part of a "Composition" class:
class Composition {
... data declared here ... ;
public Fitness evaluate(Note n) {
}
}
I'd like to be able to compare Fitness objects in numerical order. There are two ways to compare: either goodness or badness can be numerically compared, depending on the situation.
class CompareFitnessByGoodness implements Comparator<Fitness> {
}
class CompareFitnessByBadness implements Comparator<Fitness> {
}
I'd like to package the Note together with its fitness, so I can sort the combined list by fitness and later pull out the best Note.
class Together {
public Note;
public Fitness;
}
I'd like to sort a List<Together> by either the goodness, or by the badness. So I might need:
class CompareTogetherByGoodness implements Comparator<Together> {
...
}
class CompareTogetherByBadness implements Comparator<Together> {
...
}
Eventually I'll write something like
Note pickBest(List<Together> notes) {
// Pick a note that's not too bad, and pretty good at the same
// time.
// First sort in order of increasing badness, so I can choose
// the bottom half for the next stage (i.e. the half "least bad"
// notes).
Collections.sort(notes, new CompareTogetherByBadness());
List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
// Now sort `leastBadHalf` and take the last note: the one with
// highest goodness.
Collections.sort(leastBadHalf, new CompareTogetherByGoodness());
return leastBadHalf.get(leastBadHalf.size()-1);
}
Whew! That is a LOT of code for something that would be a few lines in Haskell or Python. Is there a better way to do this?
EDIT:
Addressing some of the answers.
"You don't need to decorate." Well, my fitness computation is very expensive, so I want to compute it once for each note, and save the result for later access as well.
"Store goodness/badness in Note." The goodness or badness is not a property of the note alone; it's only meaningful in context and it can change. So this is a suggestion that I add mutable state which is only meaningful in some contexts, or plain wrong if there's a bug which accidentally mutates it. That's ugly, but maybe a necessary crutch for Java.
Going by what you already have
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
This is the equivalent in modern Java:
Given your composition object:
Composition composer = ...;
And a list of notes:
List<Note> notes = ...;
Then you can do:
List<Together> notesAllTogetherNow = notes.stream()
.map(note -> new Together(note, composer.evaluate(note)))
.sorted(new CompareTogetherByGoodness())
.collect(Collectors.toList());
To get the best note, you can take a bit further:
Optional<Note> bestNote = notes.stream()
.map(note -> new Together(note, composer.evaluate(note)))
.sorted(new CompareTogetherByBadness())
.limit(notes.size() / 2) // Taking the top half
.sorted(new CompareTogetherByGoodness())
.findFirst() // Assuming the last comparator sorts in descending order
.map(Together::getNote);
You can use streams:
Function<Foo, Bar> func = ...
Comparator<Foo> comparator = ...
var list = ...
var sorted = list.stream()
.sorted(comparator)
.map(func)
.collect(Collectors.toList());
Java plainly includes a Collections.sort :: List -> Comparator -> List that does everything for you. It mutates the original list, though.
Unfortunately, Java's standard library does not include tuples and even a plain Pair; the Apache Commnons library does, though.
In short, you don't need the decorate / undecorate approach in Java.
class Fitness {
double goodness;
double badness;
}
class Together {
Note note;
Fitness fitness;
}
class Note{
}
List<Together> notes = ...
Collections.sort(notes, Comparator.comparingDouble(value -> value.fitness.badness));
List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
return leastBadHalf.stream().max(Comparator.comparingDouble(value -> value.fitness.goodness));

Java Streams: Do f() for N - 1 elements and g() for N. i.e. different function for the last element

Is there a way to call the Java stream API to perform a function for all but the last elements of an Iterable and call another on the last without splitting it into two separate calls?
This would save on two passes on the array, one for splitting the array into it's head-array and tail-element, and another to iterate those two and apply a function.
My use case is calling repo.save(entity) on all but the last element and repo.saveAndFlush(entity) on the last.
Assume I have a Iterable<FooEntity> items;
I'm hoping for a solution along the lines of items.stream().???.profit(!)
Update:
Here is my class updated as per #jonsharpe 's comment:
public class FooWriter implements ItemWriter<FooEntityManifest> {
private final FooRepository fooRepo;
#PersistenceContext
private EntityManager em;
#Autowired
public FooWriter(FooRepository fooRepo) {
this.fooRepo = fooRepo;
}
#Override
public void write(List<? extends FooEntityManifest> items) {
items.forEach(fooEM -> {
FooEntity foo = fooEM.getChangedObject();
fooRepo.save(foo);
});
em.flush();
}
}
As i mentioned in the comments, I'm unsure whether this injects the correct EntityManager so would rather use the repo only. Are my concerns valid?
P.S. I realize that my collection interface is of List and not Iterable but I was wondering about this in a general sense.
The simplest solution is to treat all items equally like
items.forEach(fooEM -> fooRepo.save(fooEM.getChangedObject()));
em.flush();
If you want to treat the last element specially, the Stream API is not the right tool for the job. There are possible solutions, but they will be more complicated than using an other API.
E.g. considering that your starting point is a List:
if(!items.isEmpty()) {
int last = items.size()-1;
items.subList(0, last).forEach(fooEM -> fooRepo.save(fooEM.getChangedObject()));
fooRepo.saveAndFlush(items.get(last).getChangedObject());
}
You can use reduce to simulate such a behavior. E.g.:
list.stream()
.reduce((a, b) -> {
repo.save(a);
return b;
})
.ifPresent(x -> repo.saveAndFlush(x));
But, to be completely honest, this is quite clunky, and from a maintenance point of view, you might be better off using # jonrsharpe's suggestion in the comments - "In this example, why not .save all of them then .flush after"?

What is the best way to navigate a complex tree of dissimilar objects?

For example:
class Vehicle {
Collection<Axle> axles;
}
class Axle {
Collection<Wheel> wheels;
}
class Wheel {
// I think there are dually rims that take two tires -- just go with it
Collection<Tire> tires;
}
class Tire {
int width;
int diameter;
}
I have a service through which I can get a collection of all Vehicle objects I know about. Now say I have a tire of a specific width and diameter, and I want to find a Vehicle which can take it. The simplistic way is to have a set of four nested loops, like so:
for (Vehicle vehicle : vehicles) {
for (Axle axle : vehicle.getAxles()) {
for (Wheel wheel : axle.getWheels()) {
for (Tire tire : wheel.getTires()) {
if (tire.width == targetWidth
&& tire.diameter == targetDiameter) {
// do something
break;
}
}
}
}
}
Is there a good design pattern for this? Or a better data structure to use? Would it be better to just keep an index somewhere of tire information mapped to vehicles?
edit: answering questions from comments
Do you have control over the structure of the data you receive from the service?
Yes
Do you need to search for different tires multiple times in the same data?
Yes
Is performance an issue?
Not especially
When you find the tire, do you just need to know which vehicle contains it or do you also need the axle and wheel?
Sometimes just the vehicle, sometimes just the axle -- two different contexts
Do you need the reference to the tire that was found?
Yes, in the cases where I need the axle
edit2:
Extending the metaphor further, to explain the two contexts above:
Context 1 -- I want to know the vehicle, so I can send a worker out to collect the vehicle and bring it back
Context 2 -- I want to know the axle and tire, because I am at the vehicle trying to do the work
You could flatten out the loops by using Java 8 streams.
vehicles.stream()
.flatMap(vehicle -> vehicle.getAxles().stream())
.flatMap(axle -> axle.getWheels().stream())
.flatMap(wheel -> wheel.getTires().stream())
.filter(tire -> tire.width == targetWidth
&& tire.diameter == targetDiameter)
.forEach(tire -> {
// do something
});
The nice thing about streams is that you could insert additional filter, filter, findAny, etc., calls pretty easily anywhere in the sequence.
I would inverse your logic and move the question into the Vehicle, unless of course you'd like to keep your objects thin for any other reason (in which case I'd personally wrap them with a thicker object to add any behaviour needed)
class Vehicle {
...
public Tire acceptsTire(Tire tire) {
}
}
from here on there are several possibilities, depending on how important this piece of business logic is in your domain in general.
If you'll have several actions you could probably just iterate as you had done in your sample. Or possibly in the same way as I suggested, keep cascade the question to the correct component. As long as you can live with the time complexity of doing this that should be alright.
If this check is something you'd usually do then you could have a reference to the type of tires you hold in the vehicle directly, this could be either your Tire collection, or you could pass a TireSpecification instance when constructing the Vehicle if for any reason you need to keep these separated (Your intention is not very clear in the question, is the tire on the car or just an spec of what could fit?)
Without changing your data structure you won't be able to make significant difference. You can add some syntactic sugar with lambdas, but it is essentially the same solution.
Things you could look at:
Your model allows for Vehicles with zero axles or hundred. While it depends on your business model it seems to weird.
Your model allows to have different axles in your vehicle, different wheels. Is it really necessary? Make sure which elements of your model should have their separate identity (currently each object has it) and which is just a value object.
Make sure you really need such detailed model. Currently you have two classes (Axle,Wheel), which only hold collections of inner objects. If they will be just simple JavaBean object with getAllInnerTypes() then you should consider removal of this class. It may even be the case that tire information should be stored almost directly in Vehicle class.
As long as there aren't too many items and/or performance is not a big issue, I would probably just go with the nested loops (or streams from John's answer).
Since you have two contexts for the search, you could pass the appropriate action to the search method - something like this (using loops in this case):
interface TireAction {
void doSomething(Vehicle v, Axle a, Tire t);
}
void findTireAndPerform(int targetWidth, int targetDiameter, TireAction action) {
for (Vehicle vehicle : vehicles) {
for (Axle axle : vehicle.getAxles()) {
for (Wheel wheel : axle.getWheels()) {
for (Tire tire : wheel.getTires()) {
if (tire.width == targetWidth && tire.diameter == targetDiameter) {
action.doSomething(vehicle, axle, tire);
break;
}
}
}
}
}
}
void someMethod() {
...
findTireAndPerform(width, diameter, (v, a, t) -> {
// send worker to 'v'
});
...
findTireAndPerform(width, diameter, (v, a, t) -> {
// work on 'a' and 't'
});
}

Categories