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

sympy expression with arbitrary variables/parameters #349

Open
kevinxxq opened this issue Apr 26, 2022 · 8 comments
Open

sympy expression with arbitrary variables/parameters #349

kevinxxq opened this issue Apr 26, 2022 · 8 comments

Comments

@kevinxxq
Copy link

kevinxxq commented Apr 26, 2022

Hi, @tBuLi , thank you for the package.
Just as https://stackoverflow.com/questions/55580926/how-to-extend-the-number-of-symfit-parameters-arbitrarily-in-python, I would like to wrap this package for api:
model: (dict of) sympy expression(s). e.g; a * x+ b
variables: x,y
parameters: a,b

Here is your example:

a, b = parameters('a, b')
x, y = variables('x, y')
model = {y: a * x + b}

# Fit will use its default settings
fit = Fit(model, x=xdata, y=ydata)
fit_result = fit.execute()

Now it turns to a different arbitrary way: a,b may be c,d, x,y may be x1,y1

I will pass a list of varibles and parameters such as "a, b, c, d" and "x, y, z" and a related sympy expression.

How can I handle it?

Thank you very much!

@tBuLi
Copy link
Owner

tBuLi commented Apr 26, 2022

Hi @kevinxxq, thanks for your question! I'm not sure I understand your problem tough. The symfit model dict can have any number of elements in it, e.g.

x_1, x_2, y_1, y_2 = variables('x_1, x_2, y_1, y_2')
y0, a_1, a_2, b_1, b_2 = parameters('y0, a_1, a_2, b_1, b_2')

model_dict = {
    y_1: y0 + a_1 * exp(- b_1 * x_1),
    y_2: y0 + a_2 * exp(- b_2 * x_2),
}

such as the example taken from here: https://symfit.readthedocs.io/en/stable/fitting_types.html#fitting-multiple-datasets. Maybe that helps? If not, maybe you can reformulate the question? I've had a look at the stackoverflow question but that deals with automatically generating the model, is that your problem?

@kevinxxq
Copy link
Author

Thank you for so quick reply.

Not true. I don't know the left part of below declarification:
x_1, x_2, y_1, y_2 = variables('x_1, x_2, y_1, y_2')

The variables come from the caller when the function is called,the signature of my function is something as below.

def my_fit_function(expr,list_var,list_para,dict_data(key_var,list_data))->list_para:
expr: a*x+b
list_var:[x,y]
list_para:[a,b]
dict_data:{x:[1,2,...10],y:[2,4,6...20]}

Thank you.

@pckroon
Copy link
Collaborator

pckroon commented Apr 28, 2022

It's a bit unclear to me what you're exactly asking, and your code snippet also does not add clarity.

The variables function does no magic. It simply returns a list of Variable objects. Beyond that x_1, x_2, y_1, y_2 = variables('x_1, x_2, y_1, y_2') is just tuple unpacking. So you could do:

list_of_variables = variables('x, y, z')
x, y, z = list_of_variables  # This is optional! You can also use list_of_variables[0] to get x, etc.

@kevinxxq
Copy link
Author

kevinxxq commented Apr 28, 2022

@pckroon Thank you for involving.
Sorry for the inconvenience.

Yes, I understand that the variables are tuple unpacking.

The problem is that I don't know the symbols for a sympy expression.
I can't define x,y=variables("x,y) since it may be x_1,x_2=variables("x_1,x_2)

The way it would be possible or I expect is:

list_of_variables = variables('x, y, z')
list_of_parameters = parameters('a, b, c')

fit=Fit(expr,list_of_variables,list_of_parameters,dict_data(key_var,list_data),...)
fit_result = fit.execute()

Thank you.

@pckroon
Copy link
Collaborator

pckroon commented Apr 28, 2022

It's still not clear to me what you need/want. If you need the symbol names to pass the relevant data to Fit you can use dictionary unpacking. Otherwise I really need you to phrase your question more carefully: What do you want to achieve, what have you tried, what functionality are you missing.

@Jhsmit
Copy link
Collaborator

Jhsmit commented Apr 28, 2022

Do you know the number of variables and/or parameters?

from symfit import variables, parameters
from functools import reduce
from operator import add


num_terms = 5
var_names = [f'x_{i}' for i in range(num_terms)]
par_names = [f'a_{i}' for i in range(num_terms)]

var_tup = variables(', '.join(var_names))
par_tup = parameters(', '.join(par_names))

expression = reduce(add, [a*v**i for i, (v, a) in enumerate(zip(var_tup, par_tup))])

expression
>>> a_0 + a_1*x_1 + a_2*x_2**2 + a_3*x_3**3 + a_4*x_4**4

You can then do fitting by passing a dict with var_names as keys

@kevinxxq
Copy link
Author

Thank you ALL, sorry that is me to consider it too simplistic or idealized:
def my_fit_function(expr,list_var,list_para,dict_data(key_var,list_data))->list_para:
It will work as a powerful funtion to any expresion, any number of variables/parameters.

I just want to wrap the code in python to serve other clients who don't know anything about python.
They need pass the expression, list of variables in str, list of paramers in str, dict(str_variable, data), then they can get the fitted parameters(list of parameters).

So I expect:

fit=Fit(expr,list_of_variables,list_of_parameters,dict_data(key_var,list_data),...)   # here inside Fit class, zip(list_of_variables) would be helpful to evaluate expr. Sorry I didn't get into the internal implentation
fit_result = fit.execute()

It may be impossible now, I will try to split it to serveral different functions.

Thank you again.

@pckroon
Copy link
Collaborator

pckroon commented Apr 28, 2022

Ok. You'll need a way to turn your string expression into a sympy expression with the appropriate Variable/Parameter objects. That is out of scope for this issue/discussion though. It doesn't help for this discussion that your signature has a list_var, but it's actually a string, same for expr.

If you have a string of variables as you feed them to variables you know they're comma-separated, so you can do my_string_of_variables.split(',') to get all your variable names. Otherwise all Variable objects have a name attribute and str(my_var) will also do what you expect.

It's still not clear to me where you get stuck, we won't write your adapter function for you.

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

No branches or pull requests

4 participants