How to change every i-th element of an array in Modelica - arrays

I’m trying to change every i-th element of an array, as an event occurs. This could be reached by the following code. In this example every second element should be changed. Due to parameter defined array size, the second argument of the ‘inner’ loop should be set by the variable ‘Upper’.
model Test
Boolean Event;
Real Vector[6](start = ones(6), fixed = true);
Integer Upper;
algorithm
when Event then
Vector := ones(6);
Upper := 3;
for i in {2*j for j in 1:Upper} loop
Vector[i] := Vector[i]+1;
end for;
end when;
equation
Event = if time <=1 then false else true;
end Test;
Dymola doesn’t accept this solution, stating ‘Failed to calculate the last argument of 1:Upper’. When I enter 3 directly instead of ‘Upper’, the code works.
Is there a possibility to fix this? Or is there an easier way to change every i-th element in algorithm section?
Thanks in advance.

I would say this is a Dymola issue. OpenModelica handles it just fine.
This is an alternative formulation that might work better for you (hiding everything in a function should make Dymola happier since there are no dimension sizes that are hard to deduce).
function incrementEveryIth
input Real v[:];
input Integer i;
input Real increment := 1;
output Real o[size(v,1)] := v;
algorithm
o := {if mod(n,i)<>0 then v[n] else (v[n]+increment) for n in 1:size(v,1)};
end incrementEveryIth;
model Test
Boolean Event;
Real Vector[6](start = ones(6), each fixed = true);
algorithm
when Event then
Vector := incrementEveryIth(pre(Vector),2);
end when;
equation
Event = if time <=1 then false else true;
end Test;
Or perhaps this one:
model Test
Boolean Event;
Real Vector[6](start = ones(6), each fixed = true);
algorithm
when Event then
Vector := pre(Vector); // This should not really be needed, but OpenModelica insists
Vector[1:2:6] := Vector[1:2:6] + {1,1,1};
end when;
equation
Event = if time <=1 then false else true;
end Test;

Related

Modelica flexible array size within record - failed to expand

I'm trying to read in multiple files (csv, 2 columns) with belonging names (String) and interpolation methods smoothness (String). By using a record I get a nice GUI in Dymola:
To explain my problem, here is a simplified model:
model Test_Strings
parameter String x[:];
parameter Integer k = size(x,1);
Integer i;
initial algorithm
i := 0;
Modelica.Utilities.Streams.print(String(i));
Modelica.Utilities.Streams.print(String(k));
equation
algorithm
when sample(1,1) then
i :=pre(i) + 1;
Modelica.Utilities.Streams.print(String(i));
for j in 1:k loop
Modelica.Utilities.Streams.print(x[j]);
end for;
end when;
end Test_Strings;
The GUI for this looks as follows:
The code to run it:
model Test_Strings_System
Test_Strings test_Strings(x={"a","b","c","d"});
end Test_Strings_System;
This will give the following result in the console:
Now, if I try to use a record:
record MyRecord2
parameter String name = "NoName";
end MyRecord2;
And adapt the model (only the first parameter line MyRecord2 x[:] and within the for loop x[j].name changed):
model Test_Strings2
parameter MyRecord2 x[:];
parameter Integer k = size(x,1);
Integer i;
initial algorithm
i := 0;
Modelica.Utilities.Streams.print(String(i));
Modelica.Utilities.Streams.print(String(k));
equation
algorithm
when sample(1,1) then
i :=pre(i) + 1;
Modelica.Utilities.Streams.print(String(i));
for j in 1:k loop // k must be fixed number if equation
Modelica.Utilities.Streams.print(x[j].name); // j must be fixed number if algorithm
end for;
end when;
end Test_Strings2;
Then I get a translation error: Internal error: failed to expand string.
If I fix k or j within the for loop to a given number (let's say 3) then it works, but depending if it's within an algorithm or equation section (see comments within code).
I had similar problems with flexible array sizes and still don't understand how to solve it.
Do I have to use functions?
How can I use flexible array sizes which are defined depending on external data, selected as parameters prior to simulation (e.g. the length of a table)?
Or is the problem in this case somewhere else?
Thanks.
You can change the model to have an array of records as visible parameters, but internally use an array of strings (tested with Dymola 2017 and later):
model Test_Strings2
parameter MyRecord2 x[:];
parameter Integer k = size(x,1);
Integer i;
protected
parameter String s[:]=x.name; // Hack
initial algorithm
i := 0;
Modelica.Utilities.Streams.print(String(i));
Modelica.Utilities.Streams.print(String(k));
equation
algorithm
when sample(1,1) then
i :=pre(i) + 1;
Modelica.Utilities.Streams.print(String(i));
for j in 1:k loop
Modelica.Utilities.Streams.print(s[j]);
end for;
end when;
end Test_Strings2;

Algorithm that finds the start and the finish of many sub-arrays?

so I have this question in C:
Given an array that only contains 0's and 1's (Example: [1,1,0,0,0,0,1,0,1,0,1,1]).
I need to find the start of a "ring interval" and the finish of the same "ring interval" (there could be many rings like that, we'll have to store the start and finish of each one in a matrix of 2 columns)
"Silence" is when at least two 0's are next to each other. (in the given array, the sub array [0,0,0,0] is silent.
"Ring interval" is when Silence doesn't occur. (example in the given array, the sub array [1,1] (first 2 values), and the sub array [1,0,1,0,1,1] (the end of the array)).
So we'll have to store [0,1] in the first row of the matrix.
then [6,11]. since the second sub array starts at the 6th index and ends at the 11th.
I can't seem to describe it any better, it's in a different language and quite a bit more complicated than this.. i hope you understand!
Examples:
Array = [0,0,0,0,1,0,1,1,1,0,0,0,1,0,0]
Matrix would be : [4,8] [12,12]
Array = [1,0,0,1,1]
Matrix would be : [0,0] [3,4]
Thank you!
I have a simple algorithm for this that you can quite easily translate to C with a bit of research. You could also translate it to basically any other language as well:
Step 1) create two boolean values. One will be true if there is currently a "silence", the other will be true if the last value seen was a zero. Both of these should be true. If we do not assume that there are infinite zeros before the first element of the array, then there will be problems if the first number in the array is zero.
Step 2) loop over the array and check against one of 2 conditions: a) If you see a 1, set silence to false, previousZero to false. If this 1 breaks a silence, store this value as it is the beginning of your next range. b) If the value is zero and there is not a silence, set previousZero to true. If previousZero was already true, you have reached a silence, so set silence to true and store your beginning position and end position in your output array. Your end position in this situation would be the current position -2 to account for the zeros you just examined
Step 3) once you've looped through the entire array, you need to make sure you didn't end on a valid range. if silence is false, you know you ended on a valid range. store this range in your output array by using the begin value you stored in your loop and the end of the array as the end value.
This algorithm runs in linear time. Here is some pseudo-code to get you started on your implementation in C or whatever you choose.
findRing(Array arr)
bool silence = true, previousZero = true;
int currentBegin = 0, currentEnd = 0;
for( int i = 0; i<arr.length; i++) {
if(arr[i] == 1)
if(silence == true)
currentBegin = i;
silence = false;
previousZero = false;
else if(arr[i] == 0 && silence == false)
if(previousZero)
silence = true;
currentEnd = 1-2;
addToOutput(currentBegin, currentEnd);
else
previousZero = true;
}
if(silence == false)
currentEnd = arr.length - 1;
addToOutput(currentBegin, currentEnd);
I implemented this pseudo-code in C++ and got the same outputs you provided in your examples. It should be easy to implement in C or Matlab as you mentioned and runs in O(n) time.

End condition of an IF loop that depends on a 3D array

I'm writing a program which will move a particle about a cube, either left,right,up,down, back or forward depending on the value randomly generator by the program. The particle is able to move with cube of dimensions LxLxL. I wish the program to stop when the particle has been to all possible sites and the number of jumps taken output.
Currently I am doing this using an array[i][j][k] and when the particle has been to a position, changing the value of the array at that corresponding point to 0. However, in my IF loop I have to type out every possible combination of i,j and k in order to say if they are all equal to 0 the program should end. Would there be a better way to do this?
Thanks,
Beth
Yes. I'm assuming the if in question is the one contained within the triple nested loop who's body sets finish=1;. The better way of doing this is to set a your flag before the loop, beginning with a true value then setting it to false and breaking if you encounter a value other then zero. Your if statement becomes much simpler, like this;
int finish =1; // start with a true value
//loops are untouched so still got the for i and for j above this
for(k = 0; k < 15; k++)
{
if (list[i][j][k] != 0)
{
finish = 0;
break;
}
}
// outside all the loops
return finish;
I think this is what you're asking for but if not please edit your question to clarify. I'm not sure if there is some technical name for this concept but the idea is to choose your initial truth value based on what's most efficient. Given you have a 15x15x15 array and a single non-zero value means false, it's much better to begin with true and break as soon as you encounter a value that makes your statement false. Trying to go in the other direction is far more complicated and far less efficient.
Maybe you can add your list[i][j][k] to a collection every time list[i][j][k]=0. Then at the end of your program, check for the collection's length. If it's of the right length, then terminate..

Ensure clause in Eiffel

I'm doing an assignment in Eiffel and I'm having trouble implementing my ensure clause. Is there some special syntax you need to include a variable or function?
This is my code at the moment for my 'put' function
put(key: K; value: V)
require
key /= void
local
tmp:ITEM[K,V]
do
create tmp.make(key, value)
list.put_front (tmp)
count := count + 1
ensure
count = old count + 1 and list.has(key, value)
end
This is the code for the 'has' function
has(key:K; val:V):BOOLEAN
require
key /= void
local
flag: INTEGER
do
flag := 0
from
list.start
until
list.exhausted
loop
if list.item.getkey = key then
if list.item.getvalue = val then
flag := 1
end
end
list.forth
end
if flag = 1 then
Result := true
else
Result := false
end
ensure
--???
end
The assignment is to implement a map adt via linked list. The 'put' function inserts item(key, value) into the list. The 'has' function checks whether the list contains (key value) pair.
Any help will be greatly appreciated.
It could be just
Result = across list as c some (c.item.key = key and c.item.value = value) end
But then there are several other comments on the code:
I do not see where the property key /= Void is used. So it looks like it is not required.
Given that the code of put inserts elements of type ITEM, the postcondition of put should also use across list ... end instead of list.has (key, value). So I suspect it should be just has (key, value) without list. in front of it.
I do not see any point of using an auxiliary variable flag. The reserved variable Result will do just fine.
All variables in Eiffel are initialized by the default values, so there is no need to assign 0 to flag (or false to Result in a simplified version) at the beginning of a routine.
Usually there is no need to have dedicated getters in Eiffel, so normally the code list.item.getkey looks like list.item.key.
One can preemptively exit from the loop by calling list.finish that moves cursor to the last item of the list when a required element is found. Then after list.forth the loop exit condition is satisfied and the loop terminates.

Returning the maximum value in an array

I have written the following 'matlab' code that is supposed to return the maximum value in an array:
function m = maxi(a)
maximum = a(1,1);
[m,n]=size(a);
for i=1:m
for j=1:n
if a(i,j)>=maximum
maximum = a(i,j)
else
maximum = maximum;
end
end
end
m = maximum;
end
The case here is that the returned result seems to be the maximum number in each iteration. How can I return only one value, which is the maximum value?
Thanks.
To find the maximum value in an array, it is advisable to use the built-in function max. Note that max operates along the first dimension of the array by default; to find the overall max, you may therefore want to pass your array as a vector:
overallMax = max(array(:));
Really, it's not recommended to re-implement built-ins if performance is at all important. However, for educational purposes, it can be useful to reverse-engineer code.
Your function runs fine for me, though I would suggest that you iterate over linear indices (similar to how you transform the array to a vector above). This way it will work for an array of arbitrary dimensionality.
function mx = maxi(a)
mx = a(1);
for ii = 1:numel(a)
if a(ii) > mx
mx = a(ii);
end
end

Resources