Skip to content
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

check that equations_of_motion are not AEs #236

Merged
merged 5 commits into from
Sep 16, 2024

Conversation

Peter230655
Copy link
Contributor

@Peter230655 Peter230655 commented Sep 15, 2024

Check whether the equations of motions contain differential equation, and rais a ValueError if they are AEs.
I used @tjstienstra idea, which seems to be VERY fast!
Should take care of issue # 228

@moorepants
Copy link
Member

You'll need to check this on something at least the size of the bicycle model to make sure it doesn't slow down things. I'm generally fine having a "garbage in, garbage out" design, especially when there can be significant performance costs for checking inputs.

@Peter230655
Copy link
Contributor Author

Peter230655 commented Sep 16, 2024

You'll need to check this on something at least the size of the bicycle model to make sure it doesn't slow down things. I'm generally fine having a "garbage in, garbage out" design, especially when there can be significant performance costs for checking inputs.

The bicycle model does not run with me, and I still could not lokate the error.
I tested this two liner:

zeit = time.time()
if eom.has(sm.Derivative) == False:
    raise ValueError(.....)
duration = time.time() - zeit

with the eom having 23,000 operations, and duration was less than 10^(-15).
Is this testing of duration inadequate?
Should my eom have many more operations?
(Of course my eom had some sm.Derivative very 'soon', and I believe has(...) turns true as soon as it has found the first one.)

@moorepants
Copy link
Member

(Of course my eom had some sm.Derivative very 'soon', and I believe has(...) turns true as soon as it has found the first one.)

If that is true, then it should be pretty fast.

@@ -152,6 +152,9 @@ def __init__(self, obj, obj_grad, equations_of_motion, state_symbols,

"""

if equations_of_motion.has(sm.Derivative) == False:
raise ValueError('The equations of motion must be DEs or DAEs, not AEs.')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise ValueError('The equations of motion must be DEs or DAEs, not AEs.')
raise ValueError('No time derivatives are present, the equations of motion must be ordinary differential equations (ODEs) or differential algebraic equations (DAEs),')

@moorepants
Copy link
Member

This needs a unit test to make sure the error raises.

This will isn't completely robust in the sense that it may find a Derivative that is not a time derivative. In the case a user passes in equations with derivatives of variables other than time, the error message is misleading.

@Peter230655
Copy link
Contributor Author

(Of course my eom had some sm.Derivative very 'soon', and I believe has(...) turns true as soon as it has found the first one.)

If that is true, then it should be pretty fast.

As per chatGPT it is true, that it stops as soon as it has found the first term...

@moorepants
Copy link
Member

I'm not the type that listens to anything ChatGPT may say...

@Peter230655
Copy link
Contributor Author

Peter230655 commented Sep 16, 2024

This needs a unit test to make sure the error raises.

This will isn't completely robust in the sense that it may find a Derivative that is not a time derivative. In the case a user passes in equations with derivatives of variables other than time, the error message is misleading.

I tested it with a small example, where I simply deleted the .diff(t) in all the terms. This worked, it raised the error.
Seems, I cannot find sm.Derivative(t) this way, I guess it is not an atom. I guess, I could find sm.Derivative(t similar to how I do it in plot_constraint_violations. But likely this is slow.
So, better drop this PR?

What I tried earlier was this:

  • converted the eom to a string
  • then I tested 'Derivative' in str(eom)

With 23,000 operations, this took about o.5 sec.
Like this, I can look for what I want, but time consuming.
Worth doing it?
I think, too complicated, I checked.
I guess, either we can accept the ambiguity or better drop it: garbage in / garbage out!

@Peter230655
Copy link
Contributor Author

I'm not the type that listens to anything ChatGPT may say...

likely smart - but it has helped me a lot with git commands. :-)

@Peter230655
Copy link
Contributor Author

Adjusted the wording of the ValueError, just in case you want to merge this.

@moorepants
Copy link
Member

Adjusted the wording of the ValueError, just in case you want to merge this.

It would still need a unit test.

@Peter230655
Copy link
Contributor Author

Adjusted the wording of the ValueError, just in case you want to merge this.

It would still need a unit test.

Would this be a program without time derivaties so it gives the error? (of course I did test it)
If YES, would I push it with this PR?
Any special 'form' required?
Sorry about all these questions!

@moorepants
Copy link
Member

Yes to all three questions.

@Peter230655
Copy link
Contributor Author

Peter230655 commented Sep 16, 2024

Yes to all three questions.

I wrote a function, which when run will cause the ValueError to be raised - and of course will stop running. (copied it from an existing opty test function and modified according to my needs)

  • Would I add it to opty/opty/tests?
  • Does this function need to import all the libraries it needs, or just a function which will cause the ValueError to be raised?
  • When this function runs, the ValueError is raised and it stops. This is maybe not want you want? But what to do about it? Should it not continue to run if and only if a ValueError is raised?

I found a way (with chatGPT!) so my function stops with an exception if no ValueError is found, If a ValueError occurs it keeps on running.
But on first two points I am unclear.
Thanks!

@moorepants
Copy link
Member

I would recommend having a look at the existing unit tests and using the patterns there to come up with how your test will look.

@Peter230655
Copy link
Contributor Author

I would recommend having a look at the existing unit tests and using the patterns there to come up with how your test will look.
This is what I did, and there I found this:
image
Would I paste my function at the end of test_direct_collocation.py? (There are many functions there)

@moorepants
Copy link
Member

Yes.

except ValueError:
print('ValueError found correctly')
else:
raise Exception()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use the raises() function from pytest. See where it is used elswhere in the file.

@Peter230655
Copy link
Contributor Author

Is this how you meant it? I simply copied it from the only other place it is used in test_direct_collocation.py
Frankly unsure how it works.

bounds={T(t): (-2.0, 2.0)},
)
with raises(ValueError):
eom = 'algebraic equations'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd have to run the line that raises the error in the with statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd have to run the line that raises the error in the with statement.

Sorry, but I do not understand.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@moorepants
Copy link
Member

These things are explained in documentation: https://docs.pytest.org/en/4.6.x/reference.html#pytest-raises

@Peter230655
Copy link
Contributor Author

You ARE a teacher! Your method of not telling me exactly what to do helps me to learn!

Just curiosity: Would my original way have worked and just been very ugly compared to this way, or plain wrong?

@moorepants
Copy link
Member

Just curiosity: Would my original way have worked and just been very ugly compared to this way, or plain wrong?

Probably would have worked. We use pytest for the tests, so no reason not to use these helper functions that are more robust than things we write.

@moorepants moorepants merged commit 0b5c8bb into csu-hmc:master Sep 16, 2024
17 checks passed
@Peter230655
Copy link
Contributor Author

THANKS!
Stupid question - as often:
Did this merge the test only, or also the change in direct_collocation.py?
(You were not so sure you wanted it)

@Peter230655
Copy link
Contributor Author

Just curiosity: Would my original way have worked and just been very ugly compared to this way, or plain wrong?

Probably would have worked. We use pytest for the tests, so no reason not to use these helper functions that are more robust than things we write.

Makes sense, plus more 'elegant', I think!

@moorepants
Copy link
Member

Everything in the PR is merged. You can see all changes in the "files changed" tab.

@Peter230655
Copy link
Contributor Author

Everything in the PR is merged. You can see all changes in the "files changed" tab.

Thanks! Makes me feel good to contribute - even if not exactly in gigantic ways! :-)
By the time I will be 75 I hope I will know much more, fewer dumbe questions!° :-)

@Peter230655 Peter230655 deleted the check_for_AE branch September 16, 2024 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants