OptaPlanner - ConstraintStreams - Disabling constraints dynamically - optaplanner

I am using Java ConstraintStreams for constraint implementation and need to enable/disable the constraints dynamically.
Following the suggested approach in this answer Optaplanner : Add / remove constraints dynamically using zero constraint weight seems to work as expected (the score is different compared to when the constraint is enabled) but when I put a log in the constraint implementation the log was printed which suggests that the constraint is actually being evaluated even if the score is set to zero.
private Constraint minimizeCost(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CloudProcess.class)
.filter(process -> {
System.out.println("Minimize computer cost");
return process.getComputer() != null;
})
.penalizeConfigurable("computerCost",
node -> (Integer) process.getComputer.getCost());
}
For Disabling the constraint I am using
new CloudBalance().setConstraintConfiguration(new CloudBalanceConstraintConfiguration()
.computerCost(HardMediumSoftScore.ZERO))
I have modified the CloudBalancing example to make it similar to what I am trying to implement.
So is there something that I am missing in terms of understanding/implementation ?
Will the disabled constraint still execute regular stream operations like filter and skip OptaPlanner specific operations like ifExists, joins etc.?
Is there any way to prevent this behavior ? (currently I am working with version 8.16.0.Final)

You are correct that part of the constraint may still be executed. But constraint weight of zero makes sure that no constraint will ever match - they may have a cost in terms of performance, but they will not affect the score nor justifications.
There is nothing else you could do, other than generating a different ConstraintProvider every time. In the future, we may improve constraint disabling so that the constraints are disabled entirely.

Related

How would you write this model validation as a SQL constraint?

I have this validation in a Model for a number attribute, and I also want to add a database constraint. How would you do this? would you add an index or partial index to satisfy the scope and the if statements?
validates :number,
numericality: { greater_than: 0 },
uniqueness: { scope: :tenant_id },
unless: state == 'pending',
if: :number
I'm thinking about this migration to create the constraint but I'm not sure it is the best way
def change
reversible do |dir|
dir.up do execute <<-SQL
ALTER TABLE work_orders
ADD CONSTRAINT number_uniqueness_constraint
CHECK ( number IS NULL OR number NOT IN
( SELECT number
FROM work_orders
WHERE tenant_id = work_orders.tenant_id )
)
SQL
end
end
end
Business constraints should be defined both in the database as a hard constraint (if possible) as well as within Rails.
The advantage of having the constraint within your database is that this strictly ensures that your dataset is valid as the database will not allow to break the constraint. The disadvantage of this however is that if there is a query which tries to break the constraint, the error message will not be a great user experience.
Within Rails, you get great messages for each constraint and can handle errors very well. This works great for e.g format constraints (such as the numericality check). For uniqueness constraints however, there is the possibility for race conditions, as in parallel requests, the uniqueness check and later commit can overlap, resulting in a failed constraint.
Because of that, it is often a good idea to define constraints in both places. The Rails constraint will result in good error messages for most cases, the SQL constraint will strictly ensure valid data, even when there are races.
With that being said, your Rails constraint currently doesn't matych your Postgres constraint. You are missing the unless rule. For the uniqueness constraint, you may also use a much simpler combined UNIQUE constraint for the two columns, rather that writing your own sub-query, depending on how exactly you plan to resolve your edge-cases (i.e. the unless and if rules of your Rails validation).

OptaPlanner: Mixing constraint and for-next based score calculation

