Beispiel #1
0
def call(self, **kwargs):
    """
    :param self: Any subclass of sympy.Expr
    :param args:
    :param kwargs:
    :return:
    """
    # Convert to a pythonic function
    vars, params = seperate_symbols(self)
    func = sympy_to_py(self, vars, params)
    # Prepare only the relevant kwargs
    arg_names = [arg.name for arg in params + vars]
    args = dict([(name, value) for name, value in kwargs.items() if name in arg_names])
    return func(**args)
Beispiel #2
0
def call(self, *values, **named_values):
    """
    Call an expression to evaluate it at the given point.

    Future improvements: I would like if func and signature could be buffered after the
    first call so they don't have to be recalculated for every call. However, nothing
    can be stored on self as sympy uses __slots__ for efficiency. This means there is no
    instance dict to put stuff in! And I'm pretty sure it's ill advised to hack into the
    __slots__ of Expr.

    However, for the moment I don't really notice a performance penalty in running tests.

    p.s. In the current setup signature is not even needed since no introspection is possible
    on the Expr before calling it anyway, which makes calculating the signature absolutely useless.
    However, I hope that someday some monkey patching expert in shining armour comes by and finds
    a way to store it in __signature__ upon __init__ of any ``symfit`` expr such that calling
    inspect_sig.signature on a symbolic expression will tell you which arguments to provide.

    :param self: Any subclass of sympy.Expr
    :param values: Values for the Parameters and Variables of the Expr.
    :param named_values: Values for the vars and params by name. ``named_values`` is
        allowed to contain too many values, as this sometimes happens when using
        \*\*fit_result.params on a submodel. The irrelevant params are simply ignored.
    :return: The function evaluated at ``values``. The type depends entirely on the input.
        Typically an array or a float but nothing is enforced.
    """
    independent_vars, params = seperate_symbols(self)
    # Convert to a pythonic function
    func = sympy_to_py(self, independent_vars + params)

    # Handle args and kwargs according to the allowed names.
    parameters = [  # Note that these are inspect_sig.Parameter's, not symfit parameters!
        inspect_sig.Parameter(arg.name,
                              inspect_sig.Parameter.POSITIONAL_OR_KEYWORD)
        for arg in independent_vars + params
    ]

    arg_names = [arg.name for arg in independent_vars + params]
    relevant_named_values = {
        name: value
        for name, value in named_values.items() if name in arg_names
    }

    signature = inspect_sig.Signature(parameters=parameters)
    bound_arguments = signature.bind(*values, **relevant_named_values)

    return func(**bound_arguments.arguments)
Beispiel #3
0
def call(self, *values, **named_values):
    """
    Call an expression to evaluate it at the given point.

    Future improvements: I would like if func and signature could be buffered after the
    first call so they don't have to be recalculated for every call. However, nothing
    can be stored on self as sympy uses __slots__ for efficiency. This means there is no
    instance dict to put stuff in! And I'm pretty sure it's ill advised to hack into the
    __slots__ of Expr.

    However, for the moment I don't really notice a performance penalty in running tests.

    p.s. In the current setup signature is not even needed since no introspection is possible
    on the Expr before calling it anyway, which makes calculating the signature absolutely useless.
    However, I hope that someday some monkey patching expert in shining armour comes by and finds
    a way to store it in __signature__ upon __init__ of any ``symfit`` expr such that calling
    inspect_sig.signature on a symbolic expression will tell you which arguments to provide.

    :param self: Any subclass of sympy.Expr
    :param values: Values for the Parameters and Variables of the Expr.
    :param named_values: Values for the vars and params by name. ``named_values`` is
        allowed to contain too many values, as this sometimes happens when using
        \*\*fit_result.params on a submodel. The irrelevant params are simply ignored.
    :return: The function evaluated at ``values``. The type depends entirely on the input.
        Typically an array or a float but nothing is enforced.
    """
    independent_vars, params = seperate_symbols(self)
    # Convert to a pythonic function
    func = sympy_to_py(self, independent_vars + params)

    # Handle args and kwargs according to the allowed names.
    parameters = [  # Note that these are inspect_sig.Parameter's, not symfit parameters!
        inspect_sig.Parameter(arg.name, inspect_sig.Parameter.POSITIONAL_OR_KEYWORD)
            for arg in independent_vars + params
    ]

    arg_names = [arg.name for arg in independent_vars + params]
    relevant_named_values = {
        name: value for name, value in named_values.items() if name in arg_names
    }

    signature = inspect_sig.Signature(parameters=parameters)
    bound_arguments = signature.bind(*values, **relevant_named_values)

    return func(**bound_arguments.arguments)
Beispiel #4
0
    def test_fitting(self):
        xdata = np.linspace(1,10,10)
        ydata = 3*xdata**2

        a = Parameter('a')
        b = Parameter('b')
        x = Variable('x')
        new = a*x**b

        fit = Fit(new, xdata, ydata)

        func = sympy_to_py(new, [x], [a, b])
        result = func(xdata, 3, 2)
        self.assertTrue(np.array_equal(result, ydata))

        result = fit.scipy_func(fit.xdata, [3, 2])
        self.assertTrue(np.array_equal(result, ydata))

        import inspect
        args, varargs, keywords, defaults = inspect.getargspec(fit.scipy_func)

        # self.assertEqual(args, ['x', 'a', 'b'])
        fit_result = fit.execute()
        self.assertIsInstance(fit_result, FitResults)
        print(fit_result)
        self.assertAlmostEqual(fit_result.params.a, 3.0)
        self.assertAlmostEqual(fit_result.params.b, 2.0)

        self.assertIsInstance(fit_result.params.a_stdev, float)
        self.assertIsInstance(fit_result.params.b_stdev, float)

        self.assertIsInstance(fit_result.r_squared, float)

        # Test several false ways to access the data.
        self.assertRaises(AttributeError, getattr, *[fit_result.params, 'a_fdska'])
        self.assertRaises(AttributeError, getattr, *[fit_result.params, 'c'])
        self.assertRaises(AttributeError, getattr, *[fit_result.params, 'a_stdev_stdev'])
        self.assertRaises(AttributeError, getattr, *[fit_result.params, 'a_stdev_'])
        self.assertRaises(AttributeError, getattr, *[fit_result.params, 'a__stdev'])