Optaplanner : Incomplete justification list in solver - optaplanner

I am solving a roster assignment problem using optaplanner.
When the solver ends, I see logs like
INFO [2019-03-25 22:42:41,486] org.optaplanner.core.impl.solver.DefaultSolver: Solving ended: time spent (4083), best score (-500hard/-6133758medium/-1477130soft)
After which I print the score justification list using
ScoreDirectorFactory<MyPlanningSolution> scoreDirectorFactory = solver.getScoreDirectorFactory();
ScoreDirector<MyPlanningSolution> guiScoreDirector = scoreDirectorFactory.buildScoreDirector();
guiScoreDirector.setWorkingSolution(planningSolutionInstance);
for (ConstraintMatchTotal constraintMatchTotal : guiScoreDirector.getConstraintMatchTotals()) {
String constraintName = constraintMatchTotal.getConstraintName();
// The score impact of that constraint
Score scoreTotal = constraintMatchTotal.getScoreTotal();
this.logger.info("constraintName " + constraintName + " scoreTotal " + scoreTotal + " Justification List :");
for (ConstraintMatch constraintMatch : constraintMatchTotal.getConstraintMatchSet()) {
List<Object> justificationList = constraintMatch.getJustificationList();
this.logger.info(justificationList.toString() + " Score : " + constraintMatch.getScore());
}
}
This only print a few constraints:
constraintName Sample constraint1 scoreTotal -100hard/0medium/0soft Justification List :
[...] Score : -100hard/0medium/0soft
constraintName Sample constraint3 scoreTotal -400hard/0medium/0soft Justification List :
[...] Score : -100hard/0medium/0soft
[...] Score : -100hard/0medium/0soft
[...] Score : -100hard/0medium/0soft
[...] Score : -100hard/0medium/0soft
constraintName Sample constraint3 scoreTotal 0hard/-6133758medium/-1345422soft Justification List :
[...] Score : 0hard/0medium/-3125soft
[...] Score : 0hard/0medium/-625soft
[...] Score : 0hard/0medium/-25soft
[...] Score : 0hard/0medium/-16384soft
[...] Score : 0hard/0medium/-3125soft
[...] Score : 0hard/0medium/-3125soft
[...] Score : 0hard/0medium/-625soft
[...] Score : 0hard/0medium/-625soft
[...] Score : 0hard/0medium/-625soft
[...] Score : 0hard/0medium/-125soft
[...] Score : 0hard/0medium/-125soft
[...] Score : 0hard/0medium/-64soft
[...] Score : 0hard/0medium/-9soft
If you add up the score printed here, you get -500hard/0medium/-28607soft
As you can see there is are multiple constraint that are not printed here. The medium constraints are not logged at all. Plus lots of soft constraints are missing as well.
What could be the reason for this?

Call guiScoreDirector.calculateScore() after calling guiScoreDirector.setWorkingSolution(planningSolutionInstance) .

This could be score corruption. Turn on environmentMode FULL_ASSERT to prove it (let it run for a long time). If turning that on, stops the bug from occurring, try NON_INTRUSIVE_FULL_ASSERT instead.

Related

How to iterate over json object in python containing dictionary and list

