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

Refactor/pure functions #1944

Draft
wants to merge 1 commit into
base: devel
Choose a base branch
from

Conversation

SamKG
Copy link
Collaborator

@SamKG SamKG commented Mar 9, 2021

@kmantel
@jvesely
this is a draft of the pure transferfunction refactor - I could definitely use some input on if this is a good approach, or any other suggestions.

autocompiled udf code isn't in this draft yet - i want to completely nail down pure functions first

@SamKG SamKG changed the base branch from master to devel March 9, 2021 17:07
@SamKG SamKG requested review from jvesely and kmantel March 9, 2021 17:08
@lgtm-com
Copy link
Contributor

lgtm-com bot commented Mar 9, 2021

This pull request introduces 16 alerts and fixes 17 when merging c5ee9e2 into aabefef - view on LGTM.com

new alerts:

  • 9 for Comparison using is when operands support `__eq__`
  • 3 for Unused local variable
  • 2 for Duplication in regular expression character class
  • 1 for Except block handles 'BaseException'
  • 1 for Variable defined multiple times

fixed alerts:

  • 16 for Unused import
  • 1 for Duplication in regular expression character class

@lgtm-com
Copy link
Contributor

lgtm-com bot commented Mar 9, 2021

This pull request introduces 1 alert when merging c5ee9e2 into 11ccd54 - view on LGTM.com

new alerts:

  • 1 for Except block handles 'BaseException'

modulable_params = {p.name: _get_param(p) for p in self.parameters}
if params is None:
params = {}
parameters = {**modulable_params, **params}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
parameters = {**modulable_params, **params}
parameters = {**modulable_params, **kwargs, **params}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Adding kwargs here prevents multiple keyword arguments error on ex: pnl.Linear()(variable=5, slope=10, intercept=1)

Comment on lines +158 to +160
return self._derivative(**kwargs, **parameters)
else:
value = self._function(**kwargs, **parameters)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return self._derivative(**kwargs, **parameters)
else:
value = self._function(**kwargs, **parameters)
return self._derivative(**parameters)
else:
value = self._function(**parameters)

def _get_param(p):
try:
return self._get_current_parameter_value(p.name, context)
except:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should catch specific exception[s], AttributeError probably

return self._get_current_parameter_value(p.name, context)
except:
print(e)
modulable_params = {p.name: _get_param(p) for p in self.parameters}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Depending on what's faster, could only call _get_param on parameters in the function signature (see caching in prune_unused_args

try:
sig = _unused_args_sig_cache[func]
except KeyError:
sig = inspect.signature(func)
_unused_args_sig_cache[func] = sig
)

Should also remove need for dummy args like in L411 **_): and unused args like L2454:L2456

x_0=None,
offset=None,
scale=None,
**_):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Still _get_current_parameter_value calls inside

Comment on lines 1546 to 1548
input = np.asarray(input).copy()
input[input>0] = gain
input[input<=0] = gain * leak
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
input = np.asarray(input).copy()
input[input>0] = gain
input[input<=0] = gain * leak
variable = np.asarray(variable).copy()
variable[variable>0] = gain
variable[variable<=0] = gain * leak

also line 1550

 	        return variable

@jvesely
Copy link
Collaborator

jvesely commented Mar 22, 2021

Other than the few design issues. This is missign two major design justifications:

1.) Can all Functions be converted? What about the likes of DDI, ContentAddressableMemory?
If the compiler needs to be improved to handle those, converting TransferFunctions just removes cases that are easily supported and can be targeted as intermediate steps.

2.) How is the new design going to be enforced? Is every new Function expected to conform to the new format? If so what kind of help/guidance/enforcement will there be to guarantee that? Will there be a need for similar cleanup every time few more Functions are added?

def _derivative(variable=None,
slope=None,
**_):
return np.reshape(slope, variable.shape)
Copy link
Collaborator

Choose a reason for hiding this comment

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

this should use broadcast instead of reshape. reshape needs compatible shapes (same number of elements)

def _function(variable=None,
slope=None,
intercept=None,
**_):
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should update the argument documentation

def _function(variable=None,
slope=None,
intercept=None,
**_):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do you need hidden kwargs?

if params is None:
params = {}
parameters = {**modulable_params, **params}
parameters["variable"] = variable
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't this update the variable param in the current context?

if derivative:
return self._derivative(**kwargs, **parameters)
else:
value = self._function(**kwargs, **parameters)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a rather ugly extra redirection. why can't you just move the checks to a helper method and call that from both function and derivative?


def derivative(self, *args, **kwargs):
return self.function(derivative=True, *args, **kwargs)
Copy link
Collaborator

@jvesely jvesely Mar 22, 2021

Choose a reason for hiding this comment

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

This should be:

params = self._process_params(*args, **kwargs)
return self._derivative(params)

It should also allow you to drop the **_ ugliness.

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.

3 participants