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

Custom solver __call__ must have default arguments #1358

Closed
arvoelke opened this issue Sep 14, 2017 · 2 comments · Fixed by #1359
Closed

Custom solver __call__ must have default arguments #1358

arvoelke opened this issue Sep 14, 2017 · 2 comments · Fixed by #1359
Labels

Comments

@arvoelke
Copy link
Contributor

Minimal example:

import nengo

class MySolver(nengo.solvers.Solver):
    def __call__(self, *args, **kwargs):
        return super(MySover, self).__call__(*args, **kwargs)
    
with nengo.Network(seed=0) as model:
    nengo.Connection(nengo.Ensemble(1, 1), nengo.Ensemble(1, 1), solver=MySolver())
    nengo.Simulator(model)
...
c:\Users\Aaron\Anaconda2\lib\site-packages\nengo\cache.pyc in cached_solver(conn, gain, bias, x, targets, rng, E, **uncached_kwargs)
    653             except TypeError:
    654                 args, _, _, defaults = inspect.getargspec(conn.solver.__call__)
--> 655             args = args[-len(defaults):]
    656             if rng is None and 'rng' in args:
    657                 rng = defaults[args.index('rng')]

TypeError: object of type 'NoneType' has no len()

I'm assuming that it's expecting the signature def __call__(self, A, Y, rng=None, E=None) which has default arguments. My case doesn't have any since I delegate the __call__ to a sub-solver.

@jgosmann jgosmann self-assigned this Sep 15, 2017
@jgosmann jgosmann added the bug label Sep 15, 2017
@jgosmann
Copy link
Collaborator

You might be required to specify the complete argument list. The E and the random number generator state rng are included in the hash identifying the function arguments. Thus, if these are not passed explicitely, the default values have to be used. But these can only be inspected if the argument list is made explicit.

So far the theory ... actually the solvers use a default of rng=None and retrieve np.random within the function if rng is None. So the random number generator state will not be included correctly in the hash anyways. 😨

It seems like a bad idea to assume that rng=None means that the solver will use np.random. But because there is no way to find out what the solver is actually doing, the best option might be to have the cache set rng to np.random if rng=None is passed. That would ensure that the correct RNG state is hashed and that RNG is used by the solver. In that case it is also not required to inspect the default value of rng which is half-way towards solving your problem.

The other half is the E argument. For this it seems really weird if a solver would have a default other than None, so we might just overwrite it with a default of None?

@jgosmann
Copy link
Collaborator

So the random number generator state will not be included correctly in the hash anyways.

Though in practice this probably wasn't a problem because the builder always passes the rng argument?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

2 participants