{'PCCandidateDetails': {'BatchId': '456279',
'Candidate': 'Noori sahi ',
'CandidateId': '9124657',
'CenterName': 'K',
'ProjectName': 'PKKVY',
'QPName': 'Domestic Data Entry Operator(SSC/Q2212)',
'TrainingProviderName': 'OrionEdutechPrivateLimited'},
'PCTestScores': [{'MaxScore': 12,
'PCId': 'SRC/N3022_PC1',
'PCName': 'obtain sufficient information from the customer /client to understand the need and perform initial task',
'Percentage': 0,
'YourScore': 0},
{'MaxScore': 15,
'PCId': 'SRC/N3022_PC10',
'PCName': 'compares transcribed data, as displayed on a visual screen, document and corrects any errors with the source',
'Percentage': 0,
'YourScore': 0},
{'MaxScore': 5,
'PCId': 'SSC/N3022_PC11',
'PCName': 'obtain help or advice from specialist if the problem is outside his/her area of competence or experience',
'Percentage': 0,
'YourScore': 0}]}
I want to loop over this json object which I have got using web request.
import requests,ast
r = requests.get("some url")
data = r.text
data_dic = ast.literal_eval(data)
When I try to loop over the Json I am not able to fetch the expected output in key- Value pair. I want output like this
BatchId : 456279
Candidate : Noori sahi
CandidateId :9124657 ...
and so on. Below code is My approach but dictionary inside the list is causing problem in looping.
for i in data_dic:
for k,v in i.iteritems():
print k,v
What I'm getting as error is 'str' object has no attribute 'iteritems'. What is the right approach for looping this kind of data.
This works for your example (python 3.5.2) but i don't know if is the best approach (I mean, maybe there are some json parsing functions easier to use):
for v, k in itms.items():
if not isinstance(k, list):
for x, y in k.items():
print(x,':', y)
else:
for i in k:
for s, m in i.items():
print(s,':', m)
with the result:
CandidateId : 9124657
BatchId : 456279
QPName : Domestic Data Entry Operator(SSC/Q2212)
CenterName : K
ProjectName : PKKVY
Candidate : Noori sahi
TrainingProviderName : OrionEdutechPrivateLimited
Percentage : 0
PCName : obtain sufficient information from the customer /client to understand the need and perform initial task
MaxScore : 12
YourScore : 0
PCId : SRC/N3022_PC1
Percentage : 0
PCName : compares transcribed data, as displayed on a visual screen, document and corrects any errors with the source
MaxScore : 15
YourScore : 0
PCId : SRC/N3022_PC10
Percentage : 0
PCName : obtain help or advice from specialist if the problem is outside his/her area of competence or experience
MaxScore : 5
YourScore : 0
PCId : SSC/N3022_PC11
for python 2.7. only remove the parentheses from print
for v, k in itms.items():
if not isinstance(k, list):
for x, y in k.items():
print x,':', y
else:
for i in k:
for s, m in i.items():
print s,':', m
To get data use:
import json
data = json.loads(request.body)
print data['PCTestScores']
for values in data['PCTestScores']:
print values
print values['PCId']
print values['PCName']
print values['Percentage']
print values['MaxScore']
print values['YourScore']

forall always evaluates to be true [Drools 6.3 final]

