-
-
Notifications
You must be signed in to change notification settings - Fork 88
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
Is it possible to get the absolute value of an expression? #163
Comments
Ah, as I wrote this, I thought maybe I can add all of these constraints ( I'll test it out and close this issue if it works. |
It worked, sorry for the noise. |
There is a problem with the idea mentioned above. I was under the impression that the algorithm would always return a result that minimizes the number of broken constraints (weighted by strength). That is, if there are two "strong" constraints where one can be satisfied but not both, the solution will have at least one of those constraints satisfied. But it seems like this is not the case. Here's an example: from kiwisolver import Solver, Variable
x = Variable("x")
s = Solver()
s.addConstraint(x >= 0)
s.addConstraint((x == -10) | "strong")
s.addConstraint((x == 10) | "strong")
s.updateVariables()
print(x.value()) This prints Similar to #164, it seems like order of constraints matters. For example: from kiwisolver import Solver, Variable
x = Variable("x")
s = Solver()
s.addConstraint(x >= 0)
s.addConstraint((x == 10) | "strong")
s.addConstraint((x == -10) | "strong")
s.updateVariables()
print(x.value()) This prints out 10.0, but in a real application it won't be clear what order the constraints should be added in. So I'm stuck on my original question about absolute value. Maybe there's some way to pick custom strengths to get this to work, but I'm not sure what those strengths would be. |
This is actually the correct solution, because both “strong” constraints
have the same strength. So the solver has correctly minimized the error in
the system.
If you want one constraint to be more strong than another, you need to use
numerical weights instead of string symbolic weights.
Under the hood, “strong” is just defined as a fixed numerical weight anyway.
…On Tue, Jun 6, 2023 at 19:27 Gulshan Singh ***@***.***> wrote:
There is a problem with the idea mentioned above. I was under the
impression that the algorithm would always return a result that minimizes
the number of broken constraints (weighted by strength). That is, if there
are two "strong" constraints where one can be satisfied but not both, the
solution will have at least one of thoconstraints satisfied. But it seems
like this is not the case.
Here's an example:
from kiwisolver import Solver, Variable
x = Variable("x")
s = Solver()
s.addConstraint(x >= 0)
s.addConstraint((x == -10) | "strong")
s.addConstraint((x == 10) | "strong")
s.updateVariables()
print(x.value())
This prints 0.0, which violates both strong constraints, despite the fact
that 10.0 would have only violated one strong constraint.
Similar to #164 <#164>, it seems
like order of constraints matters. For example:
from kiwisolver import Solver, Variable
x = Variable("x")
s = Solver()
s.addConstraint(x >= 0)
s.addConstraint((x == 10) | "strong")
s.addConstraint((x == -10) | "strong")
s.updateVariables()
print(x.value())
This prints out 10.0, but in a real application it won't be clear what
order the constraints should be added in. So I'm stuck on my original
question about absolute value. Maybe there's some way to pick custom
strengths to get this to work, but I'm not sure what those strengths would
be.
—
Reply to this email directly, view it on GitHub
<#163 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABBQSMV7LWNRQY2AHORRQLXJ7DFHANCNFSM6AAAAAAYUI5KZ4>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Just for a quick reference, here are the defaults: Lines 18 to 34 in 26051dd
|
Sorry, I didn't follow this. Both strong constraints have the same strength. But both are violated. Why is this the minimal error when an additional strong constraint could be satisfied? |
It’s all a minimization problem. All non-required strengths can be violated
and the solution still be correct, by definition.
In your example, when one ‘strong’ constraint is solved, the opposite is
broken by ‘twice as much’. Since it is a linear system, the net error is
the same.
To put it another way, your system of constraints is under defined, and has
multiple solutions of minimum error. When presented with multiple
solutions, which one the solver picks is more or less undefined.
Your job as the programmer is to setup a system that only has one solution.
On Tue, Jun 6, 2023 at 22:45 Gulshan Singh ***@***.***> wrote
… This is actually the correct solution, because both “strong” constraints
have the same strength. So the solver has correctly minimized the error in
the system.
Sorry, I didn't follow this. Both strong constraints have the same
strength. But both are violated. Why is this the minimal error when an
additional strong constraint could be satisfied?
—
Reply to this email directly, view it on GitHub
<#163 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABBQSMRZR5D32LFMMVD7OTXJ72MNANCNFSM6AAAAAAYUI5KZ4>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Are you referring to the second example? If so, I think that makes sense. Are you saying that when the This wouldn't apply in the first example though, as when the To understand this better I tried to dump the state of the Solver, but I don't really understand it: from kiwisolver import Solver, Variable
x = Variable("x")
s = Solver()
print("Adding constraint: x >= 0")
s.addConstraint(x >= 0)
print(s.dumps())
print("Adding constraint: x == -10")
s.addConstraint((x == -10) | "strong")
print(s.dumps())
print("Adding constraint: x == 10")
s.addConstraint((x == 10) | "strong")
print(s.dumps())
s.updateVariables()
print(x.value()) Output:
I did some reading Simplex to understand the tableau, and then skimmed the Cassowary paper, but how the Objective and Tableau ends up with these values is still unclear to me. From this output, it is possible for me to manually compute the error of different solutions to better understand what's going on?
But back to the original problem, it's not that I know that I want one constraint to be stronger, it's that I have two constraints that are opposites and I know that only one will be satisfied, but I don't know which one. How would numerical constraints be any different than this (which again doesn't work because I won't know which one to make "weak"):
With this |
You have to think about it in terms of minimizing the total error in the
system.
If there are multiple solutions in the system that result in the same
error, the solver will just "pick one". Which one it picks is
non-deterministic and will depend on the order you add constraints because
that ultimately affects the order of pivots in the internal sparse matrix.
In your example, the value for `x` can be anything from `0 to 10` and
still result in the same value of the objective function.
If you have a preference for positive values, try adding a `weak`
constraint to some very large value.
Ultimately, you are trying to express non-linearity in a linear system. You
may or may not be reliably successful.
…On Wed, Jun 7, 2023 at 2:17 AM Gulshan Singh ***@***.***> wrote:
In your example, when one ‘strong’ constraint is solved, the opposite is
broken by ‘twice as much’.
Are you referring to the second example? If so, I think that makes sense.
Are you saying that when the x == 10 constraint is added it is satisfied,
and then when the x == -10 constraint is added, the solver does not want
to break the already satisfied constraint?
This wouldn't apply in the first example though, as when the x == -10
constraint is added, no strong constraints are satisfied. When the x == 10
constraint is added next, no constraints would be broken if the value of x
was set to 10, and this additional constraint would be satisfied. This is
what I'm confused about.
To understand this better I tried to dump the state of the Solver, but I
don't really understand it:
from kiwisolver import Solver, Variable
x = Variable("x")
s = Solver()print("Adding constraint: x >= 0")s.addConstraint(x >= 0)print(s.dumps())
print("Adding constraint: x == -10")s.addConstraint((x == -10) | "strong")print(s.dumps())
print("Adding constraint: x == 10")s.addConstraint((x == 10) | "strong")print(s.dumps())
s.updateVariables()print(x.value())
Output:
Adding constraint: x >= 0
Objective
---------
Tableau
-------
v1 | + 1 * s2
Infeasible
----------
Variables
---------
x = v1
Edit Variables
--------------
Constraints
-----------
1 * x + -0 >= 0 | strength = 1.001e+09
Adding constraint: x == -10
Objective
---------
+ 1e+06 * s2 + 2e+06 * e4
Tableau
-------
v1 | + 1 * s2
e3 | + 1 * s2 + 1 * e4
Infeasible
----------
Variables
---------
x = v1
Edit Variables
--------------
Constraints
-----------
1 * x + -0 >= 0 | strength = 1.001e+09
1 * x + 10 == 0 | strength = 1e+06
Adding constraint: x == 10
Objective
---------
+ 2e+06 * e4 + 2e+06 * e5
Tableau
-------
v1 | + 1 * s2
e3 | + 1 * s2 + 1 * e4
e6 | + -1 * s2 + 1 * e5
Infeasible
----------
Variables
---------
x = v1
Edit Variables
--------------
Constraints
-----------
1 * x + -0 >= 0 | strength = 1.001e+09
1 * x + 10 == 0 | strength = 1e+06
1 * x + -10 == 0 | strength = 1e+06
0.0
I did some reading Simplex to understand the tableau, and then skimmed the
Cassowary paper, but how the Objective and Tableau ends up with these
values is still unclear to me. From this output, it is possible for me to
manually compute the error of different solutions to better understand
what's going on?
If you want one constraint to be more strong than another, you need to use
numerical weights instead of string symbolic weights.
But back to the original problem, it's not that I know that I want one
constraint to be stronger, it's that I have two constraints that are
opposites and I know that only one will be satisfied, but I don't know
which one. How would numerical constraints be any different than this
(which again doesn't work because I won't know which one to make "weak"):
s.addConstraint(x >= 0)
s.addConstraint((x == -10) | "weak")
s.addConstraint((x == 10) | "strong")
With this x is 10.0, but I had prior knowledge that that constraint was
the one that would be satisfied, which obviously won't be the case in real
applications.
—
Reply to this email directly, view it on GitHub
<#163 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABBQSLLMO2E27PF5OFH6LDXKATKPANCNFSM6AAAAAAYUI5KZ4>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
This worked, thanks 🙂 I added the
to
Again, I don't really get these equations yet, but I'll close this issue and keep investigating on my own. |
I saw here that absolute values are not linear constraints and so can't directly be added: #35 (comment)
I just wanted to follow up to see if there was any workaround for this, or if there are suggestions for other ways to deal with the problem I'm facing.
I have an
Arrow
object in my layout that will point from one object to another object. Specifically, it starts at xy coordinates(expr1, expr2)
and ends at(expr3, expr4)
. I would like to set the width of this object toabs(expr3 - expr1)
and the height toabs(expr4 - expr2)
. The absolute value is needed here because it shouldn't matter in what direction the arrow is going, the width will be the same. And I don't know which of the expressions will be greater than the other at this point, so I can't reorder the subtraction to always make it positive.Am I out of luck here or is there some other way to express this constraint with a linear constraint solver?
The text was updated successfully, but these errors were encountered: