Cartesian Product of Lists Using Ada - ada

I am currently working on programming this (https://rosettacode.org/wiki/Cartesian_product_of_two_or_more_lists) in Ada, I am trying to do a Cartesian product between different sets. I need help figuring it out, the main issue is how would I be able to declare empty Pairs and calculate that if it's empty, then the result should be empty. Thank you!
Numbers I am trying to use:
{1, 2} × {3, 4}
{3, 4} × {1, 2}
{1, 2} × {}
{} × {1, 2}
My code:
with Ada.Text_IO; use Ada.Text_IO; -- Basically importing the functions that will be used to print out the results.
procedure Hello is -- Procedure is where variables & functions are declared!
type T_Pair is array(1..2) of Integer; -- Declare a type of array that contains a set of 2 numbers (Used for final result!).
type T_Result is array(1..4) of T_Pair; -- Declare a type of array that contains a set of T_Pair(s), used to hold the result.
Demo1 : T_Result;
Demo1A : T_Pair := (1, 2);
Demo1B : T_Pair := (3, 4);
function Fun_CartProd(p1: T_Pair; p2: T_Pair) return T_Result is
results: T_Result;
i: integer := 1;
begin
for j in 1..2 loop
for h in 1..2 loop
results(i) := (p1(j), p2(h));
i := i + 1;
end loop;
end loop;
return results;
end Fun_CartProd;
begin -- This is where the statements go
Demo1 := Fun_CartProd(Demo1A, Demo1B);
for K in 1 .. Demo1'length loop
Put(" [");
for B in 1 .. Demo1(K)'length loop
Put(Integer'Image(Demo1(K)(B)));
if Demo1(K)'length /= B then
Put(",");
end if;
end loop;
Put("]");
if Demo1'length /= K then
Put(",");
end if;
end loop;
Put_Line(""); -- Create a new line.
end Hello;

Since each set of integers can be any length, including empty, I would start with a type that can handle all those situations:
type Integer_Set is array(Positive range <>) of Integer; -- Input type
type Integer_Tuple is array(Positive range <>_ of Integer; -- Output type
and you can represent the empty sets and tuples this way:
Empty_Set : constant Integer_Set(1..0) := (others => <>);
Empty_Tuple : constant Integer_Tuple(1..0) := (others => <>);
The other problem isn't just how many elements are in each set, but how many sets you will be finding the product of. For this I would recommend some kind of container. An array won't work here because each of the individual sets can have different sizes (including empty), but Ada has a variety of "indefinite" containers that can handle that. Here is an example using vectors:
package Set_Vectors is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive,
Element_Type => Integer_Set);
package Tuple_Vectors is new Ada.Containers.Indefinite_Vectors
(Index_Type => Positive,
Element_Type => Integer_Tuple);
and you can then represent an empty result as:
Empty_Tuple_Vector : constant Tuple_Vectors.Vector := Tupler_Vectors.Empty_Vector;
Now you can create a function that takes in a vector of sets and returns a Cartesian product which will also be a vector of sets:
function Cartesian_Product(Inputs : Set_Vectors.Vector) return Tuple_Vectors.Vector;
If one of the input sets is empty, you return an Empty_Tuple_Vector. You can check if one of the input sets are empty by checking their Length attribute result. It will be 0 if they are empty. Additionally if the input vector is completely empty, you can decide to either return Empty_Tuple_Vector or raise an exception. For example:
if Inputs'Length = 0 then
return Empty_Tuple_Vector; -- or raise an exception, etc.
end if;
for Set of Inputs loop
if Set'Length = 0 then
return Empty_Tuple_Vector;
end if;
-- Maybe do other stuff here if you need
end loop;
Note that the logic you presented assumes only pairs of inputs. I don't have enough experience to convert your logic to account for variable inputs, but perhaps someone can comment on that if you need it.
Also note as Flyx commented, this does not semantically check if a set is a set or not on the inputs (I.E. no duplicate values).

Related

Solving sudoku in Ada

This is mostly solved now thank you
procedure Sudoku is
-- Set Array Types
type arr is array(1..9,1..9) of integer;
type solutions is array(integer range <>)of integer;
-- Declare Variable Types
infp : File_Type;
fileName : string(1..50);
fromFile : string(1..9);
last: natural;
num : arr;
j : integer;
--
--Function to check if board is full
--
function isTrue(board : arr) return boolean is
--Variable Declaration
numCheck : integer;
begin
for x in 1..9 loop
for y in 1..9 loop
if board(x,y) /= 0 then
numCheck := board(x,y);
for k in 1..9 loop
if numCheck = board(x,k) and k /= y then
put_line("Unsolvable Puzzle");
return false;
end if;
if numCheck = board(k,y) and k /= x then
put(x);
put(y);
put_line("Unsolvable Puzzle");
return false;
end if;
end loop;
end if;
end loop;
end loop;
return true;
end isTrue;
A procedure looks like
procedure Proc (params) is
{declarations}
begin
{statements}
end Proc;
which is a pattern you use without problem in the nested procedures; but it applies just the same to the outer sudoku procedures. Note that {declarations} can include nested subprograms.
At line 43 you end the first sudoku, which began at line 5, without any
begin
{statements}
and at line 44 you start a second sudoku, which you end at line 124, again without any
begin
{statements}
So that makes two outer-level procedures in the same file, which is something that GNAT does not support out of the box.
In any case, I think you probably only want one sudoku procedure, so you need to merge the two declarative regions and write a body that calls the nested procedures as appropriate (something I can’t help you with).

Ada - Subprogram determining the biggest number

The task is simple :
Create a subprogram of type function that receives exactly two parameters, both floats and returns the value of the number that is the greatest.
The execution should go as following:
Type in two floats: -13.12 2
-- User types in two numbers marked in bold
The greatest value was : 2.00
This is my code:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
procedure Test is
function Value(Float_1, Float_2 : in Float) return Float is
begin
if Float_1 > Float_2 then
return Float_1;
elsif Float_2 > Float_1 then
return Float_2;
end if;
end Value;
Float_1, Float_2 : Float;
begin
Put("Type in two numbers: ");
Get(Float_1);
Get(Float_2);
Put("The greatest value was: ");
if Float_1 > Float_2 then
Put(Float_1, Fore => 0, Aft => 2, Exp => 0);
elsif Float_2 > Float_1 then
Put(Float_2, Fore => 0, Aft => 2, Exp => 0);
end if;
end Test;
Although it works, I feel like I've overcomplicated it and haven't executed it well. For instance I haven't even used my subprogram Value at all in my main program, which I should do.
Any help is greatly appreciated!
Another approach uses a conditional expression:
function Max_Value (Float_1, Float_2 : in float) return float is
(if Float_1 > Float_2 then Float_1 else Float_2);
The conditional expression does the same thing as you were attempting while eliminating the need to return from the function in two different places.
Note that the logic simply returns Float_1 if it is greater than Float_2, otherwise it returns Float_2. Obviously, returning Float_2 when the two values are equal is a valid consequence of this logic.
Perhaps a better name for Value is Max_Value. The conditional within it is also not exhaustive. If the two numbers are equal, there is no return value. This can be corrected by using >= instead of >, at which point the only other option is that Float_2 is greater.
function Max_Value(Float_1, Float_2 : in Float) return Float is
begin
if Float_1 >= Float_2 then
return Float_1;
else
return Float_2;
end if;
end Max_Value;
Alternatively, as suggested by others, the attribute 'Max on Float can accomplish this much more concisely.
function Max_Value(Float_1, Float_2 : in Float) return Float is
begin
return Float'Max(Float_1, Float_2);
end Max_Value;
Or even more concisely:
function Max_Value(Float_1, Float_2 : in Float) return Float renames Float'Max;
Having the ability to pick the larger of two Floats using Max_Value there's now no need to have a conditional later on.
Put(Max_Value(Float_1, Float_2), Fore => 0, Aft => 2, Exp => 0);
As others have mentioned, Ada already provides this functionality. Thus, the most concise implementation would be
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
procedure Test is
function Max_Value (Left, Right : Float) return Float renames Float'Max;
begin
Put ("Type in two numbers: ");
Get (Float_1);
Get (Float_2);
Put ("The greatest value was: ");
Put (Max_Value (Float_1, Float_2));
end Test;
What you do here is declare a function Max_Value that renames the existing Float'Max function. Other answers have shown you how to implement the logic yourself.

Why my loop invariant might not be preserved by any iteration?

I'm trying to write a code in Spark that computes the value of the polynomial using the Horner method. The variable Result is calculated by Horner, and the variable Z is calculated in the classical way. I've done a lot of different tests and my loop invariant is always true. However, I get the message:
loop invariant might not be preserved by an arbitrary iteration
Are there any cases where the loop invariant doesn't work or do you need to add some more conditions to the invariant?
Here's my main func which call my Horner function:
with Ada.Integer_Text_IO;
use Ada.Integer_Text_IO;
with Poly;
use Poly;
procedure Main is
X : Integer;
A : Vector (0 .. 2);
begin
X := 2;
A := (5, 10, 15);
Put(Horner(X, A));
end Main;
And Horner function:
package body Poly with SPARK_Mode is
function Horner (X : Integer; A : Vector)
return Integer
is
Result : Integer := 0;
Z : Integer := 0;
begin
for i in reverse A'Range loop
pragma Loop_Invariant (Z=Result*(X**(i+1)));
Result := Result*X + A(i);
Z := Z + A(i)*X**(i);
end loop;
pragma Assert (Result = Z);
return Result;
end Horner;
end Poly;
How is Vector defined? Is it something like
type Vector is array(Integer range <>) of Float;
In this case maybe the condition could fail if some indexes of A are negative. Also, does the invariant hold even if the first index of A is not zero? Maybe another case when the invariant fails is when A'Last = Integer'Last; in this case the i+1 would overflow.
Usually SPARK gives a reason, a counterexample, when it is not able to prove something. I would suggest you to check that, it can give you an idea of when the invariant fails. Keep in mind that the counterexamples are sometimes some very extreme case such as A'Last = Integer'Last. If this is the case you need to tell SPARK that A'Last = Integer'Last will never happen, maybe by defining a specific subtype for Vector index or by adding a contract to your function.

Ada constraint error: Discriminant check failed. What does this mean?

I've tried searching the docs and the code, but I'm unable to find what this is and therefore how to correct it.
Scenario:
I'm using the Ada SPARK vectors library and I have the following code:
package MyPackage
with SPARK_Mode => On
is
package New_Vectors is new Formal_Vectors (Index_Type => test, Element_Type => My_Element.Object);
type Object is private;
private
type Object is
record
Data : New_Vectors.Vector (Block_Vectors.Last_Count);
Identifier : Identifier_Range;
end record;
I get the error when the code calls:
function Make (Identifier : Identifier_Range) return Object is
begin
return (
Data => New_Vectors.Empty_Vector,
Identifier => Identifier);
end Make;
Pointing to Empty_Vector. The difficulty is that Empty_Vector defines the Capacity as 0 which appears to be leading to the problem. Now I'm not sure then how to deal with that as Capacity seems to be in the type definition (having looked in a-cofove.ads).
So basically I'm stuck as to how to resolve this; or quite how to spot this happening in future.
Your analysis is correct. The error occurs because you attempt to assign an empty vector (i.e. a vector with capacity 0) to a vector with capacity Block_Vectors.Last_Count (which appears to be non-zero).
You actually do not need to initialize the vector explicitly in order to use it. A default initialization (using <>, see, for example, here) suffices as shown in de example below.
However, in order to prove the absence of runtime errors, you do need to explicitly clear the vector using Clear. The Empty_Vector function can then be used to in assertions that check if a vector is empty or not as shown in the example below. The example can be shown to be free of runtime errors using gnatprove. For example by opening the prove settings via menu SPARK > Prove in GNAT Studio, selecting "Report checks moved" in the "General" section (top left) and then running the analysis by selecting "Execute" (bottom right).
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Formal_Vectors;
procedure Main with SPARK_Mode is
package My_Vectors is new Ada.Containers.Formal_Vectors
(Index_Type => Natural,
Element_Type => Integer);
use My_Vectors;
type Object is record
Data : Vector (Capacity => 10); -- Max. # of elements: 10
Value : Integer;
end record;
-- Initialize with default value (i.e. <>), no explicit initialization needed.
Obj : Object :=
(Data => <>,
Value => 42);
begin
-- Clear the vector, required for the assertions to be proven.
Clear (Obj.Data);
-- Assert that the vector is not empty.
pragma Assert (Obj.Data = Empty_Vector);
-- Populate the vector with some elements.
Append (Obj.Data, 4);
Append (Obj.Data, 5);
Append (Obj.Data, 6);
-- Assert that the vector is populated.
pragma Assert (Obj.Data /= Empty_Vector);
-- Show the contents of Obj.Data.
Put_Line ("Contents of Obj.Data:");
for I in Natural range 0 .. Natural (Length (Obj.Data)) - 1 loop
Put_Line ("[" & I'Image & "]" & Element (Obj.Data, I)'Image);
end loop;
New_Line;
-- or, alternatively using an iterator ...
declare
I : Extended_Index := Iter_First (Obj.Data);
begin
while Iter_Has_Element (Obj.Data, I) loop
Put_Line ("[" & I'Image & "]" & Element (Obj.Data, I)'Image);
I := Iter_Next (Obj.Data, I);
end loop;
end;
New_Line;
-- Show the contents of Obj.Value.
Put_Line ("Contents of Obj.Value:");
Put_Line (Obj.Value'Image);
New_Line;
end Main;
output
Contents of Obj.Data:
[ 0] 4
[ 1] 5
[ 2] 6
[ 0] 4
[ 1] 5
[ 2] 6
Contents of Obj.Value:
42

Return a fat/thick pointer as an out parameter

I am having trouble creating a thick pointer. My current set of declarations look like this:
type Index_Typ is mod 20; -- will be larger in real life
type Data_Buffer_Typ is array (Index_Typ range <>) of Integer; --unconstrained array type
type Data_Buffer_Ptr is access all Data_Buffer_Typ; -- a thick pointer, contains the bounds of array subtype pointed to and address..
Data_Buffer : aliased Data_Buffer_Typ (Index_Typ) := (others => 0); -- this is private
type Result_Typ is (Ok, Overflow, Null_Pointer);
procedure Retrieve (Index : in Index_Typ;
Len : in Index_Typ;
Data_Ptr : out Data_Buffer_Ptr;
Result : out Result_Typ) is
begin
-- assuming range checks are ok, what goes here ?
end Retrieve;
so if i declare:
Ptr : Data_Buffer_Ptr := null;
and given a call of Retreive (2,3, Ptr,Result); how do i end up with a pointer that points at elements 2,3 & 4 of Data_Buffer ?
Notes:
Yes i know passing out an array slice will probably be done as a
pointer anyway, but we want to explicitly use pointers, not
implicitly (and not my choice!).
Yes i have experimented, i usually get : (object subtype must statically match designated subtype) error message..
Where possible use of new to be avoided.
This works for me, though I have to say it's repulsive! Note the order of the components in Fat_Pointer, which is the opposite to what I started with, and the size of the record on this 64-bit machine (I put the rep clause in to have make the order explicit, it works fine without). Also, I think you're stuck with the new.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Conversion;
with System;
procedure Fat is
type Index_Typ is mod 20;
type Data_Buffer_Typ is array (Index_Typ range <>) of Integer;
type Data_Buffer_Ptr is access all Data_Buffer_Typ;
Data_Buffer : aliased Data_Buffer_Typ (Index_Typ) := (others => 0);
type Result_Typ is (Ok, Overflow, Null_Pointer);
procedure Retrieve (Index : in Index_Typ;
Len : in Index_Typ;
Data_Ptr : out Data_Buffer_Ptr;
Result : out Result_Typ)
is
type Bound is (Lower, Upper);
type Bounds is array (Bound) of Index_Typ;
type Bounds_P is access Bounds;
type Fat_Pointer is record
The_Data : System.Address;
The_Bounds : Bounds_P;
end record;
for Fat_Pointer use record
The_Data at 0 range 0 .. 63;
The_Bounds at 8 range 0 .. 63;
end record;
function To_Data_Buffer_Ptr
is new Ada.Unchecked_Conversion (Fat_Pointer, Data_Buffer_Ptr);
Answer : constant Fat_Pointer
:= (The_Bounds => new Bounds'(Lower => Index,
Upper => Index + Len - 1),
The_Data => Data_Buffer (Index)'Address);
begin
Result := Ok;
Data_Ptr := To_Data_Buffer_Ptr (Answer);
end Retrieve;
Ptr : Data_Buffer_Ptr := null;
Result : Result_Typ;
begin
for J in Data_Buffer'Range loop
Data_Buffer (J) := Integer (J);
end loop;
Retrieve (2, 3, Ptr, Result);
for J in Ptr'Range loop
Put_Line (J'Img & " => " & Ptr (J)'Img);
end loop;
end Fat;

Resources