it's me again.
So i have a problem with concurrency in Ada. Basically part of my program looks like that:
for i in 1..it loop
for x in 1..A loop
for y in 1..B
--tab(x,y):=...
end loop;
end loop;
for x in 1..A loop
for y in 1..B
--tab(x,y):=...
end loop;
end loop;
end loop;
Inside this loops are some calculations. What i intend to do is to make these two 'inside' loops work concurrently. Either one element from loop 1, then one element element from loop 2 or little less 'symmetric'. But generally i want it to look like that: first iteration, two 'inside' loops work concurrently, all operations finish, iteration finishes. Second iteration same and so on.. My questions is: can i do it with ENTRY and ACCEPT statements? Or will this require something more? If You could just point me the right solution, because i've seen many examples but none suiting my issue.
If the two inner loops really don't share any data, you can do it loke this:
task First;
task Second;
task body First is
...
begin
for i in 1 .. it loop
for x in 1 .. A loop
for y in 1 .. B loop
...
end loop;
end loop;
end loop;
end First;
task body Second is
...
begin
for i in 1 .. it loop
for x in 1 .. A loop
for y in 1 .. B loop
...
end loop;
end loop;
end loop;
end Second;
You may want to limit the amount of tasks to the amount of cores supported by the system. See this example on calculating pi:
https://github.com/AdaDoom3/OldStuff/blob/master/time_pi.adb
Related
I have:
h(t):=piecewise(0<=t<2,2-t,2<=t<=3,2t-4)
Then I use:
plot(h(t),t=0..6,y=-1..3,scaling=constrained)
My intention was to create a period of 2 by making a larger interval. This didn't solved my problem.
How would I be able to create two periods in the plot?
Hopefully I've understood the goal.
restart;
h:=t->piecewise(0<=t and t<2,2-t,2<=t and t<=3,2*t-4):
H:=proc(t,p::realcons)
local P,T;
if not t::realcons then
return 'procname'(args);
end if;
P:=evalf(p);
T:=frem(t-P/2,P)+P/2;
h(T);
end proc:
plot(H(t,3), t=0..6, y=-1..3);
plot(H(t,3), t=-12..12, y=-1..3);
Foreword
The Fortran program that I'm writing should deal with 1D, 2D and 3D problems depending on ndims, which can be 1, 2 or 3 and is read from an input file.
In these cases the quantity/ies of interest can be stored in arrays (one could be named phi)
of rank dims (ALLOCATABLE(:) or ALLOCATABLE(:,:) or ALLOCATABLE(:,:,:)),
or in arrays of rank 3 (ALLOCATABLE(:,:,:) with third dimension to be set equal to 1 in 2D or both second and third dimensions equal to 1 in 1D);
both cases are explained well in this answer. The first approach seems more elegant to me, but in the following I assume the second one, which is definitely simpler.
These quantities have to be operated on by several subroutines (e.g. mysub) along the ndims dimensions (along "pencils" should give a graphic idea), so I should call something like
SELECT CASE (ndims)
! 3D case
CASE (3)
DO j = ...
DO k = ...
CALL mysub(phi(:,j,k))
END DO
END DO
DO i = ...
DO k = ...
CALL mysub(phi(i,:,k))
END DO
END DO
DO i = ...
DO j = ...
CALL mysub(phi(i,j,:))
END DO
END DO
! 2D case
CASE (2)
DO j = ...
DO k = ...
CALL mysub(phi(:,j,1))
END DO
END DO
DO i = ...
DO k = ...
CALL mysub(phi(i,:,1))
END DO
END DO
! 1D case
CASE (1)
DO j = ...
DO k = ...
CALL mysub(phi(:,1,1))
END DO
END DO
END SELECT
Actual question
Can anyone suggest me (or help me to to devise!) a different way of store phi (maybe involving derived data types?) so that I can collapse the preceding code as follows?
DO id = 1, ndims
CALL mysub2(phi,id)
END DO
(Here mysub2 acts on mysub's place.)
So the question is how should I store phi, so that I can substitute the first code with the second one?
Maybe I could return to the foreword and decide to follow the point 1., in which case would be easier to write a generic interface. This would be, I think, just a way to "hide" exactly what the SELECT CASE would do. Which of the two (SELECT CASE/generic INTERFACE) would be more efficient?
Are these the only two ways to face this problem?
Perhaps I have misunderstood, but I think the answer to the specific question is to not make any changes to the storage or declaration of phi at all.
In the original code, three dimensional data (differentiating rank of the data from rank of the array used to store the data) is processed in slices along the first dimension, then the second, then the third. Two dimensional data is processed along the first, then the second, and one dimensional data is processed along the first only.
So with id going from 1 to the number of dimensions in the data, consider the following implementation of mysub2:
SUBROUTINE mysub2(phi, id)
TYPE(pink_elephant), INTENT(IN) :: phi(:,:,:)
INTEGER, INTENT(IN) :: id
INTEGER :: i, j, k
SELECT CASE (id)
CASE (1)
DO j = ...
DO k = ...
CALL mysub(phi(:,j,k))
END DO
END DO
CASE (2)
DO i = ...
DO k = ...
CALL mysub(phi(i,:,k))
END DO
END DO
CASE (3)
DO i = ...
DO j = ...
CALL mysub(phi(i,j,:))
END DO
END DO
END SELECT
END SUBROUTINE mysub2
~~
Generic interfaces can always be resolved at "compile time" - the specific procedure (not type bound) or binding (type bound) that will be invoked by a particular CALL statement or function reference can be determined just from looking at the declarations in the code.
If you have a situation where "runtime" information is going to affect the choice of procedure, then there has to be some other executable mechanism, other than or additional to the resolution of a generic, that comes into play - if statement, select case, dynamic dispatch, etc, etc, etc.
Asking whether generic resolution is more efficient than a executable decision is therefore not particularly meaningful - they are different things.
You probably want something like this:
program test
integer :: j,ndims
integer :: n ! rank of each dimension, could also be read from input an allocated separately
type arr
real(8) :: x(n) ! one array for each dimension
end type
type(arr),allocatable :: phi
read(*,*) ndims
allocate(phi(ndims))
do j=1,ndims
call mysub(phi(j)%x) ! acts on the array in dimension j
end do
contains
subroutine mysub(x)
...
end subroutine
end program
I've taken an Algorithm course in which the instructor has decided to use Ada as programming language tool to test our understanding. The argument was that ADA language is quite close to the Pseudo code that appears in CLRS book.
Below code is a snip for Selection sort in ADA:
procedure Selection_Sort(Data : in out List) is
begin
for Destination_Index in Data'Range loop
for Source_Index in Destination_Index + 1 .. Data'Last loop
if Data(Source_Index) < Data(Destination_Index) then
Swap(Data, Source_Index, Destination_Index);
end if;
end loop;
end loop;
end Selection_Sort;
The following:
for Source_Index in Destination_Index + 1 .. Data'Last loop
will cause traversing the array from given element (Data1) to last element, however if I wish to traverse from the last element to the first, the following don't seem to work.
for Source_Index in Data'Last .. Data'First loop
It would be great help if someone can help me with this trivial problem, so that I can get on with the main problem at hand, which is learning Algorithms.
A range A .. B having A > B results in an empty range. In respect to the for cycle, there's the reverse keyword to define a descending loop (end of ARM 5.5 (9)). Hence reverse A .. B, where A < B, will result in looping from B down to A.
The rest is left up to you for the sake of learning. In order to learn something, you cannot avoid learning at the first place.
Given a very simple SPARK function that sums an array of integers:
function Add (X, Y : in Ints) return Ints is
Sum : Ints;
begin
for i in Ints'Range loop
pragma Loop_Invariant (for all j in Ints'First .. i - 1 => Sum(j) = X(j) + Y(j)); -- line 7
Sum(i) := X(i) + Y(i);
end loop;
return Sum; -- line 11
end Add;
(Where type Ints is array (Integer range 0 .. 9) of Integer_32)
Compiling without the loop invariant works fine (because I have a precondition that bounds the elements of X and Y such that overflow cannot occur). However, I need the invariant in order to show some properties of the post condition, but it results in:
7:69: warning: "Sum" may be referenced before it has a value
Phase 2 of 3: analysis and translation to intermediate language ...
7:10: "Sum" is not initialized
11:7: warning: "Sum" might not be initialized
I'm not sure how the concept of "being initialised" is expressed in the proof language so I don't know how to convince gnatprove that no uninitialised reads are occuring.
I can remove the warnings by explicitly setting all the elements of Sum to zero at the start of the function but I'm hoping that there's a better way.
In SPARK, arrays are considered as entire objects, and a component-by-component initialization like you do is not allowed. However, there is a heuristics in gnatprove which allows a simple for-loop over the range of the array, as you do. This is why without a loop invariant, you don't get the warning. This heuristics breaks down with the loop invariant, that's why you get the warning again.
You will have to accept the warning using pragma Warnings, as described here:
https://gcc.gnu.org/onlinedocs/gnat_rm/Pragma-Warnings.html
And to avoid the error you are getting at line 7, you may move the loop invariant after the assignment (and change the range of the quantificaton accordingly).
I am trying to change the value of upper bound in For loop ,but the Loop is running till the upper bound which was defined in the starting.
According to logic loop should go infinite, since value of v_num is always one ahead of i,But loop is executing three time.Please explain
This is the code
DECLARE
v_num number:=3;
BEGIN
FOR i IN 1..v_num LOOP
v_num:=v_num+1;
DBMS_OUTPUT.PUT_LINE(i ||' '||v_num);
END LOOP;
END;
Ouput Coming
1 4
2 5
3 6
This behavior is as specified in the documentation:
FOR-LOOP
...
The range is evaluated when the FOR loop is first entered and is never re-evaluated.
(Oracle Documentation)
Generally, FOR loops would be fixed iterations
For indeterminate looping, use WHILE
This isn't Oracle specific, and why there are separate looping constructs.
While it is generally considered a bad idea to change the loop variable's value, sometimes it seems like the only way to go. However, you might find that loops are optimized, and that might be what is happening here.
There's nothing preventing the language designers from saying "The upper bound of the for loop is evaluated only once". This appears to be the rule that plsql is following here.