I am a newbie for Drools. Would like to ask a question about the conditional element forall. Ihave some classes and the following UML diagram shows the relationships among these objects: 
UML diagram
One order has one customer and has a list of orderlines.
Each orderline is linked to one item. Frankly speaking, it is a sample code of one book about Drools.
Iwant to fire the below rule when the customer of order is SILVER category and all items in the order are in high range ( with high cost), in order to setup the discount of the order. Here is the rule:
rule "Silver Customers + High Range Order - 10% Discount -1"
when
$o: Order( $lines : orderLines.size >= 2, $customer: customer, discount == null )
$c: Customer( category == Category.SILVER, this == $customer )
forall( OrderLine( this memberOf $lines, $item : item)
Item(this == $item, category == Item.Category.HIGH_RANGE)
)
then
$o.setDiscount(new Discount(10.0));
update($o);
end
The problem is the rule always fires, even when I tried to insert one order with 5 items in low range.
In the debug info i found that the category of the first item was LOW_RANGE but the rule was still fired:
==>[BeforeActivationFiredEvent: getActivation()=[[ Silver Customers + High Range Order - 10% Discount active=false ] [ null
[fact 0:1:1561745898:141057847:1:DEFAULT:NON_TRAIT:org.drools.devguide.eshop.model.Customer:Customer [id = null, age=null, email=null, name=null, category = SILVER]]
[fact 0:12:1971991758:-345298280:12:DEFAULT:NON_TRAIT:org.drools.devguide.eshop.model.Order:Order [ id = null, customer=Customer [id = null, age=null, email=null, name=null, category = SILVER], date=Fri Oct 21 11:11:38 CST 2016, lines=[OrderLine [item=Item{id=1, name=A, cost=80.0, salePrice=800.0, category=LOW_RANGE}, quantity=1], OrderLine [item=Item{id=1, name=B, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=2], OrderLine [item=Item{id=1, name=C, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=3], OrderLine [item=Item{id=1, name=D, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=4], OrderLine [item=Item{id=1, name=E, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=5]], state=PENDING, discount=null]] ] ], getKnowledgeRuntime()=KieSession[0]]
-------------------
rule triggered:Silver Customers + High Range Order - 10% Discount
==>[AfterActivationFiredEvent: getActivation()=[[ Silver Customers + High Range Order - 10% Discount active=false ] [ null
[fact 0:1:1561745898:141057847:1:DEFAULT:NON_TRAIT:org.drools.devguide.eshop.model.Customer:Customer [id = null, age=null, email=null, name=null, category = SILVER]]
[fact 0:12:1971991758:-345298280:18:DEFAULT:NON_TRAIT:org.drools.devguide.eshop.model.Order:Order [ id = null, customer=Customer [id = null, age=null, email=null, name=null, category = SILVER], date=Fri Oct 21 11:11:38 CST 2016, lines=[OrderLine [item=Item{id=1, name=A, cost=80.0, salePrice=800.0, category=LOW_RANGE}, quantity=1], OrderLine [item=Item{id=1, name=B, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=2], OrderLine [item=Item{id=1, name=C, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=3], OrderLine [item=Item{id=1, name=D, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=4], OrderLine [item=Item{id=1, name=E, cost=800.0, salePrice=850.0, category=HIGH_RANGE}, quantity=5]], state=PENDING, discount=10.0 % ]] ] ], getKnowledgeRuntime()=KieSession[0]]
I have read the answers of the question: forall always evaluates to be true [Drools] . I tried the solution, but i got another wrong result, the below rule never fires even i used an order with all high range items:
rule "Silver Customers + High Range Order - 10% Discount"
when
$o: Order( $lines : orderLines.size >= 2, discount == null )
$c: Customer( category == Category.SILVER ) from $o.customer
forall( OrderLine() from $o.orderLines
OrderLine( item.category == Item.Category.HIGH_RANGE)
)
then
$o.setDiscount(new Discount(10.0));
update($o);
end
The unittest code is below:
#Test
public void highRangeOrderDiscountTest() {
KieSession kSession = createDefaultSession();
Order o = ModelFactory.getOrderWithFiveHighRangeItems();
kSession.insert(o.getCustomer());
kSession.insert(o.getOrderLines().get(0));
kSession.insert(o.getOrderLines().get(1));
kSession.insert(o.getOrderLines().get(2));
kSession.insert(o.getOrderLines().get(3));
kSession.insert(o.getOrderLines().get(4));
kSession.insert(o.getOrderLines().get(0).getItem());
kSession.insert(o.getOrderLines().get(1).getItem());
kSession.insert(o.getOrderLines().get(2).getItem());
kSession.insert(o.getOrderLines().get(3).getItem());
kSession.insert(o.getOrderLines().get(4).getItem());
kSession.insert(o);
int fired = kSession.fireAllRules();
// We have 5 Items that are categorized -> 5 rules were fired
// We have 1 Customer that needs to be categorized -> 1 rule fired
// We have just one order with all HIGH RAnge items -> 1 rule fired
// One Coupon is created for the SILVER Customer -> 1 rule fired
assertThat(8, is(fired));
assertThat(o.getCustomer().getCategory(), is(Customer.Category.SILVER));
assertThat(o.getDiscount(), not(nullValue()));
assertThat(o.getDiscount().getPercentage(), is(10.0));
}
}
Could you tell me the cause or tell me the correct usage of forall ? Thanks a lot.
This establishes the set of OrderLine-s and then ascertains that all pertain to a high range item. (Note: untested)
rule "Silver Customers + High Range Order - 10% Discount"
when
$c: Customer( category == Category.SILVER )
$o: Order( $lines : orderLines.size >= 2, customer == $c,
discount == null )
forall( OrderLine( $item : item) from $lines
Item(this == $item, category == Item.Category.HIGH_RANGE))
then
modify( $o ){ setDiscount(new Discount(10.0)) }
end
All Customer and Item objects must be inserted as facts; it would be reasonable to do this for OrderLine-s as well.

Writing rule in Drools - conditional sum

I am stuck in writing a rule for a particular problem statement.
I have an excel file having columns id, specialty,salary. Specialty can take values such as "oncology","urology" etc. I have to calculate total salary corresponding to each specialty.
There are two ways of doing this.
First:
rule "Total salary of Oncology"
no-loop
lock-on-active
salience 100
when
$m : Masterclass( $id : phyid , $p : p,spec=="Oncology")
not Masterclass( spec=="Oncology", phyid < $id)
$total : Number() from accumulate ( Masterclass( $salary : salary ,spec=="Oncology") ,
init( double total =0;),
action(total+=$salary;),
result( new Double (total)))
then
System.out.println($m.getSpec());
System.out.println("Total target pay is : " + $total + " of specialty : "+ $m.getSpec());
retract($m);
end
And similarly for other specialties.
This rule works fine.
Second:
Write only a single rule which reads the value of specialty and then sums up the salaries corresponding to it.
I tried to implement this but didn't succeed.
Any help will be appreciated.
This is far from perfect. But note that you don't have to insert some specific string. Running the rule without a string to match will produce the accumulated sums for all specialities anyway.
And you should wrap the String into a Java class - I was just too lazy to invent a proper Java class with one field.
rule "trigger read"
when
not String()
then
String s = read_any_way_you_want();
insert( s );
end;
rule "Total salary of something"
when
$spec: String()
$m : Masterclass( $id: phyid , spec == $spec)
not Masterclass( spec == $spec, phyid < $id)
$total : Number() from
accumulate ( Masterclass($salary: salary, spec == $spec) ,
init( double total =0;),
action(total+=$salary;),
result( new Double (total)))
then
System.out.println($m.getSpec());
System.out.println("Total target pay is : " + $total +
" o specialty : "+ $m.getSpec());
retract($spec);
end

drools code for score calculation logic

I want to schedule events using optaplanner in which required resource by event is a soft constraint.
I have done score calculation in java code like :
int resources = 0;
int quantity = 0;
for(ResourceAvailability availability : eventDate.getResourceAvailabilities()){
for(ResourceAvailability required : event.getResourceAvailabilities()){
if(availability.equals(required)){
resources += required.getQuantity();
quantity += availability.getQuantity();
}
}
}
// Soft constraints
int resourcesAvailable = quantity - resources;
if (resourcesAvailable < 0) {
softScore += resourcesAvailable;
}
This is working but it is slow,i want to get equivalent drools code for this soft score calculation logic.
So how to write drools code for this??
I checked drools file of machine reassignment problem,but could not relate it with my problem.
Here Event is my planning entity and EventDate is planning variable.
I am writing drools rule like :
rule "requiredResources"
when
$eventDate : EventDate()
$requiredResources : Number(intValue > 1) from accumulate(
Event(
eventDate == $eventDate,
//here logic for comparing required and available resource and then find
//sum of required resources and available resoulces
//add difference to score
),
sum($quantity)
)
then
System.out.println($requiredResources+$availableResources);
end
From the machine reassignment example:
rule "machineUsage"
when
$machineCapacity : MrMachineCapacity($machine : machine, $resource : resource)
accumulate(
$processAssignment : MrProcessAssignment(machine == $machine),
$usageTotal : sum($processAssignment.getUsage($resource))
)
then
scoreHolder.addHardConstraintMatch($capacity - $usage); // see docs chapter score calculation
end

Angular select box with 2 values

I want to have a select box with a list of price range.
Example:
- 0 to $2,000
- $2,000 to $3,500
- $3,500 to $5,000
- $5,000 to $7,500
- $7,500 to $10,000
- $10,000
When the user select one option I want to set the budget range:
For instance if the user clicks on - $3,500 to $5,000 then is set the following values:
$scope.var.x = 3500;
$scope.var.y = 5000;
I would like to do this directly on a partial if possible.
That's something easy to do if you have correctly understood the Angular principles. I think that you have something like an array which contains your price ranges:
$scope.ranges = [
{start : 0, end : 2000},
{start : 2000, end : 3500},
{start : 3500, end : 5000},
{start : 5000, end : Infinity}
];
Then, simply construct your <select> menu from this array:
<select ng-model="selectedRange" ng-options="range as '$' + range.start + ' to $' + range.end for range in ranges"></select>
Fiddle
Notice that if you have just a list of price…
$scope.ranges = [0, 2000, 3500, 5000];
… it's not really difficult to reconstruct the first object I've shown.

Resources