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

Remove simple equations #9

Open
phannebohm opened this issue Sep 23, 2020 · 10 comments
Open

Remove simple equations #9

phannebohm opened this issue Sep 23, 2020 · 10 comments
Assignees

Comments

@phannebohm
Copy link
Collaborator

STEPS:

  1. collect alias sets
  2. choose variable to keep if necessary
  3. match/sort set (linear w.r.t. since all equations contain two crefs at max and are simple/linear)
  4. create and apply replacements
  5. save replacements in bindings of alias variables

Upgrade to old RSE:

  1. linear w.r.t. variables
  2. make decision on which variable to keep with full information
  3. alias variables can have any constant coefficient (before only 1 or -1)
  4. alias variables can have an offset (did not exist)
@phannebohm
Copy link
Collaborator Author

This is mostly done for scalar variables in 185d6e4

@phannebohm
Copy link
Collaborator Author

For now, simple equations are the ones that have at most two unknowns that appear linearly (e.g. p*x + q*y = r with x, y unknown and p, q, r some constant or parametric expressions)

What about equations like x/y = 5 or even x = 1/y? Where should we draw the line?

@phannebohm
Copy link
Collaborator Author

Also we want to extend this to work on arrays and possibly records. The simple case with a "full" equation like a = b should work just like with scalars.
But there are number of cases that need special attention.

  1. Array elements in scalar equations like a[1] = x cannot be removed. Instead in step 2 a[1] must be chosen as variable to keep. If there are more than one array element in an alias set those simple equations cannot be removed and have to stay.
  2. Equations with array slices probably need to be kept, except one side is a full array like a = b[1:3] where a can be removed.

What are the possible cases with records ?

@phannebohm
Copy link
Collaborator Author

Maybe in step 2 we want to create a new variable for each alias set, so the attribute collecting (upgrade 2) is easier (among other things). On the other hand it could be inconvenient for modellers because they cannot immediately recognize the variable by its name. A discussion with @casella on this is pending.

@casella
Copy link

casella commented Sep 23, 2020

Maybe in step 2 we want to create a new variable for each alias set, so the attribute collecting (upgrade 2) is easier (among other things).

If you do it internally, that's ok. But this shouldn't really be visible from the outside, including the debugger. This could be really confusing.

@casella
Copy link

casella commented Sep 23, 2020

Please also check #5813. IMHO the problem of selecting the "right" start attribute among aliases is far from being solved, both in terms of specification and of implementation.

More specifically, I have a fairly clear idea of what I'd like the tools to do (see examples in the ticket) but I still have no idea how to formalized, nor how to implement it.

@kabdelhak
Copy link
Owner

kabdelhak commented Sep 26, 2020

I stumbled upon one major issue with alias removal. The problem is that code generation and result files standards (the standards that dymola also follows and we definitely want to comply to that) do only allow equality and negated alias variables. This is due to the way it is represented in the result file, if there is an alias it just points with an index to the corresponding simulation variable. If the index is negated it is a negated alias variable, so there is no way of representing any other alias.

I categorized three types of alias and handled them a little different:

  1. constant alias. These are alias sets that get replaced by constants entirely. All of them are afterwards saved as parameters with corresponding constant as start value. (unfortunately constants are not put into the result file so it has to be parameters)
  2. alias/negated alias. gain of 1/-1 handled as before
  3. linear function alias. Any that follows the linear structure gain * alias + offset. They are removed from the system and will not be part of any further optimizations. After the backend they will be added to the algebraic part of the the simulation (so not part of the jacobian and solver part) and only evaluated once each step. This is not as optimal as having it entirely as an alias, but while following the standards there does not seem to be another way.

These cases can later on be expanded, but for now it suffices.

Regarding the array problem with arrays i would propose to only allow at most one array slice to be part of any alias set, because that is the one that we want to keep. Also there must not be a constant binding of the alias set. We always choose to keep the array slice and replace all others.

Regarding records we need to probably have a meeting and talk about it because we need to come up with a general specification on how to handle records and what not flattening arrays means for them.

We also need to talk about selecting attributes for alias eleminiation. Is it better to
a) find the variable with the highest rating (cref depth, fixed = true, non trivial start value, ...) and take all attributes from that, or
b) find the variable with the highest rating for each attribute that is set and do not has a default value. Combine all of those to replace the attributes of the selected variable
c) just like b) but use an artificial variable instead that replaces all of them and update the comment to alias of pin.u, pin2.u, ...

@kabdelhak
Copy link
Owner

This is mostly done, we just need to finalize the last idea as we summarized before. Right now we just keep the first variable with all its attributes.

@casella
Copy link

casella commented Oct 15, 2020

I stumbled upon one major issue with alias removal. The problem is that code generation and result files standards (the standards that dymola also follows and we definitely want to comply to that) do only allow equality and negated alias variables. This is due to the way it is represented in the result file, if there is an alias it just points with an index to the corresponding simulation variable. If the index is negated it is a negated alias variable, so there is no way of representing any other alias.

This is true, but on the other hand this file format is a de-facto standard created by Dynasim 20 years ago. Maybe it's time to review it. BTW, we may need an even more general data format to support multi-rate solvers such as QSS, which have different sampling rates for different variables, in an efficient way. One way could be to include some simple post-processing rules, e.g. as you proposed further down for linear function aliases, embedding them in the data format.

I categorized three types of alias and handled them a little different:

1. constant alias. These are alias sets that get replaced by constants entirely. All of them are afterwards saved as parameters with corresponding constant as start value. (unfortunately constants are not put into the result file so it has to be parameters)

2. alias/negated alias. gain of 1/-1 handled as before

3. linear function alias. Any that follows the linear structure _gain * alias + offset_. They are removed from the system and will not be part of any further optimizations. After the backend they will be added to the algebraic part of the the simulation (so not part of the jacobian and solver part) and only evaluated once each step. This is not as optimal as having it entirely as an alias, but while following the standards there does not seem to be another way.

These cases can later on be expanded, but for now it suffices.

Regarding the array problem with arrays i would propose to only allow at most one array slice to be part of any alias set, because that is the one that we want to keep. Also there must not be a constant binding of the alias set. We always choose to keep the array slice and replace all others.

Regarding records we need to probably have a meeting and talk about it because we need to come up with a general specification on how to handle records and what not flattening arrays means for them.

Yes. We are having the same discussion for our own high-performance compiler developed at Polimi, now that we are tacking test cases with Complex numbers.

We also need to talk about selecting attributes for alias eleminiation. Is it better to
a) find the variable with the highest rating (cref depth, fixed = true, non trivial start value, ...) and take all attributes from that

The problem is to formalize what "highest rating" actually means

b) find the variable with the highest rating for each attribute that is set and do not has a default value. Combine all of those to replace the attributes of the selected variable

This could in principle be useful, for example you may have two aliases, one with meaningful and relevant start attribute, and another one with a relevant min or max attribute, e.g. coming from the connection with a component without reversing flow. Combining them seems a good idea, if this is not too complicated. But I think this is much less urgent to achieve than a), which is the real problem with applications.

c) just like b) but use an artificial variable instead that replaces all of them and update the comment to alias of pin.u, pin2.u, ...

The text of the comment could become quite big in some cases. But I have no strong opinions here.

@phannebohm
Copy link
Collaborator Author

phannebohm commented Apr 8, 2021

What about self referential array aliases like the following?

model RSECascade
  parameter Integer n=4;
  parameter Real[n] p = {1.0, -1.5, 0.0, 0.5};
  parameter Real[n] q = {-1.0, 0.0, 2.0, 3.0};
  Real[n] x;
equation
  x[1] = exp(p[1] * cos(time) + q[1]);
  for i in 2:n loop
    x[i] = p[i] * x[i-1] + q[i];
  end for;
end RSECascade;

The coefficients would need to be cascaded so that we could rewrite it as

model RSECascade2
  parameter Integer n=4;
  parameter Real[n] p = {1.0, -1.5, 0.0, 0.5};
  parameter Real[n] q = {-1.0, 0.0, 2.0, 3.0};
  parameter Real[n] a(each fixed=false);
  parameter Real[n] b(each fixed=false);
  Real[n] x;
initial equation
  a[1] = 1;
  for i in 2:n loop
    a[i] = p[i] * a[i-1];
  end for;
  b[1] = 0;
  for i in 2:n loop
    b[i] = p[i] * b[i-1] + q[i];
  end for;
equation
  x[1] = exp(p[1] * cos(time) + q[1]);
  for i in 2:n loop
    x[i] = a[i] * x[1] + b[i];
  end for;
end RSECascade2;

and regard the for loop as alias equations for x[2],...,x[n] relating all to x[1], right?
Should we pursue things like that?

In other array equations the replacement x --> (a*x[1] + b) or x[i] --> (a[i]*x[1] + b[i]) could be made. I see no immediate problem. What do you think?

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

3 participants