-
-
Notifications
You must be signed in to change notification settings - Fork 56
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
Reduce the number of calls to simplify #537
Conversation
Thank you for looking into this!
Hm, no. Whether or not a quantity is simplified should definitely not depend on the presence of a type annotation. It shouldn't depend on the type at all. Types in Numbat always mean: physical dimensions (Scalar, Length, Velocity) and not units (—, meter, meter/second).
The type
I think I would need a bit more information to see what exactly went wrong in those two tests. |
Thanks, I was completely wrong about my approach and was able to fix some stuff because of your comment. I think the PR is almost ready to merge, but there is still an issue I don't really understand:
The Also, on That seems strange to me 🤔 |
That happens because it gets
Sort of. The problem is not with your PR. The problem is the very existence of those functions. Please see my explanation here and the ticket #336. I'll try to give a more helpful response (or maybe a fix) in a few days. |
Actually. Maybe your PR even solves the problem that I mentioned in that description?! In that case, we should probably provide |
Oh yes, you're right; these functions don't really make sense when playing with different units; it's actually a way more complex subject than I expected 😅
That seems smart, and the right side of the function call could be any value instead of a type right?
💯 On a side note, it should also always be the second arguments so we can easily write And last questionWhat should be the exact syntax in our case for simple scalars? |
Let's try to fix the notation, so we don't get confused. I would propose we change the type annotation for fn round(value: Scalar) -> Scalar
fn round_in<D: Dim>(base: D, value: D) -> D = round(value / base) × base I think this solves all problems: assert_eq(round(1.234), 1)
assert_eq(1.234 m |> round_in(m), 1 m)
assert_eq(1.234 m |> round_in(cm), 123 cm)
assert_eq(1.234 m |> round_in(mm), 1234 mm)
assert_eq(1.234 m |> round_in(10 m), 0)
assert_eq(1.234 m |> round_in(1 m), 1 m)
assert_eq(1.234 m |> round_in(0.1 m), 1.2 m, 1e-9 m)
assert_eq(1.234 m |> round_in(0.01 m), 1.23 m, 1e-9 m)
assert_eq(1234 |> round_in(1000), 1000)
assert_eq(1234 |> round_in(100), 1200)
assert_eq(1234 |> round_in(10), 1230)
assert_eq(1234 |> round_in(1), 1234)
assert_eq(1234 |> round_in(0.1), 1234)
So with the notation above:
Yes.
I think we should keep |
Oops, I swapped the order of the parameters with I’ll look into it later but:
Don't we have an issue here?
Which was causing the issue initially with a |
I updated the code with a fn round_in<D: Dim>(base: D, value: D) -> D = round(value / base) × base In
I guess one solution could be to call Another solution could be to provide a new function, And the last solution I can think of would be to provide a new special internal type like « number » or something that is a fully simplified scalar. It could only be generated by converting a scalar to it and the VM could automatically generate the fullsimplify instruction. |
I think you need to change |
See #546 |
Oooh nice I didn't know we had that! |
This has been merged now. (I really like how this example looks now with the new |
Ahah this one is awesome, I didn't know about it! 😂 |
96194c9
to
6ccb113
Compare
I rebased my PR, edited the original message and updated the performance improvements |
This is great. What I don't fully instead at the moment: using your |
@@ -24,20 +24,31 @@ pub type Result<T> = std::result::Result<T, QuantityError>; | |||
pub struct Quantity { | |||
value: Number, | |||
unit: Unit, | |||
can_simplify: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name confused me a bit when first reading this code. Maybe call it simplification_allowed
? And rename no_simplify
to prevent_simplification
?
I think we can, but I didn't try it because it's hard to know if we can simplify something. The contextSo, as stated in the description, the idea is to not simplify when we don't need to.
The issueThe issue is that if someone wrote an expression that's not simplified, like The trickThis boolean is only Avoiding the trick
In the end, I believe this is possible, but it requires us to keep track of the usage of each variable while compiling the stmts to asm and, although it doesn't seem hard, that's not something we already do in numbat. let a = 3m/m -> km/m
let stuff = 47
let bidule = 34 + stuff + a
print(a) # We need to find back the definition of `a` and see if it contained a `ConvertTo` thing Just thinking out loud now I wrote this example, maybe we have only two cases currently when we should not simplify an expression:
Sorry I’m not sure that's super clear but let me know if it isn't 😅 |
I was thinking of the following:
Wouldn't this be enough already? |
Yes, I need to try a few things, but it should work and be even faster 🔥 |
So it turns out this was really easy to implement on top of what you did (I hope I didn't miss something you had thought about). I basically just had to remove some code and add a few It's very nice conceptually that This PR also fixes two issues we discovered recently. I added regression tests for them. For the
For the benchmark you suggested in your original post, I still see the 10% improvement. And I see that you have a much faster machine than I have 😄
Thank you very much for your work. This is great. Let me know if I missed something. |
Hey, it's awesome! I'm sorry I didn't finish this myself. I started working again and didn't find the time to work on it again, but it's awesome that you finished it! Thank you |
@@ -943,5 +950,14 @@ mod tests { | |||
212121001.1 cm | |||
"###); | |||
} | |||
|
|||
#[test] | |||
fn issue505_angles() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. This looks a lot better now.
Reduce the number of calls to simplify
Fixes #535
We try to call
FullSimplify
as few as possible.Basically right before outputting something to the end user (calling print, returning a value to the user or composing strings).
Performances
On my computer:
range(0, 1_000_000) |> map(sqrt) |> sum
improved by ~12% (from 1.5s to 1.3s)Original issue
Hey, after your answer, I started some work on #535
My initial idea was to call it
full_simplify
only at the end of statements.To solve this part, I added a boolean in every value that tells us if the immediate last operation was a
ConvertTo
.As expected, I got a 10% performance improvement:
The issue
With this code, only two tests fail.
The issue is that when a function with a type annotation returns something, we should convert the returned value to the expected type:
Here, for example,
floor(time / day)
returns aTime / Time
, which we want to convert to a simple scalar, I guess?I don't understand how to do that. The
return_type_annotation
of a function is aTypeAnnotation
, and I need to give aUnit
toConvertTo
. I didn't find any way to do that in the code and am struggling to make the conversion myself.Let me know if you think this makes sense and know how to help me.