In OptaPlanner, how does one restrict the number of times a fact is assigned to an entity? - optaplanner

Using course scheduling as an example, say an instructor can only teach n courses. To enforce this, my thought is to find all courses that are being taught by a given instructor, and increase badness by the negative difference, by half if below. How would I go about doing that (getting all courses that are taught by a given professor)?

If you introduce a List<Course> courseList bi-directional variable (section 6.2. Bi-directional Variable (Inverse Relation Shadow Variable) in the Instructor class, you'll have access to all his courses:
#PlanningEntity
public class Course {
#PlanningVariable(valueRangeProviderRefs = {"instructorRange"})
private Instructor instructor;
}
#PlanningEntity
public class Instructor {
#InverseRelationShadowVariable(sourceVariableName = "instructor")
private List<Course> courseList;
}
As for scoring, penalise hard score when the instructor has too many courses assigned and soft score when there aren't enough of them.

Related

Searching across aggregates in DDD

I have the following scenario in DDD.
public class Document
{
public int Id {get;set;}
public string DocumentCode {get;set;}
public int BuyerId {get;set;}
}
public class Buyer
{
public int Id {get;set;}
public string Name {get;set;}
}
And now I want to search all documents that contain buyer with a name "John".
Since Buyer is a different aggregate, I am thinking of these scenarios
Create new aggregate
public class DocumentSearch
{
public int Id {get;set;}
public string DocumentCode {get;set;}
public int BuyerId {get;set;}
public string Name {get;set;}
}
The "problem" here is that this aggregate need to listen to any Buyer changes and apply changes locally.
Keep everything as it is.
And on db level create a view that would act as a new aggregate. Problem here is that it breaks every DDD principle and the app is not really persistence ignorant
Do search and join on app level
Basically do a search on Document, do a search on Buyer and join it at application level. I believe this would require more time and power, since both sets would be initially larger then they should actually be in merged search?
What would be a way to go in order to follow DDD principles? CQRS is the ultimate solution, but I am looking for a transient solution on the way to CQRS
Asking a question shouldn't change the answer.
Since a search doesn't change the answer, you don't normally need a domain model or domain entities to support it.
The usual solutions are to either (a) query your data model directly or (b) create a "read model" to support the queries.
(a) is exactly what it says on the tin. If you are storing data in an RDBMS, then just query -> dto? -> response.
Read models are often used where query support isn't viable. A read model is effectively a cached DTO - you build a representation of the set as things change. Most often, you'll see this done asynchronously -- queries are run against the "latest" representation, and a background workflow is run to propagate changes to that representation.

Optaplanner Value Range Provider not getting called

I would like to know how a Value Range Provider works.
I have a Class Called Entity, In that class there are multiple instances, all mapped in the Solution like below
#PlanningEntityCollectionProperty
public List<Entity> getEntityList() {
return entityList;
}
Now i want to have differnet range values for different Entity objects. Eg. one will have 0 to 50, other might have 20 to 100 like. So I implemented #ValueRangeProvider inside the Entity Class.
#PlanningEntity()
public class Entity {
#PlanningVariable(valueRangeProviderRefs = {"quantityRange"})
public Long getAllocatedWeight() {
return allocatedWeight;
}
#ValueRangeProvider(id = "quantityRange")
public CountableValueRange<Long> getQuantityRange() {
return ValueRangeFactory.createLongValueRange(minWeights, maxWeights);
}
}
The breakpoint at getQuantityRange is never getting called, also the Optaplanner is not considering the range while generating results, but all the drools rules are working fine as intended. All I need is to, statically assign ranges for each entity objects.
Note : I am using the InvestmentQuantityTransferMove.java for stepping
from the investments example found in the optaplanner Repo. Since
my solution is also similar, that the sum of all entity should be
exactly equal to a specific value.
Your entity probably isn't being parsed by OptaPlanner, or you'd get a clear exception - or the break point would hit. So one of these 2 conditions isn't met:
Your Entity needs to have an #PlanningEntity annotation. This is clearly met.
Your Entity needs to be registered in the solverConfig.xml (or java API equivalent) with <entityClass>. This is probably the problem.
(If both of these are met and your break point isn't hit, then this is a bug. Create a jira with a reproducer.)
This is a common pitfall, but unfortunately OptaPlanner can't detect if an entity isn't registered (as far as I know, without incurring a heavy boostrap performance cost)...

Optaplanner not using different values for PlanningVariable

I am trying implement a job shop scheduling application using Fisher & Thompson mt10 dataset. Basically it contains of
10 jobs, each having 10 dependent steps
10 machines
each step of a job is assigned to a specific machine
I have implemented an Optaplanner use case based on the "Taskassigning" example. I removed the speed and priority concepts but kept the skill concept to make jobs run only on machines where they are able to run. I introduced a "predecessor" concept to build the dependencies between jobs/steps.
As there will be gaps in the schedule (which is different from the Taskassigning example), removed starttime and endtime and introduced a starttime PlanningVariable, fed by a list of possible start times.
However, I only get two different start times in the schedule - Optaplanner does not seem to utilize my value range provider. Therefore, hard constraints are violated because the sequence of dependent steps is not kept.
Job:
private JobType jobType;
private Job predecessor;
private Job successor;
private int indexInJobType;
// Planning variables: changes during planning, between score calculations.
#PlanningVariable(valueRangeProviderRefs = {"machineRange", "jobRange"},
graphType = PlanningVariableGraphType.CHAINED)
private JobOrMachine previousJobOrMachine;
#AnchorShadowVariable(sourceVariableName = "previousJobOrMachine")
private Machine machine;
#PlanningVariable(valueRangeProviderRefs = {"startTimeRange"})
private StartTime startTime=new StartTime(0); // In minutes
My PlanningSolution has a range provider:
#ValueRangeProvider(id = "startTimeRange")
#ProblemFactCollectionProperty
public List<StartTime> getStartTimeList() {
return startTimeList;
}
I am relatively new to Optaplanner and might be missing something very basic. I am struggling to identify what I am doing wrong, even after extensive reading of the docs and examples.
Any idea?
I found a problem with a hard constraint rule related to the planning variable. This question is no longer valid. Thanks.

OptaPlanner customer-vehicle delivery restrictions

I am using OptaPlanner for vehicle routing and scheduling. I'd like to include the concept of customer-vehicle restrictions.
Example 1: customers specified as mechanised customers can only
receive delivery from vehicles that have been specified as mechanised
(e.g. vehicles with forklifts, hydraulic tail lifts, etc.)
Example 2: customers have physical constraints on their premises and
can only accept delivery from vehicles under a certain size.
In general terms a group of customers should receive delivery from a group of vehicles. Any vehicles that do not meet the criteria should not be considered for delivery to these customers.
I've searched the forum, but don't see any questions for the same scenario. Can anyone assist?
Add a hard constraint, for example in DRL
when
Customer(vehicleOk == false)
then
... // penalize hard score
end
with a class that looks like this:
class Customer {
private boolean needsMech;
private Vehicle vehicle; // Anchor shadow variable
...
public boolean isVehicleOk() {
if (needsMech && !vehicle.isMech()) {
return false;
}
if (...) { // size limitation
return false;
}
return true;
}
}

Nhibernate Criterion - select rows in table A of TypeId defined in Table B

the title is confusing sorry, if you can think of a better one, please change it.
I have three tables, say, bikes, owners and a relationship table (something like many to many) that defines all owners of a bike, or all bikes of an owner.
So, I want to select All bikes of OwnerId 1
But, my mapping is like so:
BikeOwners references one Bike
BikeOwners References one OWner
How do I write the criterion in nhibernate to do this?
Right now, I am trying:
DetachedCriteria crit = DetachedCriteria.For<Bikes>()
.Add(Expression.Eq("OwnerId", _ownerId));
and it errors out saying there isn't any OwnerId in Bikes table, which I understand..
Hope the question is clear.. If you need any details, please ask!
I know I can get first get a list of all Bike id's from Bike owner table and then use that int array to get all bikes in bikes table - BUT - it is two database access and I am doing it manually, there should be a way to do this in one go, right?
This is my plan b, if all else fails, I'll do this.
Thanks
It really depends on your entities. I have mocked up a sample entity, just adopt it to yours.
public class Bike
{
public int BikeId;
public IList<BikeOwners> BikeOwners;
public string BikeName;
}
public class Owners
{
public int OwnerId;
public IList<BikeOwners> OwnersBikes;
public string OwnerName;
}
public class BikeOwners
{
public int Id;
public Owners owner;
public Bikes bike;
}
Now, you are going to write your nhibernate criteria like this:
DetachedCriteria crit = DetachedCriteria.For<Bikes>()
.CreateCriteria("BikeOwners") //from Bikes class
.CreateCriteria("owner") // from BikeOwners class
.Add(Expression.Eq("OwnerId", _OwnerId)); //from Owners class
obviously, you need to modify it to your entities and names.
Unless there's more column in the BikeOwners table, it shouldn't be represented in the domain model at all. Bike and Owner should be mapped as a many-to-many relationship. Also, I find it unusual that a Bike can have multiple Owners.

Resources