Opened 12 years ago
Closed 12 years ago
#2027 closed defect (fixed)
linspace() does not work with input defined via parameters
Reported by: | 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 , 12 years ago
comment:2 by , 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 , 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 , 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 , 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 , 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 , 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 , 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 , 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 , 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 , 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 , 12 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:13 by , 12 years ago
Component: | Backend → Frontend |
---|---|
Resolution: | → fixed |
Status: | assigned → closed |
The weird thing is that omc complains about unknown size even when the size is a literal constant. For example, translating the following model:
results in this error:
For some reason, even {a, a+b-a} is not recognized as Real[2] but just as Real[:]