Constraint Error running Heapify SiftDown - ada

I am writing this code in Ada for a class where we have to teach ourselves the code. I understand heap sort, but the Ada syntax is really confusing me. I don't understand why I am getting a constraint error in this sort function.
Essentially we have to pass array "A" into this procedure, and it should organize it. I get the constraint error at siftDown(A(Start...A'Last));
Thank you in advance
Procedure sort_3(A : in out array_type) is
procedure swap(Left : in out Integer; Right : in out Integer) is
temp : Integer;
begin
temp := Left;
Left := Right;
Right := Temp;
end swap;
procedure siftDown(A : in out array_type) is
Count : Integer := 1;
root : Integer := Integer'Pos(A'First);
child : Integer := Integer'Pos(A'Last);
last : Integer := Integer'Pos(A'Last);
begin
while root * 2 + 1 <= last loop
child := root * 2 + 1;
if child + 1 <= last and then A(Integer'Val(child)) < A(Integer'Val(child + 1)) then
child := child + 1;
end if;
if A(Integer'Val(root)) < A(Integer'Val(child)) then
swap(A(Integer'Val(root)), A(Integer'Val(child)));
root := child;
else
exit;
end if;
end loop;
end siftDown;
procedure heapify(A : in out array_type) is
Count : Integer := 0;
First_Pos : Integer;
Last_Pos : Integer;
Start : Integer;
begin
First_Pos := A'First;
Last_Pos := A'Last;
Start := Integer'Val((Last_Pos - First_Pos + 1) / 2);
loop
siftDown(A(Start...A'Last));
if Start > Integer'First then
Start := Integer'Pred(Start);
else
exit;
end if;
end loop;
end heapify;
Last_Index : Integer := Integer'Last;
begin
heapify(A);
while Last_Index > Integer'First loop
swap(A(Last_Index), A(A'First));
Last_Index := Integer'Pred(Last_Index);
siftDown(A(A'First..Last_Index));
end loop;
end sort_3;

You have a syntax error in the code - an extra dot in A(Start...A'Last).
The syntax A(Start..A'Last) means a slice, part of array from Start to the last element. The Constraint_Error means that Start not in array bounds. Try to add
Ada.Text_IO.Put_Line (Start'Image);
before that line and you will see Start values and when it became out of the A'Range.

Your code has some references to Integer'First and Integer'Last, which are huge values that have nothing to do with the array A and its values. I'm pretty sure you should use A'First and A'Last instead.
Also a note on style: Using the same identifier, "A", for the parameter of the local (inner, nested) procedures as for the parameter "A" of the containing (outer) procedure, when these arrays can be different, invites confusion and errors. Better to use different identifiers.

Related

Ada - Accessibility check raised within a procedure

I previously asked a question regarding accessibility checks being raised in Ada, which #Brian Drummond was kind enough to awnser. The accessibility check was in a function, now I have a similair problem within a procedure; any guidance as to why this is would be greatly appreciated.
The code I am working on has been taken from here: https://github.com/raph-amiard/ada-synth-lib
The code in main file below is from the the Simple_Sine example which can be found here:
https://github.com/raph-amiard/ada-synth-lib/blob/master/examples/simple_sine.adb
My main file looks like this:
with Write_To_Stdout;
with Command; use Command;
with Effects; use Effects;
with Sound_Gen_Interfaces; use Sound_Gen_Interfaces;
with Utils; use Utils;
procedure main is
pragma Suppress (Accessibility_Check);
BPM : Natural := 15;
Notes : Notes_Array :=
To_Seq_Notes ((C, G, F, G, C, G, F, A, C, G, F, G, C, G, F, G), 400, 4);
function Simple_Synth
(S : access Simple_Sequencer; Tune : Integer := 0; Decay : Integer)
return access Mixer
is
(Create_Mixer
((0 => (Create_Sine (Create_Pitch_Gen (Tune, S)), 0.5)),
Env => Create_ADSR (5, 50, Decay, 0.5, S)));
Volume : Float := 0.9;
Decay : Integer := 800;
Seq : access Simple_Sequencer;
Sine_Gen : access Mixer;
Main : constant access Mixer := Create_Mixer (No_Generators);
begin
for I in -3 .. 1 loop
Seq := Create_Sequencer (16, BPM, 1, Notes);
Sine_Gen := Simple_Synth (Seq, I * 12, Decay);
Main.Add_Generator (Sine_Gen, Volume);
BPM := BPM * 2;
Volume := Volume / 1.8;
Decay := Decay / 2;
end loop;
Write_To_Stdout (Main);
end main;
The error that's raised is this:
raised PROGRAM_ERROR : sound_gen_interfaces.adb:20 accessibility check failed
It is raised during a call to this procedure:
-- Register_Note_Generator --
-----------------------------
procedure Register_Simulation_Listener
(N : access I_Simulation_Listener'Class) is
begin
Simulation_Listeners (Simulation_Listeners_Nb) := N;
Simulation_Listeners_Nb := Simulation_Listeners_Nb + 1;
end Register_Simulation_Listener;
Which is line 20 of the code below:
with Ada.Containers.Vectors;
package body Sound_Gen_Interfaces is
package PA_Vectors
is new Ada.Containers.Vectors (Natural, Params_Scope);
Params_Aggregators : PA_Vectors.Vector;
function Current_FPA return Params_Scope is
(Params_Aggregators.Last_Element);
-----------------------------
-- Register_Note_Generator --
-----------------------------
procedure Register_Simulation_Listener
(N : access I_Simulation_Listener'Class) is
begin
Simulation_Listeners (Simulation_Listeners_Nb) := N;
Simulation_Listeners_Nb := Simulation_Listeners_Nb + 1;
end Register_Simulation_Listener;
---------------
-- Next_Step --
---------------
procedure Next_Steps is
begin
for I in 0 .. Simulation_Listeners_Nb - 1 loop
Simulation_Listeners (I).Next_Step;
end loop;
end Next_Steps;
----------------
-- Base_Reset --
----------------
procedure Base_Reset (Self : in out Generator) is
begin
null;
end Base_Reset;
--------------------
-- Reset_Not_Null --
--------------------
procedure Reset_Not_Null (Self : Generator_Access) is
begin
if Self /= null then
Self.Reset;
end if;
end Reset_Not_Null;
--------------------
-- Reset_Not_Null --
--------------------
procedure Reset_Not_Null (Self : Note_Generator_Access) is
begin
if Self /= null then
Self.Reset;
end if;
end Reset_Not_Null;
--------------------------
-- Compute_Fixed_Params --
--------------------------
procedure Compute_Params (Self : in out Generator) is
procedure Internal (Self : in out Generator'Class);
procedure Internal (Self : in out Generator'Class) is
begin
for C of Self.Children loop
if C /= null then
if C.Is_Param then
Add_To_Current (C);
end if;
Internal (C.all);
end if;
end loop;
end Internal;
begin
Self.Parameters := new Params_Scope_Type;
Enter (Self.Parameters);
Internal (Self);
Leave (Self.Parameters);
end Compute_Params;
-----------
-- Enter --
-----------
procedure Enter (F : Params_Scope) is
begin
Params_Aggregators.Append (F);
end Enter;
-----------
-- Leave --
-----------
procedure Leave (F : Params_Scope) is
begin
pragma Assert (F = Current_FPA);
Params_Aggregators.Delete_Last;
end Leave;
--------------------
-- Add_To_Current --
--------------------
procedure Add_To_Current (G : Generator_Access) is
use Ada.Containers;
begin
if Params_Aggregators.Length > 0 then
Current_FPA.Generators.Append (G);
end if;
end Add_To_Current;
------------------
-- All_Children --
------------------
function All_Children
(Self : in out Generator) return Generator_Array
is
function All_Children_Internal
(G : Generator_Access) return Generator_Array
is
(G.All_Children) with Inline_Always;
function Is_Null (G : Generator_Access) return Boolean
is (G /= null) with Inline_Always;
function Cat_Arrays
is new Generator_Arrays.Id_Flat_Map_Gen (All_Children_Internal);
function Filter_Null is new Generator_Arrays.Filter_Gen (Is_Null);
S : Generator'Class := Self;
use Generator_Arrays;
begin
return Filter_Null (S.Children & Cat_Arrays (Filter_Null (S.Children)));
end All_Children;
----------------
-- Get_Params --
----------------
function Get_Params
(Self : in out Generator) return Generator_Arrays.Array_Type
is
use Generator_Arrays;
function Internal
(G : Generator_Access) return Generator_Arrays.Array_Type
is
(if G.Parameters /= null
then Generator_Arrays.To_Array (G.Parameters.Generators)
else Generator_Arrays.Empty_Array) with Inline_Always;
function Cat_Arrays
is new Generator_Arrays.Id_Flat_Map_Gen (Internal);
begin
return Internal (Self'Unrestricted_Access)
& Cat_Arrays (Self.All_Children);
end Get_Params;
----------------------
-- Set_Scaled_Value --
----------------------
procedure Set_Scaled_Value
(Self : in out Generator'Class; I : Natural; Val : Scaled_Value_T)
is
V : Float :=
(if Self.Get_Scale (I) = Exp
then Exp8_Transfer (Float (Val)) else Float (Val));
Max : constant Float := Self.Get_Max_Value (I);
Min : constant Float := Self.Get_Min_Value (I);
begin
V := V * (Max - Min) + Min;
Self.Set_Value (I, V);
end Set_Scaled_Value;
end Sound_Gen_Interfaces;
Any help as to why this is happening would be greatly appreciated.
Thank you
What you're seeing here is the result of (over-)using anonymous access types (discussed in ARM 3.10.2, informally known as the “Heart of Darkness” amongst the maintainers of Ada).
I don't think there's a simple way around this (aside from using -gnatp, as we found earlier, to suppress all checks; though perhaps you might have luck with
pragma Suppress (Accessibility_Check);
in the units where there's a problem).
I managed to get a build without Program_Errors with a fairly brutal hack, changing the anonymous access I_Simulation_Listener'Class to the named Simulation_Listener_Access throughout and, for example,
function Create_Simple_Command
(On_Period, Off_Period : Sample_Period;
Note : Note_T) return access Simple_Command'Class
is
begin
return N : constant access Simple_Command'Class
:= new Simple_Command'(Note => Note,
Buffer => <>,
On_Period => On_Period,
Off_Period => Off_Period,
Current_P => 0)
do
Register_Simulation_Listener (N);
end return;
end Create_Simple_Command;
to
function Create_Simple_Command
(On_Period, Off_Period : Sample_Period;
Note : Note_T) return access Simple_Command'Class
is
Command : constant Simulation_Listener_Access
:= new Simple_Command'(Note => Note,
Buffer => <>,
On_Period => On_Period,
Off_Period => Off_Period,
Current_P => 0);
begin
Register_Simulation_Listener (Command);
return Simple_Command (Command.all)'Access;
end Create_Simple_Command;
Ideally I'd have thought about having Create_Simple_Command returning a named access type too.
You can see where I got to at Github.

Is it necessary to wrap shared array data in a protected type?

I am aware that it is generally bad practice (and the ARM probably says that this is undefined behavior), but I am attempting to write a fast text parser containing many floating point numbers and it would be very expensive to wrap the loaded text into a protected type given that the data is examined character by character and may have up to a million floats or pass a slice on the stack.
Is it possible in Ada (GNAT) to "safely" divide up an unprotected array for consumption with multiple tasks given that the array is never written and only read?
As in:
Text : array (1..1_000_000) of Character := ...
begin
Task_1.Initialize (Start_Index => 1, End_Index => 10_000);
Task_2.Initialize (Start_Index => 10_001, End_Index => 20_000);
...
Yes. That is safe because there is no race condition associated with reading the data and there is no temporally overlapping write operation.
For example, the following code uses such a technique to perform parallel addition on an array of integers.
package Parallel_Addition is
type Data_Array is array(Integer range <>) of Integer;
type Data_Access is access all Data_Array;
function Sum(Item : in not null Data_Access) return Integer;
end Parallel_Addition;
package body Parallel_Addition is
---------
-- Sum --
---------
function Sum (Item : in not null Data_Access) return Integer is
task type Adder is
entry Set (Min : Integer; Max : Integer);
entry Report (Value : out Integer);
end Adder;
task body Adder is
Total : Integer := 0;
First : Integer;
Last : Integer;
begin
accept Set (Min : Integer; Max : Integer) do
First := Min;
Last := Max;
end Set;
for I in First .. Last loop
Total := Total + Item (I);
end loop;
accept Report (Value : out Integer) do
Value := Total;
end Report;
end Adder;
A1 : Adder;
A2 : Adder;
R1 : Integer;
R2 : Integer;
Mid : constant Integer := (Item'Length / 2) + Item'First;
begin
A1.Set (Min => Item'First, Max => Mid);
A2.Set (Min => Mid + 1, Max => Item'Last);
A1.Report (R1);
A2.Report (R2);
return R1 + R2;
end Sum;
end Parallel_Addition;
with Parallel_Addition; use Parallel_Addition;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
procedure Parallel_Addition_Test is
The_Data : Data_Access := new Data_Array (1 .. Integer'Last / 5);
Start : Time;
Stop : Time;
The_Sum : Integer;
begin
The_Data.all := (others => 1);
Start := Clock;
The_Sum := Sum (The_Data);
Stop := Clock;
Put_Line ("The sum is: " & Integer'Image (The_Sum));
Put_Line
("Addition elapsed time is " &
Duration'Image (Stop - Start) &
" seconds.");
Put_Line
("Time per addition operation is " &
Float'Image(Float(Stop - Start) / Float(The_Data'Length)) &
" seconds.");
end Parallel_Addition_Test;

generating prime numbers in pl/sql

Please tell me the problem in the code. I have written this code and its not working. Tell me the mistakes or if there is any other and easy method to generate prime numbers till 1000.
declare
i number;
prime number;
j number;
begin
for i in 2 .. 1000 loop
prime := 0;
for j in 2 .. i/2 loop
if mod(i,j)=0 then prime := 1
end if;
end loop;
if prime = 0 then dbms_output.put_line(i||'&');
end if;
end loop;
end;
You already have your answer (missing semicolon), but just for fun:
The i variable declared at the top is not used.
In theory j would be more efficient as a pls_integer (as i is implicitly). Possibly even a simple_integer, but then you'd need to restructure the loop to make i a simple_integer as well, and it's barely worth it for the tiny fraction of a second you might gain, if the compiler hasn't already optimised it.
You might as well exit the inner loop at the first match, rather than checking every single number.
prime would be more readable as a Boolean.
On the subject of readability, it is standard practice to align end loop under its opening loop statement.
I'm not seeing the point of appending & to every line of output.
This gives me:
declare
j pls_integer;
prime boolean;
begin
for i in 2 .. 1000 loop
prime := true;
for j in 2 .. i/2 loop
if mod(i,j) = 0 then
prime := false;
exit;
end if;
end loop;
if prime then
dbms_output.put_line(i);
end if;
end loop;
end;
You have missed one semicolon and try to put set server output on then run it
set serveroutput on
declare
i number;
prime number;
j number;
begin
for i in 2 .. 1000 loop
prime := 0;
for j in 2 .. i/2 loop
if mod(i,j)=0 then prime := 1;
end if;
end loop;
if prime = 0 then dbms_output.put_line(i||'&');
end if;
end loop;
end;
/

How do you get the square root in Ada?

So I have been given an assignment to read in a file put the numbers into two matrices, multiply the matrices, and finally put the output into a .txt file.
I have never used Ada before and I figured it would be a good challenge. I am stuck in trying to determine the bounds for the two separate arrays.
This is what I currently have:
currentSpread := I;
g := Ada.Numerics.Generic_Complex_Elementary_Functions.Sqrt(I);
while J < g loop
if(I mod J = 0) THEN
if(currentSpread > ((I/J - J)/2)) THEN
currentSpread := ((I/J - J)/2);
arrayBounds := J;
end if;
end if;
J := J + 1;
end loop;
The problem I am having is with the sqrt function. I want to find the factors for the best bounds of the matrix multiplication and this was the only way that I thought to implement it.
The error I am getting is:
invalid prefix in selected component "Ada.Numerics.Generic_Complex_Elementary_Functions"
Thanks a lot for any help.
--Update
Full Code as requested:
with Ada.Text_IO;use Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Numerics.Generic_Complex_Elementary_Functions;
with Ada.Numerics.Generic_Elementary_Functions;
with Ada.Numerics.Complex_Elementary_Functions;
with Ada.Numerics.Generic_Complex_Types;
procedure Main is
dataFile : File_Type;
resultFile : File_Type;
value : Integer;
I : Integer := 0;
J : Integer;
currentSpread : Integer;
arrayBounds : Integer;
g : Integer;
begin
Ada.Text_IO.Open(File => dataFile, Mode => Ada.Text_IO.In_File, Name =>"C:\Users\Jeffrey\Desktop\data.txt");
while not End_Of_File(dataFile) loop
Ada.Integer_Text_IO.Get(File => dataFile, Item => value);
Ada.Integer_Text_IO.Put(Item => value);
Ada.Text_IO.New_Line;
I := I + 1;
end loop;
Ada.Integer_Text_IO.Put(I);
I := I/2;
J := 1;
currentSpread := I;
g := Ada.Numerics.Generic_Complex_Elementary_Functions.Sqrt(I);
while J < g loop
if(I mod J = 0) THEN
if(currentSpread > ((I/J - J)/2)) THEN
currentSpread := ((I/J - J)/2);
arrayBounds := J;
end if;
end if;
J := J + 1;
end loop;
declare
type newArray is array(Integer range <>, Integer range<>) of Integer;
X : Integer := J;
Y : Integer := I/J;
Arr1 : newArray(1..Y, 1..X);
Arr2 : newArray(1..X, 1..Y);
finAnswer : newArray(1..X, 1..X);
begin
for z in 1 .. X loop
for k in 1 .. Y loop
Ada.Integer_Text_IO.Get(File => dataFile, Item => value);
Arr1(z, k) := value;
end loop;
end loop;
for z in 1 .. Y loop
for k in 1 .. X loop
Ada.Integer_Text_IO.Get(File => dataFile, Item => value);
Arr2(z, k) := value;
end loop;
end loop;
for l in 1 .. X loop
for m in 1 .. Y loop
for n in 1 .. X loop
finAnswer(l, n) := finAnswer(l, n) + Arr1(l, n)* Arr2(n, m);
end loop;
end loop;
end loop;
end;
Ada.Text_IO.Close(File => dataFile);
end Main;
I am using the square root exclusively to figure out the factors of a number nothing else. How I have it set up now is it will go up to the square root and then it will take the smallest spread of the factors. I do not care about rounding errors or anything else if it isn't a perfect square it can round either way.
Thanks.
Generic_Complex_Elementary_Functions is a generic package. It cannot be used directly. That is why the compiler gives you an error on this line:
Ada.Numerics.Generic_Complex_Elementary_Functions.Sqrt(I);
To use it, you have to instantiate the generic Generic_Complex_Types with the floating-point type you want to use, and then instantiate Generic_Complex_Elementary_Functions with an instance of Generic_Complex_Types. Fortunately, you don't have to go through all that if you're willing to use the built-in type Float; the language provides Ada.Numerics.Complex_Elementary_Functions for you, that uses Float as the floating-point type, or Ada.Numerics.Long_Complex_Elementary_Functions that uses Long_Float if your compiler vendors support it.
However, I don't think you want to use Complex anything. That deals with complex numbers, and I doubt that you want to use those. Use Ada.Numerics.Elementary_Functions (or Long_Elementary_Functions), which deal with real numbers.
Finally, even this isn't going to work:
Ada.Numerics.Elementary_Functions.Sqrt(I)
if I is an integer, because the argument type needs to be a Float. You'll have to use a type conversion.
Ada.Numerics.Elementary_Functions.Sqrt(Float(I))

Pascal. Recursive function to count amount of odd numbers in the sequence

I need to write recursive function to count amount of odd numbers in the sequence
Here my initial code:
program OddNumbers;
{$APPTYPE CONSOLE}
uses
SysUtils;
function GetOddNumbersAmount(const x: array of integer; count,i:integer):integer;
begin
if((x[i] <> 0) and (x[i] mod 2=0)) then
begin
count:= count + 1;
GetOddNumbersAmount:=count;
end;
i:=i+1;
GetOddNumbersAmount:=GetOddNumbersAmount(x, count, i);
end;
var X: array[1..10] of integer;
i,amount: integer;
begin
writeln('Enter your sequence:');
for i:=1 to 10 do
read(X[i]);
amount:= GetOddNumbersAmount(X, 0, 1);
writeln('Amount of odd numbers: ', amount);
readln;
readln;
end.
When i type the sequence and press "enter", program closed without any errors and i can't see the result.
Also, i think my function isn't correct.
Can someone help with that code?
UPD:
function GetOddNumbersAmount(const x: array of integer; count,i:integer):integer;
begin
if((x[i] <> 0) and (x[i] mod 2<>0)) then
count:= count + 1;
if(i = 10) then
GetOddNumbersAmount:=count
else
GetOddNumbersAmount:=GetOddNumbersAmount(x, count, i+1);
end;
You don't provide an end of recursion, i.e., you always call your function GetOddNumbersAmount again, and your program never terminates. Thus, you get an array index error (or a stack overflow) and your program crashes.
Please note, that every recursion need a case where it terminates, i.e. does not call itself. In your case, it should return if there are no elements in the array left.
In addition, you are counting the even numbers, not the odd ones.
You passed a static array to a dynamic so the index get confused:
Allocat the array with
SetLength(X,10)
allocates an array of 10 integers, indexed 0 to 9.
Dynamic arrays are always integer-indexed, always starting from 0!
SetLength(X,10)
for it:=0 to 9 do begin
X[it]:= random(100);
And second if you know the length a loop has more advantages:
function GetEvenNumbersAmount(const x: array of integer; count,i:integer):integer;
begin
for i:= 0 to length(X)-1 do
if((x[i] <> 0) and (x[i] mod 2=0)) then begin
inc(count);
//write(inttostr(X[i-1])+ ' ') :debug
end;
result:=count;
end;

Resources