-
Notifications
You must be signed in to change notification settings - Fork 4
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
Using gomez for solving geometric constraints / intecepts #8
Comments
Yes, struct LineCircleIntersection {
a: f64,
b: f64,
c: f64,
d: f64,
r: f64,
} and implement all necessary traits: impl Problem for LineCircleIntersection {
// ...
}
impl System for LineCircleIntersection {
fn eval<Sx, Sfx>(
&self,
x: &na::Vector<Self::Scalar, Self::Dim, Sx>,
fx: &mut na::Vector<Self::Scalar, Self::Dim, Sfx>,
) -> Result<(), ProblemError>
where
Sx: na::storage::Storage<Self::Scalar, Self::Dim> + IsContiguous,
Sfx: na::storage::StorageMut<Self::Scalar, Self::Dim>,
{
// Fill `fx` which represents residuals of the system of equations.
// Use fields in `self`.
Ok(())
}
} All the trait bounds might feel overwhelming, that's because I use If you run into problems, feel free to ask here. |
Thanks so much for the pointers! Is there a requirement that the variable at index I was originally thinking yes, but after just trying it without caring about which variables and functions go in which slots it just worked: use gomez::nalgebra as na;
use gomez::prelude::*;
use gomez::solver::TrustRegion;
use na::{Dim, DimName, IsContiguous};
struct Point {
x: f64,
y: f64,
}
// Find a point equidistant from two other points
struct DistFromPoints {
points: [Point; 2],
dist: f64,
}
impl Problem for DistFromPoints {
type Scalar = f64;
type Dim = na::U2;
fn dim(&self) -> Self::Dim {
na::U2::name()
}
}
impl System for DistFromPoints {
fn eval<Sx, Sfx>(
&self,
x: &na::Vector<Self::Scalar, Self::Dim, Sx>,
fx: &mut na::Vector<Self::Scalar, Self::Dim, Sfx>,
) -> Result<(), ProblemError>
where
Sx: na::storage::Storage<Self::Scalar, Self::Dim> + IsContiguous,
Sfx: na::storage::StorageMut<Self::Scalar, Self::Dim>,
{
// 0 = distance(point, current_guess) - desired_distance
fx[0] = ((x[0] - self.points[0].x).powi(2) + (x[1] - self.points[0].y).powi(2))
- self.dist.powi(2);
fx[1] = ((x[0] - self.points[1].x).powi(2) + (x[1] - self.points[1].y).powi(2))
- self.dist.powi(2);
Ok(())
}
}
// <snip func main() > Output:
If they aren't related at all, can I have a different number of functions in the system to variables to guess? |
There isn't a requirement on the order, it's basically a naming (like if you would use y, x instead of x, y).
Unfortunately, this is not supported. Having less equations than variables is not possible in general, the system would have infinite number of solutions (or zero). Having more equations than variables could be possible, but it requires special support by the algorithm, and it is not implemented in this library. I recommend reading this Wikipedia article. This library supports only "exactly determined and consistent" systems. |
Thanks! That all makes sense. Why is it that this library won't work for underdetermined, consistent systems? Indeed in my Solvespace relies heavily on being able to solve underdetermined systems, to power its feature where it lets you drag a point and it will remain constrained to valid positions for that point. It does this with a numerical solver, initial guesses based on the current drag, and by scaling the variables such that the solver impacts the ones not being dragged the most. Would something like that not work here? |
Interesting. I have to admit that I am not that strong in the theory behind, I just needed to solve systems of equations in Rust and so I implemented something. If you believe that your use case should work and it also seems like it works, then you might be fine. I can't say whether it will or will not work, because I don't know :) But I hope it will! And if not, but we can do anything about it, let me know. |
No worries at all, thank you for making this library! Fwiw, this is definitely one of the more thought-out rust libraries in terms of algorithms used, tests, API interface etc. I'm going to go ahead and try and use it for my underdetermined-systems use-cases, will let you know how it goes!! |
Oh thanks for the kind words. There is a big room for improvement regarding the API, but your interest motivated me to give this library some love again. I made some changes to the API, you can read the list in #9. Any feedback would be appreciated. I will now give it a few days and if I can't think of any other changes I would like to make, I will release a new version. There will be breaking changes, I may write a short upgrade guide once I release the version. |
Sounds great! Thanks for your work on this library :) Circling back on how its going with my use case: I had a lot of trouble getting gomez to work for specifically geometric CAD / underconstrained systems. Whereas a slow solver like gradient descent will tend to land on solutions that are close to the initial values, this is rarely the case for TrustedRegion. As a result, I'll be dragging a point thats very underconstrained (usually by distance or something to another point), and it will be zooming all over the screen, along with any other underconstrained points. The other issue I had was when my constraint functions had multiple solutions, such as the distance function. Unless the residual bounced about zero, having multiple solutions which could be bounced back and forth made the solver unstable and usually unable to progress. This is all on me, because as you said gomez is meant for exactly constrained systems. But thought you would be curious how it went. |
Yes, I am definitely curious. Thanks for the update. In order to debug the problems, you can install a
This is really interesting. Seeing the logs could help us to understand what is going on, maybe it's a bug in gomez or it can be fixed by tweaking the settings. By the way, do you use your own implementation of gradient descent or a library?
You could try to set the maximum size and initial size of the trust region to a small value, so the solver makes much smaller, but hopefully less chaotic steps. You could also try to use Nelder-Mead algorithm instead of trust region. It's a simple function optimization method, so it's not really powerful for solving systems of equations, but I would be curious how that performs for your case (probably badly). |
I'll give Nelder-Mead a try! On the gradient-descent side, I made my own, but its pretty terrible & I don't know what I'm doing: https://gist.github.com/twitchyliquid64/65bb3cddf4287d58f56c24035febd775 But it mostly works lol |
When I started with this library, I had no idea what I was doing either :) But in time, with trial and error, it gets better. |
Hi @pnevyk @twitchyliquid64 |
@papyDoctor I ended up with my own, very strange solver for https://github.com/twitchyliquid64/liquid-cad (online demo: https://liquid-cad.twitchyliquid.net/) But lmk what you come up with, always excited to swap notes! @MattFerraro is also working in this space, his approach is a spring-based model with an RK4 solver: https://github.com/MattFerraro/CADmium |
@twitchyliquid64 Ah, you'r using egui :) |
It's good to know that there is a demand for underdetermined systems. I am definitely open to adjusting this crate to support this type of problems, at least API-wise. Then it would be possible to contribute an implementation of such solver to this crate. @papyDoctor @twitchyliquid64 I would appreciate if you keep sharing your progress, code and literature here. You can also use this issue for discussion although there are probably better tools for that. I could enable GitHub Discussions for this repo if you want. |
@pnevyk Yes please enable a discussion because I would like to share some use case I have. And indeed I'm no more sure about the absolute necessity of an underdetermined system. Also let me some times to implement your crate in my project. |
Discussions are now enabled. I now realized that the underdetermined systems should already be possible (theoretically). One just needs to calculate fx[i] for i up to the number of equations, and (to be safe) fill the rest with zeros. It's overdetermined systems that would cause the trouble, because the fx vector is of size n and if the number of equations is higher than n then there is (at the moment) no way how to pass the values of extra equations. If you will run into issues with the API and documentation during your implementation, let me know. |
@papyDoctor My use-case is defs PC & web-oriented so defs enjoying egui :) Im curious as to what your use-case is with trying to do this embedded? Ive always thought of embedded stuff to be the CNC controller, which would be working on G-code or something simpler like that. @pnevyk lovely, thanks! |
@twitchyliquid64 The little boards I've linked will be the CNC controller :) but specifically for cutting machine (plasma and laser). G-code is an old good format but it has some limitation (for ex: no bezier path) that I want to overcome. |
Gotcha! I definitely want to add basic CAM support to liquid-cad, my approach was going to be to generate an offset curve with the tool radius subtracted, and covert that to G-code: https://docs.rs/kurbo/latest/x86_64-apple-darwin/kurbo/offset/struct.CubicOffset.html The G5 code supports bezier paths in the X-Y plane. |
Ohhh, I wasn't aware of this crate. I'll check and use it if not too heavy. |
@twitchyliquid64 @pnevyk I've made a use case on the discussion |
Hi!
I'm wondering if
gomez
is appropriate to use for implementing a geometric solver (like this)?Based on the description in the docs:
I'm not sure if each
Fn(x)
can only be dependent onx
, can it be dependent on other variables?For instance if I have a system of equations that solve for the intersection of a line and a circle, I would need to reference the parameters of the line and circle across the same equation.
NB: Apologies if I'm totally missing the mark of understanding here, I'm learning :)
The text was updated successfully, but these errors were encountered: