Opened 5 years ago

Last modified 5 years ago

#5874 assigned task

Function body dependencies FE or BE?

Reported by: Karim Adbdelhak Owned by: Per Östlund
Priority: high Milestone: Future
Component: Frontend Version:
Keywords: function body Cc: Francesco Casella

Description (last modified by Karim Adbdelhak)

Consider following function and its derivative:

function f
  input x;
  input dx;
  output y;
algorithm
  y := x;
annotation (
    derivative = df,
    Inline=false);
end f;
function df
  input x;
  input dx;
  output y;
algorithm
  y := dx;
end df;

The function call has following structure in the Frontend:

  record CALL
    Absyn.Path path;
    list<Exp> expLst;
    CallAttributes attr;
  end CALL;

And the expLst contains all inputs such that they will be used for any dependency analysis needed. As we see both functions have inputs they do not actually depend on so that leads to different problems, such as thae one mentioned in #5770. In the Backend we would need to get the actual function body from the function tree and traverse it, i would like to have them collected once and always available.

Can that information be provided by the Frontend when the function tree is built?

EDIT:
This also occurs for FMI models where the interface functions can have dummy inputs.

Change History (13)

comment:1 by Karim Adbdelhak, 5 years ago

Owner: changed from somebody to Per Östlund
Status: newassigned

comment:2 by Karim Adbdelhak, 5 years ago

Description: modified (diff)

comment:3 by Per Östlund, 5 years ago

I'm not quite sure what you're asking for here. Do you want the frontend to compile a list of unused inputs for each function, or am I misunderstanding something?

comment:4 by Karim Adbdelhak, 5 years ago

Yes basically. I am not entirely sure how to mark this but i would like to know that e.g. the second input is not actually used.

Maybe we need to update this part:

  record CALL
    Absyn.Path path;
    list<Exp> expLst;
    CallAttributes attr;

    list<Integer> skippableInput; /* !!! like this? !!! */ 
  end CALL;

Or this part:

  record FUNCTION " A Modelica function"
    Absyn.Path path;
    list<FunctionDefinition> functions "contains the body and an optional function derivative mapping";
    Type type_;
    SCode.Visibility visibility;
    Boolean partialPrefix "MetaModelica extension";
    Boolean isImpure "Modelica 3.3 impure/pure, by default isImpure = false all the time only if prefix *impure* function is specified";
    InlineType inlineType;
    ElementSource source "the origin of the component/equation/algorithm" ;
    Option<SCode.Comment> comment;

    list<Integer> skipableInput; /* !!! like this? !!! */
end FUNCTION;

The first one would be best, but i would be glad with either. The reason i want indices instead of crefs is that i have different expressions in the input list than those that actually occur in the function body. I need to know which input to skip by index. Do you think that would be a good idea or is viable?

Last edited 5 years ago by Francesco Casella (previous) (diff)

comment:5 by Per Östlund, 5 years ago

Another option would be to just remove the input entirely if it's not used, along with the corresponding argument in any calls to the function. The new frontend could easily do that if it's going to analyse which inputs are unused anyway. But maybe there are situations where changing the function signature isn't allowed?

If changing the function signature isn't viable we could also replace unused arguments in calls with dummy values, but that might require some changes in the backend to handle it.

If we decide to add the information to the DAE, adding it to the function itself would in my opinion be the most natural. But if that would lead to too much function lookup in the backend we could add it to the call instead. Calls in the NF contains a reference to the function it calls anyway, so it doesn't need to do any lookup to access the function.

comment:6 by Karim Adbdelhak, 5 years ago

The function signature is mandatory for the symbolic differentiation to correctly map the inputs.

f(x,y,z) --differentiate-> df(x,y,z)

Even if x is only used in the first and y only in the second, they need to be present to know which input is supposed to be which when looking up the predefined derivative function and generating the derivative function call. If some values are skipped inbetween you cannot reconstruct which they were. I think there are many more (maybe fringe) cases where it is needed.

Dummy values seem like a lot of work and they also break the stuff i just mentioned if not implemented correctly.

Yes it seems like adding it to the function would be the most natural way and there should not be as many lookups needed. Most of it is handled by inline anyway, only in this late/no inline dummy input cases it even occurs.

I also don't feel particularly good about just saving the indices of the skipable/dummy inputs, but i don't know a better way of making it independent of the actual names. It should work but is not really beautiful.

comment:7 by Francesco Casella, 5 years ago

@Karim, this was really a nasty issue you pointed out, I would have never thought about it.

I'm trying to figure out what functions actually pose this issue in the example I considered in #5770. Could you make some concrete example for my information?

Last edited 5 years ago by Francesco Casella (previous) (diff)

in reply to:  7 comment:8 by Karim Adbdelhak, 5 years ago

Replying to casella:

@Karim, this was really a nasty issue you pointed out, I would have never thought about it.

I'm trying to figure out what functions actually pose this issue in the example I considered in #5770. Could you make some concrete example for my information?

For the problem described in ticket #5770 it seems to origin from the function Modelica.Media.Water.IF97_Utilities.rho_props_ph (which is used in Modelica.Media.Water.IF97_Utilities.rho_ph) and has a pre defined derivative function Modelica.Media.Water.IF97_Utilities.rho_ph_der similar to the minimal example of this ticket.

I will make further explanations on problem specific details on the other ticket.

comment:9 by Karim Adbdelhak, 5 years ago

Description: modified (diff)

in reply to:  6 ; comment:10 by Per Östlund, 5 years ago

Replying to Karim.Abdelhak:

Yes it seems like adding it to the function would be the most natural way and there should not be as many lookups needed.

Ok, we'll aim for that then. Is this information needed for all functions, or only those that have derivative annotations?

in reply to:  10 comment:11 by Karim Adbdelhak, 5 years ago

Replying to perost:

Replying to Karim.Abdelhak:

Yes it seems like adding it to the function would be the most natural way and there should not be as many lookups needed.

Ok, we'll aim for that then. Is this information needed for all functions, or only those that have derivative annotations?

Hmm i don't think the derivative annotation actually matters, as i said it can also occur for FMI functions. I think the relevant functions are those that are not inlined before causalization. So those with Inline=false, LateInline=true or InlineAfterIndexReduction=true. In this case we are also very safe if someone (for whatever reason) decides to create any function that has dummy inputs that should not be inlined. The inline module should take care of everything else.

comment:12 by Per Östlund, 5 years ago

I've implemented this in 2b9188a now, let me know if you find any issues. It's only implemented for the NF of course, the OF will just give an empty list all the time.

It's also done for all functions in the function tree right now, since it's relatively inexpensive anyway. I also thought we might check for unassigned outputs at the same time, but this turned out to be a bit more complicated and didn't make it in for now.

in reply to:  12 comment:13 by Karim Adbdelhak, 5 years ago

Replying to perost:

I've implemented this in 2b9188a now, let me know if you find any issues. It's only implemented for the NF of course, the OF will just give an empty list all the time.

It's also done for all functions in the function tree right now, since it's relatively inexpensive anyway.

Perfect thank you! I will start on trying to fix the problem from #5770 with this feature.

I also thought we might check for unassigned outputs at the same time, but this turned out to be a bit more complicated and didn't make it in for now.

At first i thought we should not care about this because it should be illegal anyways, but maybe there are some fringe cases were dummy outputs are needed. All the functions i have been working with don't have these dummy outputs. The function signature that is relevant for differentiation and such things only cares about the inputs, the output just has to be consistent in size. I think we can ignore that for now.

Note: See TracTickets for help on using tickets.