Opened 12 years ago

Closed 12 years ago

#2027 closed defect (fixed)

linspace() does not work with input defined via parameters

Reported by: mikaelf@… Owned by: Martin Sjölund
Priority: high Milestone: 1.9.0
Component: Frontend Version: 1.9.0Beta
Keywords: Cc:

Description

linspace(x1,x2,n) only works if the input is given by numerical values e.g. linspace(0,100,5) and not when the input is given by parameters (se code snip below):

model linspaceTest
  Real points[5,2];
  parameter Integer pointNum = 5;
  parameter Real size[2] = {100,100};
equation
  points[:,1]=linspace(0,size[1],pointNum);
  points[:,2] = fill(size[2], pointNum);
end linspaceTest;

which fails with following error message:

Error: Array equation has unknown size in {points[1,1], points[2,1], points[3,1], points[4,1], points[5,1]}=array(size[1] * /*Real*/(i + -1) / /*Real*/(pointNum + -1) for i in 1:pointNum)
[linspaceTestTotal.mo:6:3-6:47:writable] Error: Type mismatch in equation {points[1,1], points[2,1], points[3,1], points[4,1], points[5,1]}=array(size[1] * /*Real*/(i + -1) / /*Real*/(pointNum + -1) for i in 1:pointNum) of type Real[5]=Real[:]

Change History (13)

comment:1 by Francesco Casella, 12 years ago

The weird thing is that omc complains about unknown size even when the size is a literal constant. For example, translating the following model:

model Test
  Real x[2];
  parameter Real a = 0;
  parameter Real b = 1;
equation
  x = linspace(a, b, 2);
end Test;

results in this error:

false
[Test.mo:7:3-7:23:writable] Error: Array equation has unknown size in {x[1], x[2]}={a, a + b - a}
[Test.mo:7:3-7:23:writable] Error: Type mismatch in equation {x[1], x[2]}={a, a + b - a} of type Real[2]=Real[:]}}}

For some reason, even {a, a+b-a} is not recognized as Real[2] but just as Real[:]

comment:2 by Per Östlund, 12 years ago

In r14968 I've fixed the issue that Francesco had when the size is constant, since the expression is expanded in that case and the size is known. It still does not work with parameters though, since they are not constant evaluated in this case, and I'm not sure how to fix that issue.

comment:3 by Francesco Casella, 12 years ago

The third input (n) of linspace() should *always* be evaluated. This will mean that it won't be possible to change them at run time, but we cannot do this anyway in most cases because of the structural changes this would imply. Otherwise, 95% of the application of linspace (where the size is not a constant or literal) won't work.

BTW, this is similar to the case we discussed a while ago regarding the fixed attribute, when given by a parameter expression (see #1973).

comment:4 by Martin Sjölund, 12 years ago

The third argument of linspace isn't required to be a parameter though. I'd agree if it is a parameter it should be evaluated, but this is hard to add to the type system and probably needs either a new annotation or an analysis of functions called from a place in the model environment where the dimension needs to be known... Something like:
evaluateArgIfOutputDimensionsDependOnIt(exp,name /* name of the input */,outType /* so we can see if a dimension contains name */).

comment:5 by Francesco Casella, 12 years ago

I agree that the third parameter of linspace is not required to have parameter variability. When used inside functions, we might actually need dynamic sizing. But I am not aware of any such use of linspace, while I know it is often used to specify arrays with parameter variability.

That said, I'm surprised by the fact that this model works instead:

model TestArray
  parameter Integer N = 3;
  Real x[N], y[N,N], z[2*N];
equation 
  x = ones(N);
  y = diagonal(ones(N));
  z = zeros(2*N);
end TestArray;

As far as I understand, this requires evaluating N at some point, otherwise we might change the number of variables and equations at runtime (or do I miss something here?). Why can't we do this for linspace as well?

In other words, all the operators listed in table 10-5 of the spec seem to have similar requirements in terms of array size handling. If possible, please handle linspace() in the same way as zeros(), one(), and diagonal().

comment:6 by Martin Sjölund, 12 years ago

The problem with that is: zeros() ones() and diagonal() all have special code written for them. Which means no vectorization or good error-messages for them. It's all custom code for each of the operators. Better would be to have something new that also works for linspace. That would also result in a lot of the Modelica.Math functions to return the correct dimensions without having all inputs constant.

comment:7 by Francesco Casella, 12 years ago

I also suspected that zeros, ones and diagonal were handled by special code.

I have double-checked that linspace() now works with constant array size, e.g.:

model TestLinSpace
  constant Integer N = 3;
  Real x[N];
  parameter Real a = 0;
  parameter Real b = 1;
equation
  x = linspace(a, b,N);
end TestLinSpace;

As a workaround, would it be possible to at least handle the following case?

model TestLinSpace
  parameter Integer N = 3 annotation(Evaluate = true);
  Real x[N];
  parameter Real a = 0;
  parameter Real b = 1;
equation
  x = linspace(a, b,N);
end TestLinSpace;

I've checked it with the last nightly build (r14982) but it still complains about unknown array size.

Thanks!

comment:8 by Francesco Casella, 12 years ago

If I compile the above-mentioned model (the one with the parameter), I get this error:

[TestLinSpace.mo:8:3-8:23:writable] Error: Array equation has unknown size in
{x[1], x[2], x[3]}=
array(a + (b - a) * /*Real*/(i + -1) / /*Real*/(N + -1) for i in 1:N)

I have then tried to type in the array() expression directly in the code:

model TestLinSpace
  parameter Integer N = 3;
  Real x[N];
  parameter Real a = 0;
  parameter Real b = 1;
equation
  // x = linspace(a, b,N);
  x = array(a + ((b - a) * (i - 1)) / (N - 1) for i in 1:N);
end TestLinSpace;

and, lo and behold, this works fine in r14982, even without any Evaluate annotation.

It seems to me that if the call to linspace() is replaced by its corresponding array expression up front, everything should work smoothly. That should be easy to fix.

comment:9 by Martin Sjölund, 12 years ago

Ok, one problem is that we have the following stored in the environment:
.linspace<function>(Real x1, Real x2, Integer n) => Real[:]

It is declared as:

function linspace
  input Real x1 "start";
  input Real x2 "end";
  input Integer n "number";
  output Real v[n];
// ...
end linspace;

I guess that makes it hard for the type system to get the correct type. I remember trying to fix it at one point in the past; the old inst module really doesn't like it if you try to replace some [:] with [exp]...

comment:10 by Martin Sjölund, 12 years ago

Ok, r14999 + my local changes made things a bit better:

[a.mo:7:3-7:23:writable] Error: Type mismatch in equation {x[1], x[2], x[3]}=array(a + (b - a) * /*Real*/(i + -1) / /*Real*/(N + -1) for i in 1:N) of type Real[3]=Real[3]

The problem is we don't know N is structural until after we perform the inline (yeah; silly omc). And apparently something is way off in the InstSection module since it gets two equal types.

comment:11 by Martin Sjölund, 12 years ago

Running testsuite now; then it will work. N will be marked as structural parameter but not evaluated in the flattened code (except for the dimension of the type).

The backend will then realize that this parameter is structural and remove it, making this into a constant. It simplifies the array-equation into scalar equations in the end, i.e. x[2] = a + b / 2.0 - a / 2.0

comment:12 by Martin Sjölund, 12 years ago

Owner: changed from probably noone to Martin Sjölund
Status: newassigned

comment:13 by Martin Sjölund, 12 years ago

Component: BackendFrontend
Resolution: fixed
Status: assignedclosed

Fixed in r15002, testcase added in r15003.

Note: See TracTickets for help on using tickets.