-
Notifications
You must be signed in to change notification settings - Fork 2
Issue34 dependent parameters #112
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
base: develop
Are you sure you want to change the base?
Conversation
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.
This pull request does not contain a valid label. Please add one of the following labels: ['chore', 'fix', 'bugfix', 'bug', 'enhancement', 'feature', 'dependencies', 'documentation']
Have to add a deprecated label for the CI to proceed |
Hmm, the |
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.
General points:
- complexity: AST parsing and
asteval.Interpreter
pose significant complexity, making the code potentially harder to understand and maintain. - performance: the observer pattern and dependency evaluation could introduce performance overhead, especially in scenarios with many dependent parameters or frequent updates. We need to run benchmarks to see if the overhead is not too serious
- error handling: too much reliant on exceptions, which can clutter logs, cause unwanted exits or fail to provide clear error messages in complex setups
Additionally, complex methods like _process_dependency_symbol_names
and _process_dependency_unique_names
need clear examples for developers to understand their usage.
:param description: A brief summary of what this object is | ||
:param url: Lookup url for documentation/information | ||
:param display_name: The name of the object as it should be displayed | ||
:param enabled: Can the objects value be set | ||
:param independent: Is the object dependent on another object? |
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.
We use the enabled
state quite extensively in the libs/guis. Why did you remove this attribute?
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.
Well, can you tell me what its purpose is?
How does it differ at all from "fixed" or (not) "independent"?
In all the code I could see about it, it looked like it was just an alias for not independent.
self._scalar.variance = temporary_parameter.variance | ||
self._min.value = temporary_parameter.min | ||
self._max.value = temporary_parameter.max | ||
self._notify_observers() |
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 only occurrence of this method being called is in DescriptorNumber
. It is called from _notify_observers()
method.
Does this mean the self._notify_observers()
called here will be also called the DescriptorNumber and cause an infinite loop?
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.
Nope. Remember that Parameter
inherits from DescriptorNumber
. The only reason the _notify_observers()
methods is written in the DescriptorNumber
code, is because a Parameter
should be able to depend on a DescriptorNumber
.
Currently there can be an infinite loop if a dependent parameter is dependent on another dependent parameter which relies on itself, since each of those parameters have the other parameter in their _observers
list, but this will be handled by my unique update id suggestion
# Notify observers of the change | ||
self._notify_observers() | ||
else: | ||
raise AttributeError("This parameter is not independent, its value cannot be set directly. Please make it independent first.") # noqa: E501 |
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.
Do we want to raise here? (And the methods below).
Maybe just notify the user and drop the assignment attempt.
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.
Well, we raise when the user tries to set the full value. Since that is a read-only property.
For a dependent parameter, the value (and other entries) are also read-only properties, so I figured they should be handled in the same way. We could also raise a warning, but trying to set the value of a dependent parameter is an error, and that is why I flag it as such.
As I mentioned in my own comment, the AST parsing didn't work anyways due to the global namescope not being available inside modules, so I am currently removing it in favour of a simpler (albeit more verbose) approach where the user has to pass a dictionary of the dependencies along with the string to create a dependent parameter (unless unique_names are used).
Yes, I think this is an issue we would run into with any implementation of dependent parameters, including our current one, but we will definitely need to benchmark it. Especially with the approach I am currently implementing where each Parameter gets its own asteval interpreter, I am concerned about the potential performance issue as I am unsure of how heavy the asteval interpreter object is.
What do you mean? Most of the error handling I do is specifically aimed at providing clearer error messages when stuff fails.
I was gonna go through the implementation of the |
…han from the global scope
…ve dependent parameter constructor to class method
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.
I had a look at the current implementation. I think it is very readable actually, and it seems like a lot of cases have been handled w.r.t cleanup etc. My main concern is performance because of ASTeval, but I don't see a better way of doing things. Would be interesting to see what the computational cost is for a real-life example.
@notify_observers | ||
def convert_unit(self, unit_str: str) -> None: | ||
""" |
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.
This is the user-facing version of convert_unit
, right? So from the user's perspective nothing has changed API-wise w.r.t converting units?
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.
Yes, exactly. Nothing has changed from the user-perspective.
clean_dependency_string = dependency_expression | ||
existing_unique_names = self._global_object.map.vertices() | ||
# Add the unique names of the parameters to the ASTEVAL interpreter | ||
for name in inputted_unique_names: |
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.
inputted_unique_names only contains global ids, right? So if no global id's are passed in the expression this will be skipped?
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.
Yup. If there are no unique_names in the dependency expression, inputted_unique_names
will be empty and therefore the for-loop will not run.
@@ -115,6 +154,7 @@ def value(self) -> numbers.Number: | |||
return self._scalar.value | |||
|
|||
@value.setter | |||
@notify_observers | |||
@property_stack_deco |
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.
This decorator should really be renamed to property_stack
only. _deco
looks weird.
Unrelated but annoying
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.
Yes, I agree. We can sneak that change into this PR :D
…s in the dependent parameters.
docs/src/fitting/constraints.rst
Outdated
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.
Consider replacing rather than deleting the documentation on constraints.
It will be required to have this available and the best time to write the docs is when the feature is implemented...
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.
I don't think these docs actually work or are published anywhere. At least the contents does not appear to be similar to https://easyscience.github.io/corelib/modules/constraints/
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.
In fact, should I just remove the entire docs folder? There is basically nothing in it.
I still don't know exactly what our documentation plans are.
No description provided.