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

Indexed variables #179

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open

Indexed variables #179

wants to merge 20 commits into from

Conversation

tBuLi
Copy link
Owner

@tBuLi tBuLi commented Sep 10, 2018

First version of Indexed-variables support! For more info on the possibilities, also see #175.

The goal with this PR is to get to the point where IndexedVariable's are fully implemented and working, but for IndexedParameter's we just implement the correct infrastructure and handling on Models, but with no means for solving them.

This means that after merging this PR, the following things will work:

  • Equality constraints with any minimizer due to lagrange multipliers
  • Constraints which depend on the data, both equality and inequility.

The following things will be possible for advanced users willing to implement their own subclass of BaseObjective:

  • Solving matrix equations such as {y[i]: A[i, j] * x[j] + b}.
  • Global fitting problems such as y[i] = y0 + a[i] * exp(- b[i] * x[i]).

p.s. my apologies for the huge PR

@tBuLi tBuLi requested a review from pckroon September 10, 2018 14:50
An example of this can be a brute-force implementation of least-squares fitting.
Copy link
Collaborator

@pckroon pckroon left a comment

Choose a reason for hiding this comment

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

Good start. I won't pretend I understand everything that's happening though. I also feel like there's about 1000 tests missing.
And I think we should implement the Objectives you describe. Or just make LeastSquares smarter.

symfit/core/argument.py Show resolved Hide resolved

# A mapping of the vars to their (perhaps) indexed counterparts
self.symbol2indexed = {var if isinstance(var, Variable) else var.base: var
for var in model_dict.keys()}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this also work with brackets? {(var if ... else var.base): var for var in model_dict.keys()}

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yeah that might be cleaner


self.dependent_vars = sorted(self.symbol2indexed.keys(), key=sort_func)
# Ordering is determined by the Variable names, not their indexed
# version. (e.g. `y`, not `y[i]` to prevent possible ambiguities.).
Copy link
Collaborator

Choose a reason for hiding this comment

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

move comment above line. And define sort_func down here.


# Extract all the params and vars as a sorted, unique list.
expressions = model_dict.values()
_params, self.independent_vars = set([]), set([])
_params, _independent_vars, _indices = set([]), set([]), set([])
Copy link
Collaborator

Choose a reason for hiding this comment

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

set() instead of set([])?

vars, params = seperate_symbols(expression)
# extract symbols from expression, viewing IndexedSymbols as atoms,
# e.g. returns `y[i]` not `y` when applicable
indexed_vars, indexed_params = seperate_symbols(expression)
Copy link
Collaborator

Choose a reason for hiding this comment

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

add argument for separate_indices

symfit/core/fit.py Show resolved Hide resolved
symfit/core/fit.py Show resolved Hide resolved
symfit/core/fit_results.py Show resolved Hide resolved
else:
vars.append(symbol)
elif isinstance(symbol, IndexedVariableBase):
vars.append(symbol)
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can clean this if/elif tree by making a dict of {classes: lists}, and sorting based on that. At the end you combine some (possibly also based on lists/sets of classes).

outcomes = {Parameter: [], IndexedParameter: [], IndexedParameterBase: [], ...}
for symbol in func.free_symbols:
    for class_, items in outcomes.items():
        if isinstance(symbol, class_):
            items.append(symbol)

etc.

return {expr}
else:
# Call this function recursively
indexed = set([])
Copy link
Collaborator

Choose a reason for hiding this comment

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

set() instead of set([])

Martin Roelfs added 3 commits September 11, 2018 12:55
It breaks to much sympy compatibility, and writing a function to extract them from an expression turns out to be rather simple once you get the hang of sympy.

Tests have also been updated to reflect that IndexedArguments are no longer free_symbols
Additionally, removed Model.chi, Model.chi_jacobian, and its numerical counterparts. This was a remnant from a dark past when we still had to bow to the will of MINPACK.

Removed without deprication, as I seriously doubt anybody even knew about this. Symfit itself didn't even use it internally or test for it.
@tBuLi
Copy link
Owner Author

tBuLi commented Sep 11, 2018

@pckroon Thanks for the review. Of course, ultimately we should implement those Objectives. However, to give a general solution for least-squares-solving a tensor equation turns out to be non-trivial ;). In order to have an achievable goal, I think this is a good place to draw the line for this PR.

@pckroon
Copy link
Collaborator

pckroon commented Sep 11, 2018

No problem!
Works for me ;)

@pckroon pckroon added the WIP Work in Progress label Feb 11, 2019
@tBuLi tBuLi mentioned this pull request Oct 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WIP Work in Progress
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants