modelica / ModelicaSpecification

Specification of the Modelica Language
https://specification.modelica.org
Creative Commons Attribution Share Alike 4.0 International
101 stars 41 forks source link

Relaxing restrictions of conditional connectors #104

Closed modelica-trac-importer closed 5 years ago

modelica-trac-importer commented 5 years ago

Reported by otter on 10 Sep 2008 10:42 UTC Based on a short email correspondence with Hans in April (due to streams connectors, where I learned the details of inside/outside connectors), here is a short (not thought through) sketch how to relax the restrictions on conditional connectors, in order to get rid of the awful code of conditional connectors in the Rotational and MultiBody library:

For balanced modelsmodifiers onoutside connectors in the model where the connector is defined are allowed (as an alternative for equations in the equation section; modifiers for inside connectors must remain forbidden). This would allow to write a conditional connector instance as:

Support support(tau = -flange_a.tau - flange_b.tau)
                       if not useSupport;

and "tau = .." would count as one equation.

Outside connectors are in some sense similar to record elements inside the model (and binding equations for records are allowed in balanced models). There are some issues with having binding equations for input elements (since they are used to extract information instead of setting them). The connector-instance could in many cases be inherited (from a general interface-model); allowing binding equations for inherited connectors is more problematic and it might be that this cannot be allowed.


Migrated-From: https://trac.modelica.org/Modelica/ticket/104

modelica-trac-importer commented 5 years ago

Modified by dietmarw on 11 Sep 2008 08:32 UTC

modelica-trac-importer commented 5 years ago

Comment by HansOlsson on 17 Nov 2008 14:10 UTC Not clear that adding it would resolve the complete issue (including using phi). However, could be added without breaking balancing, since equations for records and connectors can already be given textually.

Proposed: "Default binding equations" include binding equations that are applied for a connector/record/type component, since only models and block components are assumed to be balanced.

modelica-trac-importer commented 5 years ago

Comment by AHaumer on 17 Nov 2008 14:14 UTC I suppose problems, consider a more complete code snippet:

  parameter Boolean useSupport;
  Flange_a flange_a;
  Flange_b flange_b;
//either support or fixed are conditionally removed!
  Support support(tau = -flange_a.tau - flange_b.tau) if useSupport;
  Fixed fixed(tau = -flange_a.tau - flange_b.tau) if not useSupport;
  SI.Angle phi_a = flange_a.phi - (if useSupport then support.phi else fixed.phi);//?
  SI.Angle phi_b = flange_b.phi - (if useSupport then support.phi else fixed.phi);//?
modelica-trac-importer commented 5 years ago

Comment by HansOlsson on 20 Nov 2008 09:38 UTC Well, no need to have if outside, since one could write:

parameter Boolean useSupport;
  Flange_a flange_a;
  Flange_b flange_b;
//either support or fixed are conditionally removed!
  Support support(tau = -flange_a.tau - flange_b.tau, phi=support_phi) if useSupport;
  Fixed fixed(tau = -flange_a.tau - flange_b.tau, phi=support_phi) if not useSupport;
  SI.Angle phi_a = flange_a.phi - support_phi;//?
  SI.Angle phi_b = flange_b.phi - support_phi;//?

Not sure whether it is good though

modelica-trac-importer commented 5 years ago

Comment by mtiller on 26 Nov 2008 13:34 UTC I want to take a step back from Martin's specific proposal and clarify something. It seems to me the fundamental issue here is how to have conditional equations associated with conditional components.

The issue seems to be making sure that the equations should be "linked" to the component so that you can always say with certainty that one never exists without the other. Wouldn't it be extremely simple to just do this:

  parameter Boolean useSupport;
  Flange_a flange_a;
  Flange_b flange_b;
  Support support if useSupport;
  Fixed fixed if not useSupport;
  SI.Angle phi_a;
  SI.Angle phi_b;
equation
  if exists(support) then
    // equations when support is present
  end if;
  if exists(fixed) then
    // equations when fixed is present
  end if;

Wouldn't this address all "balancing" issues?

A tool could almost trivially replace "exists(component_name)" with the conditional expression associated with that component name.

It seems like this would support "balance", avoid any possibility of confusion, be completely checkable and nearly trivial to implement.

Am I missing something here?

modelica-trac-importer commented 5 years ago

Comment by mtiller on 26 Nov 2008 16:46 UTC I want to clarify my previous comment. On the mailing list, Martin said:

"the hard part is to guarantee that for all combinations of conditional flags, (a) the remaining equations do not reference the disabled components and (b) that this set of equations is balanced."

I think much of the confusion so far is that we are trying to address the situation where the equations exist within some kind of conditional construct and trying to make sure that that conditional construct is logically equivalent to the condition under which the component is declared. My point in my previous comment is to side-step the issue entirely by making the equations conditionally dependent on the component directly.

Let us not forget that the goal here is making it easier for modelers to use conditional components while making the resulting models readable. I don't think we need a scheme that makes it impossible to construct models that have errors but simply to make it so that it is possible to write readable code with conditional components that can be properly checked and also properly diagnosed (i.e. good diagnostic messages in case of errors).

For this reason I would propose the following:

A "worst case" way of checking all possible combinations to be checked is to simply consider the 2^N possibilities where N is the number of conditional components. By giving users access to an "exists" primitive you then make it easy for them to write code that protects against accessing components that may not exist. You can then run through this worst case situation and check all possible cases.

I see two issues with this. The first is with cases like this:

  parameter Boolean useSupport;
  Support support if useSupport;
  Fixed fixed if not useSupport;

The 2^2 approach says there are four possible combinations but it is clear that there are actually only two possibilities. There is nothing to prevent a "smart" tool from analyzing all conditional expressions associated with components and then expanding those to identify the constrained set of possibilities.

The other issue I see would be cases like this:

  parameter Boolean useSupport;
  Support support if useSupport;
  Fixed fixed if not useSupport;
  Real a;
equation
  if exists(support) then
    a = support.phi;
  end if;
  if exists(fixed) then
    a = fixed.phi;
  end if;

The problem with this example is that if you consider all 2^2 possibilities it appears that you are missing an equation for "a" in a case where neither the support nor the fixed is present (and too many equations if both exist). Of course, this isn't possible but the "dumb" approach couldn't detect this. But I don't think this will honestly come up very often. The reason is that the example above is a bit contrived. It is written this way to work around the current restrictions. It would be more naturally written as follows:

  parameter Boolean useSupport;
  Flange support if useSupport;
  Angle support_phi;
equation
  if exists(support) then
    support_phi = support.phi;
    flange_a.tau + flange_b.tau + support.tau = 0;
  else
    support_phi = 0;
    flange_a.tau = -(1+R)*flange_b.tau;
  end if;

In this case there is truly only two possibilities to check and both should be fine. Note that no reference to support.* appears outside the "exists(support)". In fact, it would be quite straightforward for a tool to analyze all expressions within a model and then make sure that access to any conditional components was contained within a "exists(...)" condition. For example, detecting this kind of error should be trivial:

  Flange support if useSupport;
  Angle support_phi;
equation
  support_phi = support.phi;

Not only could this be detected, but it would be simple to generate a diagnostic message saying "access to support.phi only allowed for cases where exists(support) is known to be true".

The point here is not to focus on how to ensure there are no errors but rather to give the model developers the tools to write code that will check and in cases where there are issues to make sure that good diagnostics are possible.

modelica-trac-importer commented 5 years ago

Comment by HansOlsson on 27 Nov 2008 14:39 UTC This is not directly related to the proposal, but I find equations such as:

  if exists(support) then
    support_phi = support.phi;
    flange_a.tau + flange_b.tau + support.tau = 0;
  else
    support_phi = 0;
    flange_a.tau = -(1+R)*flange_b.tau;
  end if;

to be confusing, since the torque-balance equations do not seem to match (one involves gear-ratio, the other one not), and I would find it hard to verify correctness for equations for a combinatorial number of such cases.

modelica-trac-importer commented 5 years ago

Comment by magnus on 28 Nov 2008 13:43 UTC I have little insight in the difficulties related to implementation and checking of models based on an "exist" operator. I do like the idea from a user point of view. I am also in favor of Martins original proposal, and I think that they both would very much improve the support for conditional model elements.

modelica-trac-importer commented 5 years ago

Comment by mtiller on 28 Nov 2008 22:58 UTC While I can appreciate that these equations (which may have been completely wrong in my example, I just guessed) may not be intuitive, I'd like to stay focused on the issue at hand which is the ability to express conditional components and equations in a way which is robust and checkable.

The essential point here is that the physics will dictate what the equations will look like for these cases and that shouldn't have any bearing on how we express the conditional nature of the elements.

I'd also like to add here in the record of this ticket a comment that I made on the mailing list. Specifically, I suspect that most (if not all) of the problematic cases in checking could be addressed by having tools that can reduce the number of possible combinations using one simple trick (in two simple forms). Specifically, when you have mutually exclusive elements or elements with exactly the same condition that you express them as follows:

  Real x if cond;
  Real y if exists(x); // Always appears if x appears
  Real z if not exists(x); // Mutually exclusive with x
equation
  if exists(x) then
    x = ...;
    y = ...;
  else
    z = ...;
  end if;

The patterns required here are:

Using these patterns it is quite straightforward to see that there are only two conditions that need to be checked in this model (x exists and x doesn't exist).

The key point here is that tools only have to be aware of a few simple patterns in order to be able to deal with this complex case. The code is extremely readable and the intent is, IMHO, very clear.

I'd be perfectly happy with a solution that was fairly restrictive in the specification (perhaps for the time being at least) because I suspect that nearly all important cases can be covered even with restrictions. Restrictions I think are reasonable so far (we'd have to try them out of course) would be:

Just to be clear, the first restriction could still allow things like:

equation
  if exists(x) then
    if reverseFlow then
      x.m_dot = ...;
    else
      x.m_dot = ...;
    end if;
  end if;

  if reverseFlow then
    if exists(y) then
      y.m_dot = ...;
    end if;
  else
    if exists(y) then
      y.m_dot = ...;
    end if;
  end if;

The point is that there just needs to be an enclosing "if" that uses the specified form but they can be nested arbitrarily. The important aspect of such constructions is that it ensures that the surrounding conditional expressions are always effective "if exists(x) AND ..." so that the enclosing statements are certain to only be considered if exists(x) is true.

modelica-trac-importer commented 5 years ago

Comment by mtiller on 30 Nov 2008 02:46 UTC An additional thought to keep in mind. If we had conditional expressions that depended explicitly on the existence of an element, e.g.

  if exists(x) then
  end if;

Then we could also make it easier to check model by requiring that the number of equations within the "exists(x)" if statement be exactly equal to the number of variables introduced by the element. Here are some examples:

  Real x if cond1;
  Modelica.Electrical.Analog.Interfaces.PositivePin p if cond2;
  Modelica.Mechanics.Rotational.Interfaces.Flange_b support if cond3;
equation
  if exists(x) then
    x+3*y = 0;
  end if;
  if exists(support) then
    support.phi = 0.0;
  end if;
  if exists(p) then
    connect(p,motor.p);
  end if;

These example show several different forms but the important part is that you could impose such restrictions in the semantics to help simplify the task of checking.

My only concern with such an idea is whether the number of variables introduced by an element is something that can be easily determined for all cases (in particular with acausal connectors).

Is it possible to avoid testing all combinations but instead simple check the "deltas" for each component being introduced? By this I mean, could you just consider each conditional element in turn, compute the change in the number of equations required if such a component were present and then confirm that the number of equations enclosed by an "if exists(that_component) then" clause is exactly equal to that? (more strictly, it would probably have to be that the number of equation in the "then" clause minus the number of equations in the "else" clause would have to be equal to the number of additional equations required by the element if it were present.

This is just a thought since I could imagine there being some tricky cases, but it seems like one way to simplify the checking process.

Any thoughts?

modelica-trac-importer commented 5 years ago

Comment by HansOlsson on 5 Dec 2008 14:37 UTC Replying to [comment:9 mtiller]:

While I can appreciate that these equations (which may have been completely wrong in my example, I just guessed) may not be intuitive, I'd like to stay focused on the issue at hand which is the ability to express conditional components and equations in a way which is robust and checkable.

The essential point here is that the physics will dictate what the equations will look like for these cases and that shouldn't have any bearing on how we express the conditional nature of the elements.

Physics will restrict the allowed equations, but not entirely dictate them.

The problem with other "reflexive" constructs on connects (potentialRoot, isRooted) is that they have encouraged a style of writing models that led to several hard to find errors, see e.g. #50

Thus we must have concrete correct examples to ensure that we don't repeat the mistakes, and also to see whether there are way of restricting the semantics that more easily lead to correct models.

As concrete examples physics will not dictate whether we write (haven't checked it):

  Flange_a support if useSupport;
equation
  if exist(support) then
    flange_a.phi-support.phi=ratio*(flange_b.phi-support.phi);
    flange_a.tau+flange_b.tau+support.tau;
  else
    flange_a.phi=ratio*flange_b.phi;
  end if;

or:

  Torque support_tau;
  Angle support_phi;
  Flange_a support if useSupport;
equation
  if exists(support) then
    support_phi=support.phi;
  else
    support_phi=0;
  end if;
  flange_a.phi-support_phi = ratio *(flange_b.phi-support_phi);
  flange_a.tau+flange_b.tau+support_tau=0;

the 2nd alternative can be written using modifiers on connectors as:

  Angle support_phi;
  Torque support_tau;
  Flange_a support(phi=support_phi, tau=support_tau) if useSupport;
equation
  if not useSupport
    support_phi=0;
  end if;
  flange_a.phi-support_phi = ratio *(flange_b.phi-support_phi);
  flange_a.tau+flange_b.tau+support_tau=0;

There are also other options, of course.

We should start from such concrete examples to design the use-patterns together with the syntax and not try to design the syntax in isolation.

Note that I don't view balancing as the hard problem, to me balancing is similar to a spell-check of a text or compilation of a program without errors; i.e. just a first step towards correctness.

modelica-trac-importer commented 5 years ago

Comment by HansOlsson on 9 Feb 2009 13:50 UTC Proposed text added to specification for modifier proposal. Will be discussed at next meeting.

modelica-trac-importer commented 5 years ago

Modified by HansOlsson on 17 Mar 2009 12:23 UTC

modelica-trac-importer commented 5 years ago

Comment by hansolsson on 25 Oct 2018 15:32 UTC Unhide tickets in preparation for move to GitHub. (Examined tickets before; these are closed tickets that influenced specification or related documents and additionally relevant ones #52 #260 #2226 #101 #651.)