-
Notifications
You must be signed in to change notification settings - Fork 328
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
Promoting Weak, PI, and Trapping to SINDy subclass #351
Comments
Totally agree with the general sentiment that the code could use a major reorganization because there are a lot of historical hacks. On the trapping SINDy side of things, it is a weird subset of SINDy because it requires (or at least, doesn't make sense without) a (1) quadratically polynomial library and (2) the trapping SINDy optimizer, since it is optimizing additional nonconvex terms AND (3) a specific set of constraints in the coefficients (although we are removing these constraints in followup work on the trapping_extended branch by @MPeng5). It really is a very specific optimization for fluid and plasma type models. There is also some confusion because it inherits from the ConstrainedSR3 optimizer, so you could (but shouldn't) use it just like ConstrainedSR3 (although I think it may complain about non quadratically polynomial libraries). However, the trapping SINDy stuff I believe is compatible with the weak form & other differentiation methods. So not sure what the best plan is for this. |
Couple other things:
|
library_functions[k] = np.tensordot(
self.fullweights0[k],
funcs[np.ix_(*self.inds_k[k])],
axes=(
tuple(np.arange(self.grid_ndim)),
tuple(np.arange(self.grid_ndim)),
),
)
Back to TrappingThere's two problems I'm trying to get at in this GH issue (1) weak and PI problem setup shedding responsibility for function evaluation and optimizers, and (2) hey, wouldn't it be nice if the ontology of classes/types that we define in pysindy itself prohibited mathematically incoherent solutions. You said:
How does it know what function libraries were used in another step of the problem? This would work: class TrappingSINDy(SINDy):
def __init__(self, feature_library: TrappingLibrary, optimizer: TrappingSR3, **kwargs):
super(feature_library=feature_library, optimizer=optimizer, **kwargs)
TrappingLibrary = type("TrappingLibrary", (abc.ABC,), {})
class QuadraticLibrary(PolynomialLibrary, TrappingLibrary):
# def __init__(self, **kwargs):
super().__init__(**kwargs, degree=2) This way, the IDE's background type checker would detect using the wrong library and flag it as an error before running the code. Obviously if
Then we could add: class WeakQuadraticLibrary(WeakLibrary, TrappingLibrary):
# implement There is a conflict though if both trapping and the weak form becomes it's own subclass of |
Discrete SINDy might also fit better as a subclass of |
Sorry my response here is a little slow! I'll try to put some thought into good structure soon. I broadly agree with @akaptano that a big reorganization would nice if someone wants to take a lead, but its a lot of work and maybe relatively little reward to reap |
@znicolaou I'm happy to lead and do this incrementally. It's partially driven by how tests fail in somewhat unpredictable places, partially driven by a goal to simplify the I'm pretty certain this would lead to simpler, more maintainable code, and so long as your comfortable with me making these kinds of decisions. Currently, I the following is not only workable, but pretty easy and wouldn't restrict compatibility at all: # Classes that do something unique with the LHS AND RHS of the regression equation,
# and are therefore mutually incompatible:
class SINDy(BaseEstimator):
# same
class WeakSINDy(SINDy):
# IIUC, calculating the weak formulation _after_ function evaluation would allow :
# free simulation of discovered weak dynamics
# removing ParametrizedLibrary, WeakPDELibrary (although most of the latter would go in WeakSINDy)
# removing Guard code around combining weak/nonweak libraries, e.g. has_weak()
# removing the ridiculous multiplicity of tests for weak forms
# removing The `temporal_grid` and `spatial_grid` in non-PDE libraies.
class DiscreteSINDy(SINDy):
# Remove all the guard code around if:discrete
class SingleStep(SINDy):
# My research, estimating derivatives and xi at same time the only real questions
For later:
|
A reminder to make these changes on a separate branch and then to PR it. Couple other thoughts:
|
@Jacob-Stevens-Haas, yes, I'm on board with promoting weak form to the SINDy class level! And happy to provide some feedback, but I may be a little slow sometimes. I'm not totally clear what the plan would be--how would we control the features used in the One point worth noting, in the current |
💯
Yep, that's what I mean. It would only lose compatibility with anything else that is promoted to a subclass of SINDy, which in the basic set of changes I proposed, would only be
That's fine, maybe it's best to leave it as-is for now. It could also be added as a step between the library and optimizer, maybe a decorator like we did with
That's fine, none of the other changes depend upon trapping (the changes wouldn't reduce interoperability) there's a lot of things to do before then, and I think trapping would be the hardest to decouple. A few other (not necessarily good) options to consider: |
@znicolaou, you bring up some really good points, and its forcing me to get into the code and understand the weak form better. I suppose there's more value to be gained from refactoring within the The main benefit that would accrue to promoting the weak problem to a subclass of
I'm imagining a weak feature library that decorates another function library, similar to how The other thing that bugs me is that we have expensive, unspecific, and probably unnecessary integration tests, but WeakPDELibrary is not currently factored to allow a unit test of "Does the integral of a simple function result in a known value (e.g.
It uses the
If the weak form was a
Agree 💯 |
@akaptano , @znicolaou
When I proposed to combine the derivative and sparse regression step into a single optimization problem, it was clear that I couldn't use the existing SINDy class without some weird hacks (i.e. creating a$\dot x$ from the differentiation, expanded the optimization variable to $x$ and $\dot x$ , modified the feature library to create identity features for all $x$ and $\dot x$ fields, etc). This reminded me of a lot of what appear, to me, to be idiosyncracies and hacks in the SINDy code:
SingleStepOptimizer
that omittedSINDyPIOptimizer
andSINDyPILibrary
FeatureLibrary.calc_trajectory
TensoredLibrary
orGeneralizedLibrary
with aWeakLibrary
and theisinstance()
hacks to detect this.It became clear to me that if I made
SingleStepSINDy
a subclass ofSINDy
, I could do things much more clearly. By not taking a differentiation method, I would prevent users from thinking it made a difference. I could accept any existing Feature Library (other than weak features). And I could add a virtual base class for the optimizers that were compatible with my method (that only applied sparsity to a subset of the optimization variable, when I build this).And so I ask - are weak, parallel, and trapping problems truly a question of feature library/optimizer (and therefore compatible with other choices of differentiation method/feature library/optimizer) or are they mutually incompatible problem setups? If the latter, I think it makes a lot more sense to promote them to sublcasses of
SINDy
. This would allow them to keep their own logic, but probably reduce the SLOCs that you exclusively manage and perhaps the multiplicity of tests.I'm not as familiar with these methods, and knowing how to PR these would involve a more deep reading and understanding the papers and the code (except for PI, which is pretty straightforward). But removing ensembling from the SINDy class (among other things) was the first step, and #319 and #338 would also slim down the
SINDy
class substantially, making subclassing easier.Thoughts?
The text was updated successfully, but these errors were encountered: