-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot make constraint under if_then soft #176
Comments
Yeah, that if_then didn't get marked as a soft constraint when setting Field: a is_rand=True [[11, 4294967295]]
Field: b is_rand=True [[10, 10]]
Constraint: (a > 10);
Constraint: if ((a > 10)) {
(b == 1)}
Constraint: (b == 10); I tried to reference a dynamic constraint inside vsc.soft but hit a "TODO: support lambda references". @vsc.dynamic_constraint
def b_1_c(self):
with vsc.if_then(self.a > 10):
self.b == 1
@vsc.constraint
def ab_c(self):
vsc.solve_order(self.a, self.b)
self.a > 10
vsc.soft(self.b_1_c) |
@felixdube, @alwilson, Yes, unfortunately soft constraints are currently only supported as top-level constraints (not under if/else). @alwilson, I agree with your conclusion that soft constraints will need to be broken out during processing to ensure the proper conditional context is associated with each nested soft constraint. I can certainly see that getting a bit complicated... @felixdube, any feedback on how complex your intended usecase is? In other words, do you intend to have soft constraints nested under multiple levels of 'if'? Intend to have soft constraints nested in if/elsif/elsif/else structures? Let me give thought to how best to approach this. |
@mballance I don't think I'll be using multiple levels of 'if', but maybe if/elsif/elsif/else. That being said, I've been disabling that constraint when I use randomize_with to force a specific value on that random attribute. So far, it's not a blocking issue for me. |
I explored supporting nested soft constraints by extending push_constraint_stmt(). Instead of adding a nested soft constraint to the current constraint scope it duplicates the current constraint stack without the other hard constraints and places it inside a ConstraintSoftModel. I only targeted and tested if_then, but I don't think it would be much cover others. I'm not sure how ForEach and arrays might work, although I think arrays get expanded later, which would still work if they were a standalone constraint. Oh, and some debug output to see what it looks like with this method. The empty if looks weird, but boolector should throw away all of those, yeah? Final Model:
<anonymous> {
rand unsigned [32] a
rand unsigned [32] b
constraint ab_c {
if ((a > 10)) {
soft (b == 1)
}
solve a before b
(a > 10);
if ((a > 10)) {
}
}
}
constraint inline {
(b == 10);
}
RandSet[0]
Field: a is_rand=True [[11, 4294967295]]
Field: b is_rand=True [[10, 10]]
Constraint: (a > 10);
Constraint: if ((a > 10)) {
}
Constraint: (b == 10);
SoftConstraint: if ((a > 10)) {
soft (b == 1)
} |
@alwilson, thanks for starting to look into this! The approach I had in mind was to update the rand_info_builder as follows:
What do you think? Looking at an example:
|
@mballance Ah, so wait till after all the constraint expansion and bounds exploration. Then build up the soft constraint condition rather than reproduce the entire constraint stack. Does the bounds exploration take into account nested soft constraint? Or is there another bounds calculation after soft constraints are eliminated? |
@alwilson, my thinking would be to do this after expansion and before initial SAT and elimination of conflicting soft constraints. So:
|
@mballance Alright, I think I get what you described for overriding the rand_info_builder visitors to get if_then and implies to add conditions to a stack and then on the soft constraint visitor create an implies of all those conditions for the soft constraint. I added in a bit in there to remove the soft constraint from the original constraint_l, but I think that permanently changes the model such that future calls don't work since there are no soft constraints in the model. Is there a way to disable or prevent building the original nested soft constraints? I started looking at the rand_set_node_builder, but I'm still trying to grok what it's doing in |
@alwilson, really good point about the soft constraint being referenced from two places. Constraint objects are responsible for building themselves in the current PyVSC (and I regret that design decision every time we come to one of these issues...). Here's what I'm currently thinking:
pyvsc/src/vsc/model/constraint_soft_model.py Lines 20 to 21 in a4fc51c
What do you think? With respect the RandSetNodeBuilder, it's doing the following:
In the current PyVSC, each field/constraint object holds its own solver data structure. So, RandSetNodeBuilder only ensures that all these objects are built and stored (it's just a visitor). The code you reference in 'Randomizer' creates lists of (PyObj,SolveObj) pairs. I don't remember why I called the build() method again vs grabbing the cached object, but the build() method is smart enough to only build the constraint if it hasn't been built yet. |
One issue with this approach is that it's hard to see and debug what has actually happened with the constraints and Boolector objects. btor.Dump() doesn't help much either and isn't easy to parse. Even the Dump(format='smt2') is hard to follow. It would be nice if the pretty print for the constraints reflected what's happened. So in rand_set_node_builder there's a phase 0 and 1, and in phase 1 it's easy enough to intercept the c.build() on ConstraintSoftModel and use something like self.soft_phase to enable/disable building the soft constraint, but the part with the lists of (PyObj, SolveObj) it calls c.build() on each base constraint. I guess I could extend all build calls with the optional soft argument so that it gets passed down. Otherwise what I'm running into right now is that the rand_set_node_builder does the right thing by building hard constraints without soft and soft constraints with them enabled. Then build gets called again for those lists of tuples and it defaults to None for soft constraints in both hard and soft constraints and all soft constraints are lost. Maybe I missing a way to get that passed down. Hehe, I could also use a ConstraintSoftModel static variable to disable/enable building it globally, but that sounds like bad software design. :) |
Actually, I complained about adding the optional arg to the constraint_model build functions, but there's not that many that have build functions and it was pretty straightforward to pass down. So maybe it's not that bad! Seems to be passing tests now, although I probably should write new unit tests to really exercise nested soft constraints. |
The fixes that @alwilson provided to support nested soft constraints are in the 0.8.3 release. Please try this release and let us know of any issues. |
Just confirming that the fix works fine on my side! Thank you |
I have a constraint under an if_then, and I would like to make it soft, but it does not seem to work properly.
Here is a minimal example, which produce the following error:
vsc.model.solve_failure.SolveFailure: solve failure
The text was updated successfully, but these errors were encountered: