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

AAAReductor #2249

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft

AAAReductor #2249

wants to merge 4 commits into from

Conversation

lbalicki
Copy link
Member

@lbalicki lbalicki commented Jan 12, 2024

This PR adds the AAAReductor. Although we already have the PAAAReductor which can also handle non-parametric problems, the new AAAReductor does two things differently: First, it is based on strictly proper barycentric forms unlike the p-AAA implementation which uses just proper barycentric forms. Additionally, the AAAReductor allows for directly computing the ROM as an LTIModel rather than a TransferFunction.

@lbalicki lbalicki added the pr:new-feature Introduces a new feature label Jan 12, 2024
@lbalicki lbalicki added this to the 2024.1 milestone Jan 12, 2024
@artpelling artpelling self-requested a review January 16, 2024 15:32
# Define ROM with constant output
tf = np.vectorize(lambda s: np.mean(self.Hs))

self.itpl_part = []
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
self.itpl_part = []

This line should be deleted, right?


while len(self.itpl_part) < max_itpl:

# compute approximation error over LS partiation of sampled data
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
# compute approximation error over LS partiation of sampled data
# compute approximation error over LS partition of sampled data

@@ -451,3 +452,239 @@ def bary_func(*args):
return np.atleast_2d(nd)

return bary_func

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change

w /= np.linalg.norm(w)
v /= np.linalg.norm(v)
self.MIMO_Hs = Hs
self.Hs = Hs @ v @ w
Copy link
Member

Choose a reason for hiding this comment

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

is this correct? it looks a bit dangerous..

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it is correct. This is just the "cheap" way of dealing with MIMO data in rational approximation. Implementing the actual tangential AAA is the way to go in the future, but for now I think it works well.

Comment on lines 504 to 519
if len(Hs.shape) > 1:
self._dim_output = Hs.shape[1]
self._dim_input = Hs.shape[2]
rng = new_rng(0)
w = rng.normal(size=(self._dim_output,))
v = rng.normal(size=(self._dim_input,))
w /= np.linalg.norm(w)
v /= np.linalg.norm(v)
self.MIMO_Hs = Hs
self.Hs = Hs @ v @ w
else:
self._dim_input = 1
self._dim_output = 1

if self._dim_input == self._dim_output == 1:
Hs = np.squeeze(Hs)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if len(Hs.shape) > 1:
self._dim_output = Hs.shape[1]
self._dim_input = Hs.shape[2]
rng = new_rng(0)
w = rng.normal(size=(self._dim_output,))
v = rng.normal(size=(self._dim_input,))
w /= np.linalg.norm(w)
v /= np.linalg.norm(v)
self.MIMO_Hs = Hs
self.Hs = Hs @ v @ w
else:
self._dim_input = 1
self._dim_output = 1
if self._dim_input == self._dim_output == 1:
Hs = np.squeeze(Hs)
if len(Hs.shape) > 1:
self._dim_output = Hs.shape[1]
self._dim_input = Hs.shape[2]
if self._dim_input == self._dim_output == 1:
Hs = np.squeeze(Hs)
else:
rng = new_rng(0)
w = rng.normal(size=(self._dim_output,))
v = rng.normal(size=(self._dim_input,))
w /= np.linalg.norm(w)
v /= np.linalg.norm(v)
self.MIMO_Hs = Hs
self.Hs = Hs @ v @ w

Comment on lines 531 to 535
Initial partition for interpolation values. Should be `None` or a nested list
such that `itpl_part[i]` corresponds to indices of interpolated values with
respect to the `i`-th variable. I.e., `self.sampling_values[i][itpl_part[i]]`
represents a list of all initially interpolated samples of the `i`-th variable.
If `None` p-AAA will start with no interpolated values.
Copy link
Member

Choose a reason for hiding this comment

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

This needs to be updated.

Comment on lines 537 to 539
Maximum number of interpolation points to use with respect to each
variable. Should be `None` or a list such that `self.num_vars == len(max_itpl)`.
If `None` `max_itpl[i]` will be set to `len(self.sampling_values[i]) - 1`.
Copy link
Member

Choose a reason for hiding this comment

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

This too

Comment on lines 574 to 576
errs = np.empty(len(ls_part))
for i, ls_s in enumerate(self.s[ls_part]):
errs[i] = np.abs(tf(ls_s) - self.Hs[ls_part[i]])
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
errs = np.empty(len(ls_part))
for i, ls_s in enumerate(self.s[ls_part]):
errs[i] = np.abs(tf(ls_s) - self.Hs[ls_part[i]])
errs = np.array([np.abs(tf(self.s[i]) - self.Hs[i]) for i in ls_part])

Cr = np.empty((self._dim_output,r*self._dim_input), dtype=itpl_vals.dtype)
for i in range(r):
Cr[:,self._dim_input*i:self._dim_input*(i+1)] = itpl_vals[i,:]
L = np.diag(itpl_nodes)
Copy link
Member

Choose a reason for hiding this comment

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

I get an error that itpl_nodes is undefined, if it converges at the first step. Maybe we can handle this edge case.

Copy link
Member Author

Choose a reason for hiding this comment

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

I decided to force the algorithm to pick at least one interpolation point. Otherwise the resulting TF is just constant, thus not strictly proper and things are not working out nicely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr:new-feature Introduces a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants