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

Operator-centric Design #48

Closed
shanemcq18 opened this issue Oct 25, 2023 · 2 comments
Closed

Operator-centric Design #48

shanemcq18 opened this issue Oct 25, 2023 · 2 comments
Labels
API-change Changes to the public package interface enhancement New feature or request

Comments

@shanemcq18
Copy link
Member

shanemcq18 commented Oct 25, 2023

The existing ROM classes in the package can really only handle models of the form

$$ \frac{d}{dt}\mathbf{q}(t) = \mathbf{c} + \mathbf{Aq}(t) + \mathbf{H}[\mathbf{q}(t) \otimes \mathbf{q}(t)] + \mathbf{Bu}(t) $$

and similar. The user chooses which terms to include when the ROM is initialized (e.g., ContinuousOpInfROM(modelform="cAHB")) and there are properties for each of the operators, called c_, A_, H_, and B_, that are pretty strict about getting shapes right and so on. This setup is restrictive and a bit painful for development – right now if we want to add a new term to the above equation, e.g., a linear interaction between state and inputs or higher-order polynomial interactions, it involves a lot of changes in a lot of places. Furthermore, it's not easy to impose system-level structure, like the following:

$$ \begin{align*} \frac{d}{dt}\mathbf{q}_{1}(t) &= \mathbf{Aq}_{2}(t) + \mathbf{H}[\mathbf{q}_{1}(t) \otimes \mathbf{q}_{2}(t)] \\ \frac{d}{dt} \mathbf{q}_{2} (t) &= \mathbf{Aq}_{1}(t). \end{align*} $$

Here, we'd ideally like to specify that there is a quadratic interaction between $\mathbf{q}_{1}$ and $\mathbf{q}_{2}$ (but not $\mathbf{q}_{1}$ and $\mathbf{q}_{1}$ or $\mathbf{q}_{2}$ and $\mathbf{q}_{2}$) in the first equation, but not in the second equation, and so on. This is also an issue for Hamiltonian OpInf, see #45.

Here's a proposed solution. Instead of feeding the ROM a string that indicates the structure, feed it a list of operators (allowing certain strings as shortcuts for the monolithic case). So something like this:

import opinf

c = opinf.operators.ConstantOperator()
A = opinf.operators.LinearOperator()
H = opinf.operators.QuadraticOperator()
B = opinf.operators.InputOperator()

rom = opinf.ContinuousOpInfROM([c, A, H, B])

This would abolish the restrictive c_, A_, H_, and B_ properties in favor of an operators property in the ROM class. For the systems example, I can imagine something like this:

A12 = opinf.operators.LinearOperatorMulti(1, 2)
H112 = opinf.operators.QuadraticOperatorMulti(1, 2)
A21 = opinf.operators.LinearOperatorMulti(2, 1)

rom = opinf.ContinuousOpInfROMMulti([[A12, H112], [A21]])

These operators may need some additional information, such as the size of $\mathbf{q}_{1}$ $\mathbf{q}_{2}$ (which may not necessarily be equal).

To do this, each operator class would need a method like datablock(Q, U) that takes in states/inputs and spits out the chunk of the data matrix corresponding to that operator.
For example, ConstantOperator.datablock(Q, U) should always returns a vector of ones, LinearOperator.datablock(Q, U) should return Q, QuadraticOperator.datablock(Q, U) should return Q ⊗ Q, and InputOperator(Q, U) should return U.
Then, in the ROM class, we construct the data matrix with a single line:

data_matrix = np.hstack([op.datablock(Q, U).T for op in self.operators])

and similar for unpacking the operator matrix after solving the least-squares problem. In contrast, right now we have something like

data_matrix_chunks = []
if 'c' in self.modelform:
    data_matrix_chunks.append(ones.T)
if 'A' in self.modelform:
    data_matrix_chunks.append(Q.T)
if 'H' in self.modelform:
    data_matrix_chunks.append((QQ).T)
if 'B' in self.modelform:
    data_matrix_chunks.append(U.T)
# More 'if' statements needed each time we add a new type of operator
data_matrix = np.hstack(data_matrix_chunks)

This change will introduce a few API changes, but it should mostly add functionality to the package that isn't currently available.

@shanemcq18 shanemcq18 added enhancement New feature or request API-change Changes to the public package interface labels Oct 25, 2023
@shanemcq18
Copy link
Member Author

An upcoming change toward this design will introduce state-input interaction operators, i.e., $\mathbf{N}[\mathbf{q}(t)\otimes\mathbf{u}(t)]$, and make it easier to add higher-order (arbitrary order?) polynomial terms in the future.

@shanemcq18
Copy link
Member Author

Closing this for now as of #67, but multilithic structure remains a future enhancement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API-change Changes to the public package interface enhancement New feature or request
Development

No branches or pull requests

1 participant