OptaPlanner, excluded solution shows up - optaplanner

Please help me to understand DRL with this simple task assignment project. 2 workers id=1 and 2, 3 tasks id=1,2,3, each task has a duration in second. The duration for task 1 and 3 is a little bit more than task 2. At beginning I use following rule (only one rule) trying to balance total time for each worker, So I expect one worker takes task 1 and 3 while the other takes task 2.
rule "fairness"
when
$worker: Worker()
accumulate(
Task(worker == $worker, $d: durationInSec);
$s: sum($d*$d)
)
then
scoreHolder.addSoftConstraintMatch(kcontext, -$s.longValue());
end
the result is all tasks are ALWAYS assigned to worker 1. I wanted to debug the issue and replaced the rule above with following 2 rules:
rule "A"
when
$worker: Worker(id == 1) // for worker 1
then
scoreHolder.addHardConstraintMatch(kcontext, -1); // hard score -1
end
rule "B"
when
$worker: Worker(id == 2) // for worker 2
then
scoreHolder.addSoftConstraintMatch(kcontext, 1); // soft score +1
end
I thought worker 1 would be excluded because of rule "A", but the result was still, worker 1 got all 3 tasks, with this output:
o.o.c.i.l.DefaultLocalSearchPhase : Local Search phase (1) ended: time spent (30001), best score (-3hard/3soft), score calculation speed (7309/sec), step total (12948).
o.o.core.impl.solver.DefaultSolver: Solving ended: time spent (30002), best score (-3hard/3soft), score calculation speed (7258/sec), phase total (2), environment mode (NON_REPRODUCIBLE)
I expect worker 2 takes all 3 tasks with score 0hard/3soft. Following is part of my Solution class, where is the problem?
#PlanningSolution
#Entity
public class Solution {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private SolverStatus solverStatus;
#PlanningScore
private HardSoftLongScore score;
#ProblemFactCollectionProperty
#OneToMany
#ValueRangeProvider(id = "workerRange")
private List<Worker> workerList;
#PlanningEntityCollectionProperty
#OneToMany
private List<Task> taskList;
...
#Entity
#PlanningEntity
public class Task implements Comparable<Task> {
#PlanningId
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(cascade=CascadeType.ALL)
#PlanningVariable(valueRangeProviderRefs = "workerRange")
private Worker worker;
When putting a println in RHS I do see both worker 1 and 2 are printed out:
System.out.println("worker=" + $worker.toString() + ", task=" + $tb.toString() + "; " +
scoreHolder.getHardScore() + "hard/" + scoreHolder.getHardScore() + "soft");
...
worker=1, task=2; -3hard/-3soft
worker=1, task=1; -3hard/-3soft
worker=2, task=3; -3hard/-3soft
worker=2, task=2; -3hard/-3soft
worker=2, task=1; -3hard/-3soft
worker=1, task=3; -3hard/-3soft
worker=2, task=1; -3hard/-3soft
worker=2, task=1; -3hard/-3soft
...

The rules "A" and "B" penalize/reward purely for the existence of these two workers, they don't say anything about any tasks assigned to them.
At the first glance, I don't see anything wrong with the first constraint ("fairness"). You can always add System.out.println(...) in the then section of the rule to debug it.
Alternatively, if you prefer Java to DRL, maybe the ConstraintStreams API could be interesting for you.

Related

OptaPlanner, could PlanningVariable be set to null which is not in the range

optaplanner-bom 7.59.0.Final. In my PlanningEntity class Task there is a PlanningVariable and a CustomShadowVariable
#PlanningVariable(valueRangeProviderRefs = "indexRange")
private Index index;
#CustomShadowVariable(variableListenerClass = UpdatingVariableListener.class,
sources = { #PlanningVariableReference(variableName = "index") })
private Long d;
in the PlanningSolution class the range is referred:
#ProblemFactCollectionProperty
#ValueRangeProvider(id = "indexRange")
private List<Index> indexList;
the rule file is to minimize the sum of all "d"s:
rule
when
accumulate(
Task(index != null, $d: d);
$s: sum($d)
)
then
scoreHolder.addSoftConstraintMatch(kcontext, 1, (int)(-$s));
end
in the afterVariableChanged() of the UpdatingVariableListener, by calling scoreDirector.getWorkingSolution(), I can see in the variable "indexList" there are two elements (let's call them "1" and "2") and none of them is java "null". When I set breakpoint in the afterVariableChanged(), with the first hit the "index" is "2", the second time it's "1", the third time is java "null". And noticed that for the second time and third time, the solution object are the same object. Do not think "null" should be set as it's not in the range. Anything wrong was done?

How to count time in chisel with iotesters?

Is there a way to get the step value in iotesters ?
Currently I'm using a var counter but I'm sure there is a better way :
class MyTest (dut: MyModule) extends PeekPokeTester(dut) {
var timeCounter = 0
for(i <- 0 to 10) {
step(1)
timeCounter = timeCounter + 1
}
println("Step value is " + timeCounter)
Is there a getStepValue() like function to get that ?
You can get this using the (presently undocumented) method t.
There's an internal var simTime that is tracking time. This is automatically incremented on a step (just like how you're doing it). The method t lets you query the query its value.

Get Unique Code using Singleton - ASP.NET Core

I am using ASP.NET Core 1.1 with Entity Framework Core 1.1.
I try with below code to get unique "Item Code" whenever user creates item into the system. This case is about to handle concurrency / multiple request for item creation. I have done similar to this using "Singleton" class in ASP.NET, but in case of ASP.NET CORE, I have got duplicate values(only at few instance) for "Item Code". Hence just want to make sure that the code here is correct with respect to getting different "Item Code" for each request.
----------- Injecting Dependency ---------------
namespace Microsoft.Extensions.DependencyInjection
{
public static class StartupExtensions
{
public static IServiceCollection AddCloudscribeCore(this IServiceCollection services, IConfigurationRoot configuration)
{
// Add application services.
services.AddSingleton<ISingletonService, SingletonService>(); // this will create singleton instance of class.
return services;
}
}
}
----- Singleton Service -------------------
public class SingletonService : ISingletonService
{
private readonly AppDbContext _context;
public SingletonService(AppDbContext context)
{
_context = context;
}
public CommonResult GetUniqueCode(Guid tenantId)
{
CommonResult result = new CommonResult();
string newCode = string.Empty;
var query = (from tenant in _context.Tenants
join item in _context.InventoryItems on tenant.TenantId equals item.TenantId into tenantItemJoin
from subItem in tenantItemJoin.DefaultIfEmpty()
where tenant.TenantId == tenantId || subItem.ItemCode.Contains("I-")
orderby subItem.CreatedUtc descending
select new TenantItem
{
TenantCode = tenant.TenantCode,
ItemCode = (subItem != null ? (subItem.ItemCode == string.Empty ? string.Empty:subItem.ItemCode) : string.Empty)
}).FirstOrDefault();
if (query != null)
{
string tenantCode = query.TenantCode.Substring(2);
if (!string.IsNullOrEmpty(query.ItemCode))
{
int code = Convert.ToInt32(query.ItemCode.Substring(2)) + 1;
if (code < 10)
newCode = "I-00000" + code;
else if (code >= 10 && code < 100)
newCode = "I-0000" + code;
else if (code >= 100 && code < 1000)
newCode = "I-000" + code;
else if (code >= 1000 && code < 10000)
newCode = "I-00" + code;
else if (code >= 10000 && code < 100000)
newCode = "I-0" + code;
else if (code >= 100000 && code < 1000000)
newCode = "I-" + code;
else
newCode = "I-" + code;
}
else
{
newCode = "I-000001";
}
TenantItem tenantItem = new TenantItem();
tenantItem.TenantCode = tenantCode;
tenantItem.ItemCode = newCode;
result.Succeeded = true;
result.Object = tenantItem;
}
return result;
}
}
------------- API Controller -------------
[HttpGet]
public CommonResult GetItemCode()
{
CommonResult result = new CommonResult();
result = _singletonService.GetItemCode(tenantId);
TenantItem tenantItem = (TenantItem)result.Object;
}
If I see the output/values in database, I see couple of entries(where the data-entry time difference is in milliseconds) have duplicate ID. See below extracts,
ItemCode CreatedUTC
I-000045 2017-10-31 11:06:10.6419557
I-000045 2017-10-31 11:06:10.5482045
I-000044 2017-10-31 11:03:58.0772064
I-000043 2017-10-31 11:03:57.7803288
I-000042 2017-10-31 11:03:04.1054090
I-000042 2017-10-31 11:03:03.9632107
I-000032 2017-10-25 17:39:04.7054946
I-000031 2017-10-25 17:34:34.7300091
I-000030 2017-10-25 17:24:15.8891966
I-000029 2017-10-25 17:19:36.2187677
I-000028 2017-10-25 17:06:19.8946515
I-000027 2017-10-25 17:03:45.8059024
I-000026 2017-10-25 11:48:59.2262869
I-000025 2017-10-25 11:47:15.5935031
I-000024 2017-10-25 11:45:31.8251470
I-000023 2017-10-25 11:43:55.6671755
I-000022 2017-10-25 06:33:27.2546438
I-000019 2017-10-24 11:27:05.2224204
I-000016 2017-10-24 10:21:09.5983741
I-000015 2017-10-24 10:18:54.7954042
I-000011 2017-10-24 09:19:04.9033847
I-000010 2017-10-24 09:17:29.0905153
I-000008 2017-10-23 11:48:12.0188814
I-000007 2017-10-23 08:50:17.0785334
I-000006 2017-10-23 08:46:36.6120703
I-000005 2017-10-23 08:01:15.3829637
Please suggest if I am missing anything here.
This is why it's better to let the database handle identity-style columns. Regardless, this doesn't have anything to do with singletons and such; it's simple database concurrency. Singleton or not, you're running a query on a database table to fetch the latest "id", incrementing it, and saving a new record. However, unless you issue a lock on the table (which is a bad idea, by the way), other requests invoking this same operation could be being carried out. Long and short, your code is not thread-safe.
The way to make it thread safe is to either 1) create locks or 2) rely on a unique constraint and employ a catch-and-retry policy. Since #1 is almost always a bad idea, especially in a database scenario, #2 should be your preferred path.
Simply, if this value should be unique, then there should be a unique constraint on the column in the database. Since you're able to actually create duplicates, that's obviously not the case. However, if you correct that, then attempt to save a dupe will result in a database exception, which will bubble up and can be caught by your application. You can then catch this exception and retry the operation, fetching the latest "id", again, incrementing that, again, and attempting to save, again. Rinse and repeat until it goes through without issue.
This does mean that the operation could take a little longer to complete, as it may have to do multiple roundtrips to the database before it can nail down an available "id", but it's the only safe way to accomplish this, if you refuse to use an identity column.
1. Your database context should not be embedded in a service using the singleton lifetime. Unless you specified otherwise when registering your AppDbContext, it is set to the 'scoped' lifetime. I recommend you also use a scoped lifespan for the service that contains your database context.
2. I would allow the database to set the unique Id for your item code. It has builtin mechanisms to support concurrency and ensure uniqueness. In my opinion it makes sense to leverage those. You can use an auto-incrementing Id on your InventoryItem table and either mark it as the primary key or add a unique constraint on the column.
References:
Entity Framework Core service default lifetime
Two gotchas with scoped and singleton dependencies in ASP.NET Core

JPA 2, understanding CascadeType.ALL and GenerationType.AUTO (EclipseLink 2.5)

I am having trouble to understand how properly persist entities with sub-entities when the JVM has been restarted and the database already contains data from previous sessions.
I have roughly the following entities:
#Entity
public class Organization {
...
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
#JoinColumn(name = "\"ADDRESS_ID\"", nullable = false)
private Address address;
}
#Entity
public class Address {
...
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "\"ADDRESS_ID\"")
private int addressId;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.MERGE, optional = false)
#JoinColumn(name = "\"ADDRESS_TYPE_ID\"", nullable = false)
private AddressType addressType;
}
#Entity
public class AddressType {
...
// Not bi-directional, so nothing special here
}
It is excpected that the address types are present in the database (CascadeType.MERGE) before creating an address. A new organization is created with a new address and the address has a type set from the given selection. => This works ok when there is a clean database (only address types present).
Still developing, so every now and then I do shutdown the server (JVM) and restarted the application. Then I want to add a new organization to database which already contains data persisted in previous sessions, then I get the following error:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL151120084237691' defined on 'ADDRESS'.
Error Code: -20001
Call: INSERT INTO "ADDRESS" ("ADDRESS_ID", "STREET_ADDRESS", "COUNTRY", "ZIP_CODE", "CITY", "ADDRESS_TYPE_ID") VALUES (?, ?, ?, ?, ?, ?)
bind => [2, testroad 1, Country, 99999, testcity, ABCDEF-123456]
It tries to use the same ID as already exists in the database. How do I make it realize that the id is already used and it should continue from last?
Notes:
- The address is persisted as part of the organization (CascadeType.ALL) not separately.
- In tests, I am loading all the existing organiztations to the same EntityManager that does the persisting operation => The organization has its addresses accessed eagerly, so they should be available in the em-cache. The duplicate address_id it complains about in unit tests seems to be an orphan entity (maybe this is the reason of the error actually?).
- I can get this error in unit tests using Derby, but a test server using Oracle DB has these same errors in log.
- I also tried adding a 'find all' query to load all address-entities into the cache of the same EntityManager that does the persisting operation of organization. The 'find all' is executed is before the persisting is done => it still failed.
// UPDATE
This same thing happens even that I use TableGenerator to get the id values.
#Entity
public class Address {
...
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "addr_gen")
#TableGenerator(name = "addr_gen", allocationSize = 1, initialValue = 100, table = "\"ADDRESS_GEN\"")
#Column(name = "\"ADDRESS_ID\"")
private int osoiteId;
...
}
The generator table gets created, but it remains empty. The id's however start running from the initial value of '100'.
Some more notes:
- When using self defined table and inserting a value there for the sequence, the id for address-entities continues correctly from that value. When the test is finsihed, the table gets emptied while there still remains data in the tables => Will fail next time.
- When using GenerationType.AUTO, the sequence table gets a default sequence, but after tests it is cleared (same thing as with self defined table)
^I guess this has happened in test servers and it can be duplicated by not emptying the database after test. However the sequence table gets emptied. So the question would be, how to synchronize the sequence table after JVM boot (or prevent it from not emptying itself)?
I do not know if this a good solution or even right in general for original topic, but I managed to make some kind of workaround by defining the sequences separately for all auto-generated id fields.
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "addrSeq")
#SequenceGenerator(name = "addrSeq", sequenceName = "addr_seq", allocationSize = 10)
#Column(name = "\"ADDRESS_ID\"")
private int addressId;
It seems to work, though I do not know why this behaves essentially differently than using 'AUTO'?
Is it normal that the default sequence is nulled when the server is restarted?

Updating object doesn't work properly in Hibernate 3

Pojo object:
public class Test {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private Integer id;
private String name;
#Column(columnDefinition="int default 100")
private int number;
.....getter and setter........
}
Backend Action:
#ResponseBody
#RequestMapping(value= "/common/index3")
public String index3(){
Session session = sessionFactory.getCurrentSession();
Test t = session.get(Test.class, 1);
t.setNumber(t.getNumber() - 1);
System.out.println("invoked");
session.update(t);
return "success";
}
Web page ajax trigger
$(document).ready(function(){
for(var i = 0; i < 3; i ++){
$.post("/common/index3");
}
}
issue
from client side I sent 3 times requests to backend action, and the action was invoked properly 3 times as well, however, in database the 'Number' column only was deducted 1 time, after invoked 3 times, column value become from 100 to 99, I don't know why it was only deducted 1 time, the expected value should be 97, I tried to flush & clear session to avoid the hibernate3 cache issue, anybody know how to solve this?
thank you.
From what I can see, your transactions aren't being committed to the database. You should use transactions while communicating with the DB.
After starting your session, start the transaction with
Transaction tx = session.beginTransaction()
and after completing your queries, commit them to the DB with a tx.commit().