I am implementing several restrictions within my CustomizedConstraintProvider class using the streaming API. Nevertheless there is one special case, where I currently do not see how to get this properly implemented within the streaming API.
If I got several methods ...
private Constraint Restriction1(ConstraintFactory constraintFactory) {
return constraintFactory
.forEach(Class.class)
...
.penalize("Restriction1", HardMediumSoftBigDecimalScore.ONE_HARD)
}
private Constraint Restriction2(ConstraintFactory constraintFactory) {
return constraintFactory
.forEach(Class.class)
...
.penalize("Restriction2", HardMediumSoftBigDecimalScore.ONE_SOFT)
}
private Constraint Restriction3(ConstraintFactory constraintFactory) {
return constraintFactory
.forEach(Class.class)
...
.penalizeBigDecimal("Restriction3", HardMediumSoftBigDecimalScore.ONE_MEDIUM,
(a, b, c) -> BigDecimal.valueOf(Math.pow((b - c), a))
}
how can I implement one particular method (let's say "Restriction4" that runs with for-next loops, accessing the assignment lists and returning medium and soft scores at the end depending on the evaluation within the ConstraintFactroy approach? In the manual I only read this as an either or approach (TimeTableEasyScoreCalculator vs. TimeTableConstraintProvider in chapter 2 of the manual for the current OptaPlanner version 8.19.0). I am aware that the looping way scales way more poorly than the streaming alternative but this shall be a basis to get later into the more complex Constraint Stream Score Calculation having a working solution on hand for comparison.
Thanks in advance!
The easy and entirely unhelpful answer is that you can not use for-style loops in constraint streams.
The Constraint Streams API is designed to give you incremental performance, and therefore you need to think of your constraints in a certain way. This way is not always easy to learn, and it requires practice. That said, we have not yet seen a constraint which we could not implement incrementally.
For example, groupBy is a very powerful construct which allows you to transform your data in pretty much any way you want. If you implement a custom constraint collector, you can solve even very complex problems incrementally.
However, some users simply use groupBy() together with the toList() constraint collector, gather all their data in a single collection, and then penalize on that. I will not give an example of that, as it is an anti-pattern which leads to poor performance, and we generally discourage it.

Get number of attached constraints on a variable in MiniZinc

I have two sets of variables in my Minizinc program. Each variable from the first set necessarily has several constraints placed on it, but the variables in the second set are only implicitly constrained via their interactions with variables in the first set. This means that each of the variables in the second set may have anywhere from 0 to ~8 constraints placed on it, depending on the values taken by the variables in the first set.
I see that there is a way to reference the number of constraints placed on a variable at search time via the dom_w_deg search annotation, but I was wondering if there was anyway to access this information at runtime? I want to do this because I would like to specify additional constraints related to the number of constraints already placed on the variables.
I realize this is a weird question, and I may be approaching this whole thing the wrong way, but I've been banging my head against this problem for a while now, so figured I'd ask.
As a general rule, I think that you are approaching your problem erroneously. There are several mis-conceptions in the approach that I can identify leading to this:
Different solver back-ends might do very different things with the model and how it is solved
"A constraint" is not a meaningful concept for the solver. A single constraint might be multiple propagators in the back-end solver, a single propagator, or even just part of a propagator covering several constraints (assuming that it is a propagator based back-end).
Constraint models have monotonic behavior, so you can not in a well-defined and meaningful way change the model based on the number of constraints connected to a variable.
Given that a constraint maps to a single propagator, it may still have very different propagation strength, meaning that it might be done early or very late in the solving process.
Without knowing what you are actually trying to achieve, as a general technique you might be interested in using reification, where the truth of a constraint is reflected onto a binary Boolean variable. In general, it is good practice to have as little reification as possible, since it does not propagate much, but sometimes it is needed.
As a very simple example of using reification, this is a (probably not very good) model that tries to maximize the number of constraints satisfied.
set of int: Domain = 1..10;
var Domain: x;
var Domain: y;
var Domain: z;
array[1..3] of var bool: holds;
constraint holds[1] <-> x < y;
constraint holds[2] <-> y < z;
constraint holds[3] <-> z < x;
var int: goal;
constraint goal = sum(holds);
solve maximize goal;

What's the reason / usefulness is to use ENABLE keyword in oracle database statements

I would like to know what's the advantage or usefulness of using ENABLE keyword, in statements like:
CREATE TABLE "EVALUATION" (
"EVALUATION_ID" NUMBER(20, 0) NOT NULL ENABLE,
OR
ALTER TABLE "EVALUATION"
ADD CONSTRAINT("EVALUATION_FK")
FOREIGN KEY ("CREW_ID")
REFERENCES "CREW" ("CREW_ID") ENABLE;
For what I read in the documentation, ENABLE is on by default.
Could I assume it is just to enable something that has been previously disabled?
Constraint doc:
CREATE TABLE "EVALUATION" (
"EVALUATION_ID" NUMBER(20, 0) NOT NULL ENABLE,
ENABLE/DISABLE indicates that constraint is on or off. By default ENABLE is used.
ENABLE Clause Specify ENABLE if you want the constraint to be applied
to the data in the table.
DISABLE Clause Specify DISABLE to disable the integrity constraint.
Disabled integrity constraints appear in the data dictionary along
with enabled constraints. If you do not specify this clause when
creating a constraint, Oracle automatically enables the constraint.
Constraints are used to ensure data integrity, but there are scenarios we may need to disable them.
Managing Integrity:
Disabling Constraints
To enforce the rules defined by integrity constraints, the constraints
should always be enabled. However, consider temporarily disabling the
integrity constraints of a table for the following performance
reasons:
When loading large amounts of data into a table
When performing batch operations that make massive changes to a table (for example, changing every employee's number by adding 1000 to
the existing number)
When importing or exporting one table at a time
In all three cases, temporarily disabling integrity constraints can
improve the performance of the operation, especially in data warehouse
configurations.
It is possible to enter data that violates a constraint while that
constraint is disabled. Thus, you should always enable the constraint
after completing any of the operations listed in the preceding bullet
list.
Efficient Use of Integrity Constraints: A Procedure
Using integrity constraint states in the following order can ensure
the best benefits:
Disable state.
Perform the operation (load, export, import).
Enable novalidate state.
Some benefits of using constraints in this order are:
No locks are held.
All constraints can go to enable state concurrently.
Constraint enabling is done in parallel.
Concurrent activity on table is permitted.
EDIT:
The question is rather why to use obvious keyword when it is turn on by default:
I would say:
For clarity (Python EIBTI rule Explicit Is Better Than Implicit)
For completness
Personal taste and/or coding convention
This is the same category as:
CREATE TABLE tab(col INT NULL)
Why do we use NULL if column is nullable by default.

What is the purpose of constraint naming

What is the purpose of naming your constraints (unique, primary key, foreign key)?
Say I have a table which is using natural keys as a primary key:
CREATE TABLE Order
(
LoginName VARCHAR(50) NOT NULL,
ProductName VARCHAR(50) NOT NULL,
NumberOrdered INT NOT NULL,
OrderDateTime DATETIME NOT NULL,
PRIMARY KEY(LoginName, OrderDateTime)
);
What benefits (if any) does naming my PK bring?
Eg.
Replace:
PRIMARY KEY(LoginName, OrderDateTime)
With:
CONSTRAINT Order_PK PRIMARY KEY(LoginName, OrderDateTime)
Sorry if my data model is not the best, I'm new to this!
Here's some pretty basic reasons.
(1) If a query (insert, update, delete) violates a constraint, SQL will generate an error message that will contain the constraint name. If the constraint name is clear and descriptive, the error message will be easier to understand; if the constraint name is a random guid-based name, it's a lot less clear. Particulary for end-users, who will (ok, might) phone you up and ask what "FK__B__B_COL1__75435199" means.
(2) If a constraint needs to be modified in the future (yes, it happens), it's very hard to do if you don't know what it's named. (ALTER TABLE MyTable drop CONSTRAINT um...) And if you create more than one instance of the database "from scratch" and use system-generated default names, no two names will ever match.
(3) If the person who gets to support your code (aka a DBA) has to waste a lot of pointless time dealing with case (1) or case (2) at 3am on Sunday, they're quite probably in a position to identify where the code came from and be able to react accordingly.
To identify the constraint in the future (e.g. you want to drop it in the future), it should have a unique name. If you don't specify a name for it, the database engine will probably assign a weird name (e.g. containing random stuff to ensure uniqueness) for you.
It keeps the DBAs happy, so they let your schema definition into the production database.
When your code randomly violates some foreign key constraint, it sure as hell saves time on debugging to figure out which one it was. Naming them greatly simplifies debugging your inserts and your updates.
It helps someone to know quickly what constraints are doing without having to look at the actual constraint, as the name gives you all the info you need.
So, I know if it is a primary key, unique key or default key, as well as the table and possibly columns involved.
By correctly naming all constraints, You can quickly associate a particular constraint with our data model. This gives us two real advantages:
We can quickly identify and fix any errors.
We can reliably modify or drop constraints.
By naming the constraints you can differentiate violations of them. This is not only useful for admins and developers, but your program can also use the constraint names. This is much more robust than trying to parse the error message. By using constraint names your program can react differently depending on which constraint was violated.
Constraint names are also very useful to display appropriate error messages in the user’s language mentioning which field caused a constraint violation instead of just forwarding a cryptic error message from the database server to the user.
See my answer on how to do this with PostgreSQL and Java.
While the OP's example used a permanent table, just remember that named constraints on temp tables behave like named constraints on permanent tables (i.e. you can't have multiple sessions with the exact same code handling the temp table, without it generating an error because the constraints are named the same). Because named constraints must be unique, if you absolutely must name a constraint on a temp table try to do so with some sort of randomized GUID (like SELECT NEWID() ) on the end of it to ensure that it will uniquely-named across sessions.
Another good reason to name constraints is if you are using version control on your database schema. In this case, if you have to drop and re-create a constraint using the default database naming (in my case SQL Server) then you will see differences between your committed version and the working copy because it will have a newly generated name. Giving an explicit name to the constraint will avoid this being flagged as a change.