I am new with Ada programming. I am trying to generate a 80 column and 40 rows table, each case is randomly filled with either M or V. Any help with how to create this kind of table would be much appreciated !
Here's what I have so far for the table in .ads :
package Life is
type Grid is (mort, vivant);
type TableauCell is array ( 0..80, 0..40 ) of Grid;
procedure Grid_Random_Fill(A : in out Grid);
end Life;
and the randomization:
with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Numerics.Discrete_Random ;
use Ada.Text_IO, Ada.Integer_Text_IO;
package body Life is
procedure Grid_Random_Fill is
type Life is (V, M);
package Random_Life is new Ada.Numerics.Discrete_Random (Life) ;
use Random_Life ;
G : Generator ;
begin
Reset (G) ; -- intialise the generator
loop
Case Random(G) is
when V =>
put("V"); -- put V in table
when M =>
put("M"); -- put M in table
end case;
end loop ;
end Grid_Random_Fill;
end life;
Unfortunately I can't get it to compile - and I don't see how I can automatically generate M and V into my table. I'm not sure I was clear, I'm all new to coding.
This sounds homeworkish, so this is going to be kept somewhat abstract.
Declare a two-element type to represent M and V.
Declare an 80x40 array of that type.
Instantiate Ada.Numerics.Discrete_Random with that type.
Iterate over the array bounds, setting each array element via a call to the random number package's Random() function.
Since this has the feel of homework, how about an overly-complex, overly-generalized example?
Everything works, except the randomization, which is an exercise left to the reader.
Test_Table.adb
With
Tabling,
Ada.Streams.Stream_IO,
Ada.Text_IO.Text_Streams;
Use
Ada.Text_IO;
Procedure Test_Table is
-- Here we declare a stream and associate it with the standard-output,
-- this can easily be altered to any file. Yay streams!
Output : Access Ada.Streams.Root_Stream_Type:=
Ada.Text_IO.Text_Streams.Stream( Standard_Output );
Package test is new Tabling( Rows => 40, Cols => 80 );
temp : test.Table;
Begin
-- A single line to write the table.
Test.Table'Write( Output, temp );
New_Line;
End Test_Tables;
Now isn't that nice and simple? Well, here's the over-complex & over-generalized part: the specification and implementation!
Tabling.ads
Pragma Ada_2012;
With Ada.Streams;
Generic
Rows : Positive := 3;
Cols : Positive := 4;
Package Tabling is
-- Tables with rows or columns exceeding 200 are absurd, so we disallow them.
Maximum : constant:= 200;
Pragma Assert (Rows <= Maximum and Cols <= Maximum);
-- Table is a private entity.
Type Table is private;
-- Forward declaring the rows and columns here.
Type Col is private;
Type Row is private;
Private
Use Ada.Streams;
-- We are defining a type with elements of 'V' or 'M'.
Type Element_Type is ( 'M', 'V' );
-- We are declaring a stream writing function.
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Element_Type);
-- We are overriding the default write function with the one we defined.
For Element_Type'Write use Write;
-- Because we don't want an allocation wrror we restrict index-ranges to
-- a more reasonable value.
SubType Short_Positive is Positive Range Positive'First..Maximum;
-- We create subtypes representing the ranges that Rows or Columns take.
subtype column_index is Short_Positive Range Positive'First..Cols;
subtype row_index is Short_Positive Range Positive'First..Rows;
-- Here we define stream-writing functions for rows and columns.
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Col);
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Row);
-- Here we override the stream-writing methods for rows and columns.
For Col'Write Use Write;
For Row'Write Use Write;
-- Here we finally define Rows and Columns.
Type Col is Array(column_index)of Element_Type;
Type Row is Array( row_index ) of Col;
-- THIS IS A STUB, SUBSTITUTED FOR YOUR CALL TO RANDOM.
Function RANDOM_CALL Return Element_Type is ( 'M' );
-- Finally we define the stream-writing for a table...
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Table);
-- and define what a table is...
Type Table is record
Data : Row:= ( others => (others => RANDOM_CALL) );
end record;
-- finishing off by assigning our write function to the type.
For Table'Write Use Write;
End Tabling;
Tabling.adb
package body Tabling is
-- Quick definition of the new-line, windows-style.
New_Line : Constant String:= ASCII.CR & ASCII.LF;
-- Implementations of our stream writing functions.
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Element_Type) is
-- Convert takes the element-type and transforms it into a character.
Function Convert (Input : Element_Type:= Item) Return Character is
begin
-- A simple mapping using case, it also has the advantage of raising
-- a compiler error should the valuse "Element_Type" can take change.
case Input is
when 'M' => return 'm';
when 'V' => return 'v';
end case;
end Convert;
begin
Character'Write( Stream, Convert );
end Write;
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Col) is
begin
-- Using the new-style for-loop, we iterate over the given columns,
-- taking care to wrap the elements in the table's cell-definition tag.
for Element of Item loop
String'Write( Stream, ASCII.HT & "<td>" );
Element_Type'Write( Stream, Element );
String'Write( Stream, "</td>" & New_Line );
end loop;
end Write;
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Row) is
begin
-- Using the new-style loop, we iterate through the row, wrapping each
-- in the table-row tag, <tr>.
for Element of Item loop
String'Write( Stream, "<tr>" & New_Line);
col'Write( Stream, Element );
String'Write( Stream, "</tr>" & New_Line);
end loop;
end Write;
Procedure Write(
Stream : access Root_Stream_Type'Class;
Item : in Table) is
begin
-- Start the table.
String'Write(Stream, "<Table>" & New_Line);
-- Write out the rows.
Row'Write (Stream, Item.Data );
-- End the table.
String'Write(Stream, "</Table>");
end Write;
End Tabling;
The procedure body for Grid_Random_Fill needs to agree with the specification, which is:
procedure Grid_Random_Fill(A : in out Grid);
The body does not include the parameter A.
The solution will involve two nested loops, over the range of the two dimensions in the array you declared.
And the simple answer :
with Ada.Numerics.Discrete_Random;
with Ada.Text_Io;
procedure Main is
type Cell_T is (M,V);
type Rows_T is new Integer Range 1 .. 40;
type Cols_T is new Integer Range 1 .. 80;
type Grid_T is array (Rows_T,Cols_T) of Cell_T;
package Rand is new Ada.Numerics.Discrete_Random (Cell_T);
G : Rand.Generator;
Grid : constant Grid_T := (others => (others => Rand.Random(G)));
begin
for R in Rows_T'range loop
for C in Cols_T'range loop
Ada.Text_Io.Put (Cell_T'Image (Grid (R,C)));
end loop;
Ada.Text_Io.New_Line;
end loop;
end Main;
Output :
$ ./main
VMMVVMMMVMMMVVVMMMVVVMMVVVMVVVVMMMMVMMMMVVMVMVVMMVMMMVVMMMMVMMVMMVMMMMVMMVVMVVMM
VVVMVVVVMMMMMMVVMVMMVMMMVMMMVVMVVVVVMVVVMVMVVVMVMVVVMVMMMVMVVVMVMMVVVMVVMVVVVVMM
VVMVVVVVVVMVVVVMVVVMVVMMVMVVVMVMMMVMMMVVVMMMVVVMMMMMVVVVMVMVVVVVVVMMVVMVMVMMVVVM
VMMVVMVMVVMVMVVMMVMMVMVVMVMVMMVVMMVVMMVMVVVVVVMVMVMMMMMMVMVVVMMVMMMMVMVVVVMVMVVM
VVVVMMMMMVVMMMMVVMMMVMMMVVMVVVMMMMMMVMVMMVMMVVVMMVMMMMVVMVMVMMMMVMMMVMVVVVMMMVMM
VMMVVMMMMMVVMMMVVVVMMVMMVVVVVVVVVVMVMVMVVVVVVVVMVMVMVVMVMMMMMVMMVVVVVVVVMVVVVVVV
VVMMMMVVVMMVMVMVMVVMMMMMVMVVVVMMVVMVVVMMMMMMMMMMMMMVMMVVMVVMVMMVMMMVVVMMMVVVMVVV
MVMVMMVMVVVMVVVVVVVMMMMVVVMMVVVMVMMVVMVVVMVMVMMMMVVVVMVVMMVMVMVVVMVMMVMMMVVMVVVV
MMVMMVMMMVVVVMVVVVVVVMVVVVMMMVMMMVMVMMMVMVVVMVMMVMVMVMVVMMMVVVVVMVVMVMVMVVMMMVVV
VVMMMMMMMVMVVMVMVVVMVVMVMMMMMVVVVVVVMVMMVVMMMMVVVMVVMVVMVVVVMMVVVVMMMMVMMVMMMMMM
VVVMMMMVMMVVVVVMVVMVVMVMMMMMMVMMMMVVMVVVMVMVVMMVVMMMVVMMMVMVVVVVMMVVVMVVVMMVVMMM
VMVVMMVMVVVMMMVVVVMMMMVVVMVVVVMMMVMVVVVMMMVVVMVVMMVVVMVMMMVMMVVVMVMMMMMMVMVVVMVV
VMVMMMVMMMVMMMMMMVMMMVVMMMMVMMMVVMMVMMMVVMVVVMMMMVMVMVMVVMMVMMMVVMVVMVMMMMVMVMMM
VMVVVMMMMMVMMMMVVVVMMMVVMMVVMVVMVMVVMVVVVMVMMVMMVMMVMVVMVVVVVVMMMMVMVMMMVVVMMVVV
VVMVVMVMVVVMMMMMVVVMVMVVMVMVMMVVVMVVMMVMMVMMVVMVMMMMVMVVMMMVVMVMMMMMMMMVMVMMVVVM
MVVVVVMMVVMMMVMVMVMVMVVMMMVVMMVMVMVVVMVVVVVMMMMVVVMVVMVVMVVVVVVVVMMVMMVVVVVVVVMV
MVMMMMVMMVVVVVMMMVMVVVMVVMVVMVVVVMVVVMVVMVVMMVVVMVMVVMMMVVMMMMVVMMMVMVMMMMVMMMVV
MVVMVMVVMMVMVMMVMVVVMVVVVVVVVVVVVMVMMVVMMVMMMVVVMMVMMMMVVMVMVMVMVMVVVMMMMVMVVVMM
MMVVVVVMVVMVMMVMMVVVVVMVMMMMMVVVVMVMVMMVVVMMMVMVVVMVMMMMVVMMVMVMVVVVMMMVMMMMVVMV
MMMVVMMMVMVVVVVMVMVMMVVVMVVMMVMVVMVVMVMMVMVVVVVVVMMMVVVMVVVVMVVVVVVMMMVVMMMMMMMV
VVMMVMMVMMMMVMVVVMMMMVVMVMVVMVVVMMMVMVMMMMMVMMVVMMMMVMVVMMMVMVMMMMVMMMMVVVMMMVMM
VMVVVMMVVVVVVMVMMMVVVMVMMVVMVVMVVVVVVVVMMMMMVVVMMMMVMVVVMVMVMMVVVMMVMMVMVMMVVVVV
MMVMMMVMVMVMMVVMMMMVMMVMVMMVVMMMVVVMVVVVVVVVMMMVMVVVMMMVMMVMMVMVMVMMMVVMMMMMVMMM
MMVVMMMMMVVMMMMVMVVMVVMVVVVVMVVVMVMMVMMVVMMMVVVMVVVVMVVMMVVMVVMMMVMVMVMVMVMMMMVM
MVMVVVVMMMVVMVVMMVMVVMVMVVVMMVMVMMMVMVMMMMMVMVMVVMMVMMMVMVMVVMMVMMMVVMVVVVVMVMVV
VMVVMMMVMVMMMMMMMMVVVMVMVVVVMVVVVVMVMVVMVMVVVVVMMVVVVVVMMMMMVVMVMVVVVMVMMMMVVVVM
MVMVMVMMMMVMMVVVMMMMMVMMVVMMMMVVVVVVVMMVVVVMMMMMVVMMVVMVVVVVMMMVVVVMVMVVVMMVMMVM
VVVVVMMMMVVMMMMVVMVVVMMVMMVMVVVVVMVVVVVMVMVVMMVVVMVVMMMVMVVVVMMMVVVMVVMVMVMMMMVV
MVVVMVMVMVMMMMMVMVMMVMMVVMVVVVMMVMVVMVVVMVMVMVMMVVVVMMVVMMMVVVMMMMMVVMMMMMVMVVVV
MVMVMMMVVVMVVVVVVMMVMVVVMMVMVMMVMMVMVVVMMMMVMMVMMVMMMMMMVMVVVMVMMVMVMMMVVMMMMVMV
VVMVVMVVMVMVMMMMVMVVVMMMMMVMMMMMMMVVVVVMMMVVVMVMMMMVVVMVMVMVVMMMVMMMMVMMMVMMMVMV
MMMMVMMVVVVMVVMMVMVVMVVVMVMMVVVMVVVMMVVVVVMMMVMVVVMMMMVVMVMMVMVMVMVMMMVMMVVVMMMM
VMMMMVVMMVMVMVVVVVMVVVMVMMMVVMMMVVMVVVMMMMVVVVMVMMVVMMVVVVMMMVMVMVVMVMMVMVMMMMMV
MMMMVMMMMMVMMVMMMVMVVMMVVVMVMMVVMVMVVMVVMMMMMVMVVVMVVMMVVVVMMMMMMMMVMVVVMVVMVMVV
VMMVMMMMMVMVMMMVVVVVMVMVMVMMVMVMVVVVVVVMMMMVVMMVVVMVVVMMMVVVMMVMMVVVMVVVMVMMMVMM
VMVMMVVVMVMMMMVVVMMVMMMVVVVMVMVVVMMVMMVMMVVVMMMMMVVVMVMMMMVVMVVVMVVMMMVMMMVMVVVM
VVVMMMVVMMMMMVMVVVMVVMVVVVVVMMMVVMVVMVVMVMVMVVVMVMMMMVMMMMMVMMMMVVMVVVVVVMVMMVMV
VVVVMVVVMVMMMMMMVVMVVVVVVMMMMMMVVMMMMVMMVMMVMMMVMVVMMMMMVMMMMMMMMVVVMMMMVVMVMVVM
MMVVVMVMVVMVVMVVVMMVVMVMVMMVMMMVMVMMMMMVVVMMMMVMMVMVVVVMVMMMMVVVMMMVVVMMMVMMMMMM
VMMVMMMVMVVMMVVVVMMVMMVVMVMVMMVMMMVMMVVMVVVVMVMVVVVMMMMMMMVVVMVMVMMVVVVMVMVMMMVV
Related
I have a record type(REC) which contains an element of type VECTOR which is an unconstrained 2d array of STD_LOGIC:
package TEST is
type VECTOR is array (NATURAL range <>, NATURAL range <>) of STD_LOGIC;
type REC is record
data : VECTOR;
end record REC;
function con(
a : REC;
b : REC)
return REC;
end package TEST;
When declaring the body of the con function I want to specify the size of the REC.data array like so:
package body TEST is
function con(
a : REC;
b : REC)
return REC is variable r : REC(
data(a.data'length(1) + b.data'length(1) - 1 downto 0, a.data'length(2) - 1 downto 0));
begin
-- . . . do things
end function con;
end package body TEST;
but in the line where I attempt to set the size of data it Vivado throws the following error:
Sliced name is allowed only on single-dimensional arrays
Does this mean I cannot have an unconstrained 2d arraign in a record or is there a different method for defining the size of it in the con function ?
---- EDIT ----
Since I now understand that it is not possible to use 2d arrays in this context what method should I use to create a function which:
Takes two 2d arrays (or arrays of arrays) of size [x][y] and [z][y] as inputs
Outputs an array of size [x+z][y]
With both input arrays being unconstrained and the output array being constrained to size [x+z][y]
And all arrays (input and return) be a record type
user1155120 I don't think I fully understand what you are trying to say. Are you saying my code is not
a minimal reproducible example, because except for me forgetting to include the STD_LOGIC library
the code reproduces the problem when I paste it into Vivado, and it is about as minimal as I can get it.
Or are you saying that the code you linked as this works works for you, because at least in my
Vivado it still throws the same error ? – Mercury 4 hours ago
The original comment was meant for Tricky. There's a missing return statement in the function con which would prevent use in an example.
It isn't clear if record constraints (a -2008 feature) are supported in Vivado Simulator. In Vivado Synthesis Guide UG901 2020.1 we see all sorts of wonderful uses of record types from everything to inferring ram to record elements of record types. Xilinx has been busy.
It'd seems odd if unconstrained elements in record type declarations were supported but not record constraints (they're pretty much a package deal, pun aside). Note the comment called it a -2008 feature.
A record constraint is limited to supply the constraint of an element or subelement that is of an unconstrained type (typically arrays). VHDL has always been capable of supplying multi-dimensional array constraints. The language of the standard is particular based on the flexibility of the syntax.
This code is VHDL -2008 compliant and provides your record constraint:
library ieee; -- ADDED for MCVe
use ieee.std_logic_1164.all; -- ADDED
package TEST is
type VECTOR is array (NATURAL range <>, NATURAL range <>) of STD_LOGIC;
type REC is record
data: VECTOR;
end record REC;
function con (a: REC; b: REC) return REC;
end package TEST;
package body TEST is
function con (a: REC; b: REC) return REC is
variable r:
REC ( -- record constraint:
data (
natural range a.data'length(1) + b.data'length(1) - 1 downto 0,
natural range a.data'length(2) - 1 downto 0
)
);
begin
-- . . . do things
return r; -- ADDED required return statement
end function con;
end package body TEST;
You'll note the changes to the record constraint from yours is the addition of natural range before each range of the element data constraint.
From IEEE Std 1076-2008 5.3.3 Record types:
record_constraint ::=
( record_element_constraint { , record_element_constraint } )
record_element_constraint ::= record_element_simple_name element_constraint
From 6.3 Subtype declarations:
element_constraint ::=
array_constraint
| record_constraint
Here the element data is an array so an array_constraint is appropriate.
From 5.3.2 Array types, 5.3.2.1:
array_constraint ::=
index_constraint [ array_element_constraint ]
| ( open ) [ array_element_constraint ]
Because element data array elements are scalar (enumeration type STD_LOGIC) we follow index_constraint.
index_constraint ::= ( discrete_range { , discrete_range } )
discrete_range ::= discrete_subtype_indication | range
The code shown above uses a discrete subtype indication for the index ranges of the element data dimensions and successfully analyzes (compiles).
From 5.2.2 Scalar types, 5.2.2.1:
range ::=
range_attribute_name
| simple_expression direction simple_expression
direction ::= to | downto
The constraint in the question uses a range with simple expressions and direction.
So why did it produce the error message about multi-dimensional slices?
In 9. Expressions, 9.1 the BNF, simple_expression -> term -> factor -> primary -> name.
In 8. Names, 8.1 name -> slice_name, only multi-dimensional slices are not allowed semantically in 8.5 Slice names who's BNF tells us it's syntactically valid:
slice_name ::= prefix ( discrete_range )
The prefix of a slice shall be appropriate for a one-dimensional array object. The base type of this array type is the type of the slice.
and semantically the prefix data is not appropriate for a one-dimensional array object.
These comments provide bit more context for the problem although it isn't clear which version the record constraint you used in the reported eventual success:
#Mercury when you add a (VHDL) file to Vivado, it's by default set to use VHDL 93, but not 2008. Go
to the property Window and change the file type from VHDL to VHDL 2008. I'm not sure why it
prints the wrong error message in your case. (Vivado likes to confuse users with wrong error messages
...). Anyhow, it should have reported your feature is only supported in 2008 mode. – Paebbels 3 hours
ago
#Paebbels Thank you, that fixed the problem, maybe add it as a sub note to your response so I can
mark it as accepted answer. You just saved me hours of frustration. And I'm already getting familiar with
Vivado's shenanigans, my Favorit one of which is "ERROR close to ..." which has to be one of the most
useless error messages I have experience in a long time :) – Mercury 3 hours ago
As far as detecting -2008 source, there are no -1993 syntax errors and no -2008 new reserved word, delimiters, separators or graphics characters in either the primary unit or the secondary.
That leaves you at the mercy of semantic analysis which failed. You could also note the unconstrained record element wasn't reported during analysis of the package declaration. It occurred during evaluation of the variable r. All declared objects are required to be constrained. VHDL doesn't have a recital of all features, semantics can be restrictive as well. It's legal in places to have unconstrained elements and objects.
Associating semantics rules found in the text of the standard with an textual element of the particular declaration or statement can be tough and the squeaky wheel gets the lubricant. Record constraints are relatively new to VHDL implementations.
The problem appears to have been one of tool familiarity.
This is the definition of row and column merges from PoC's vectors package, see lines starting at 359:
function slm_merge_rows(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
constant ROWS : positive := slm1'length(1) + slm2'length(1);
constant COLUMNS : positive := slm1'length(2);
variable slm : T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
begin
for i in slm1'range(1) loop
for j in slm1'low(2) to slm1'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, j) := slm1(i, j);
end loop;
end loop;
for i in slm2'range(1) loop
for j in slm2'low(2) to slm2'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(slm1'length(1) + i, j) := slm2(i, j);
end loop;
end loop;
return slm;
end function;
function slm_merge_cols(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
constant ROWS : positive := slm1'length(1);
constant COLUMNS : positive := slm1'length(2) + slm2'length(2);
variable slm : T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
begin
for i in slm1'range(1) loop
for j in slm1'low(2) to slm1'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, j) := slm1(i, j);
end loop;
for j in slm2'low(2) to slm2'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, slm1'length(2) + j) := slm2(i, j);
end loop;
end loop;
return slm;
end function;
The definition of T_SLM is:
type T_SLM is array(natural range <>, natural range <>) of std_logic;
Currently, I see no problem in nesting this code in another layer like your unconstrained record.
Edit:
Thie code above requires VHDL 2008 to be enabled in Vivado.
When VHDL files are added to Vivado, it's by default set to use VHDL 93, but not 2008. Go to the property Window and change the file type from VHDL to VHDL 2008``.
The printed error message is misleading and points to a false feature being used. The correct message should be it's a VHDL-2008 feature, please enable it.
Is it possible to group related constants together inside of packages?
What I want to do is to have generic constants but then grouped together with related constants and types. In software like Python this could be done with package inside of package or class to group constants together.
What I want to do is something like this:
library constants;
...
if (some_signal = constants.group_a.SOME_CONSTANT_VALUE) then
...
end if;
Reader can see where the constant is coming from like here group_a.
If I understand the question well you can use records inside your package
package ex_pkg is
type constants_group_1_t is record
CONSTANT1 : integer;
CONSTANT2 : integer;
CONSTANT3 : integer;
CONSTANT4 : integer;
end record constants_group_1_t;
constant constant_group1 : constants_group_1_t := (
CONSTANT1 => 1,
CONSTANT2 => 2,
CONSTANT3 => 3,
CONSTANT4 => 4
);
end package;
then you can use it as
liberary work;
...
if some_integer = work.ex_pkg.constants_group1.CONSTANT1 then
end if;
so basically you declare a new record type containing all the constants that you want to use, which can be any of your chosen types, then creating a constant of the newly created type and assign for each field its value. You can then access it like "record.field" moreover you can define a record of records for as deep abstraction as you want.
I want to loop over an array and check, whether the current array index is a value of an enumeration. The array as well as the enumeration are defined as the following:
type Option is (None, A, B, C, D);
type Votes is array(Option) of Natural;
Zero_Option_Distribution: constant Votes := (others => 0);
Votes_Distribution: Votes := Zero_Option_Distribution;
The Loop looks like this:
for I in Voting_System.Votes_Distribution'Range loop
-- this is where I would like to check whether I is a representation of either of the enum values
end loop;
I already tried everything that came to my mind, like
if I = Voting_System.Option(None) then -- ...
and
if I'Val("None") then -- ...
and some more versions where each of them didn't work.
I really don't have any more ideas to achieve this.
You compare values of objects of enumeration types just like objects of any other type, using =:
if I = None then
...
end if;
-- this is where I would like to check whether I is a representation of either of the enum values
Based on this line in your question, I assume Party is an Integer subtype or something? You should be able to just use something like this:
-- (Checks if I is 0)
if (Integer(I) = Voting_System.Option'Pos(Voting_System.Option.None)) then
-- ...
If Party is a distinct type, in accordance with ARM95 3.5.1 §7 and ARM95 Annex K §175 you may try something like this:
for I in Votes_Distribution'Range loop
case Party'Pos (I) is
when Option'Pos (None) => Put_Line (I'Img & " is for «None»");
when Option'Pos (A) => Put_Line (I'Img & " is for «A»");
when Option'Pos (B) => Put_Line (I'Img & " is for «B»");
when Option'Pos (C) => Put_Line (I'Img & " is for «C»");
when Option'Pos (D) => Put_Line (I'Img & " is for «D»");
when others => Put_Line ("I not in Option");
end case;
end loop;
Need others in all cases because we moved to work with type Universal_Integer.
How would i go about creating a procedure that is a thread which continuously passes automatic random generated data within a specified range.
I currently would have to manually enter in each bit of data in the console using this procedure below. I want to creatre a procedure that when running is able to pass data to this procedure as if it was being typed into the console itself.
procedure Analyse_Data is
Data : Integer;
begin
DT_Put_Line("Data input by user");
loop
DT_Get(Data,"Data must be taken as a whole number");
exit when (Data >=0) and (Data <= Maximum_Data_Possible);
DT_Put("Please input a value between 0 and ");
DT_Put(Maximum_Data_Possible);
DT_Put_Line("");
end loop;
Status_System.Data_Measured := Data_Range(Data);
end Analyse_Data;
I havent included the specification files (.ads)
I am new to Ada and any help would be appreciated.
Use an instance of Discrete_Random to generate some number of random data values in the desired range:
subtype Valid_Range is Natural range 0 .. Maximum_Data_Possible;
package Some_Value is new Ada.Numerics.Discrete_Random(Valid_Range);
G : Some_Value.Generator;
…
procedure Generate is
N : Valid_Range;
begin
for I in 1 .. Count loop
N := Some_Value.Random(G);
Put(N);
end loop;
end;
Save the values to a file:
./generate > test_data.txt
Feed that file to your program using I/O redirection from the command line:
./analyse_data < test_data.txt
The exact details will depend on you actual program. See this related Q&A regarding empty lines in standard input.
I'm sorry to bother you I know this question have been asked quite a lot but never with Ada... I was wondering if there were in the Ada standard library a way to generate a list of unique random numbers (you never pick twice the same number) in O(n)
In a way is there an implementation of the Knuth-Fisher-Yates algorithm in Ada?
There's a discussion of implementing the Fisher–Yates shuffle here. Basically, you need a different range of Discrete_Random in each iteration, as shown here; Float_Random is an alternative, as mentioned in A.5.2(50), Note 16. If bias isn't critical, this example may be sufficient.
In any case, shuffling is O(n), but selecting can be O(1).
Addendum: The complexity of creating the set depends on the implementation. For example, Containers.Hashed_Sets, A.18.8(88/2) and Containers.Ordered_Sets, A.18.9(116/2).
Given that you want:
a) Random numbers from 0 to 1000
and
b) the numbers are not to repeat
according to the link you provided, you could do this rather easily.
Just fill an array with the range of values and perform some number of swaps on randomly chosen elements thereof; this guarantees both requirements are upheld.
I took the liberty of coding it up.
You'll need to With Ada.Numerics.Discrete_Random.
Generic
Low, High : Integer;
Package Initialization is
SubType Element is Integer Range Low..High;
Function Incrementor Return Element;
Type Element_Array is Array(Element) of Element;
Values : Element_Array;
Procedure Print;
End Initialization;
Package Body Initialization is
Count : Element := Element'Last;
Function Incrementor Return Element is
begin
Return Result : Element:= Count do
Null;
Count:= Element'Pred( Result );
Exception
When Constraint_Error => Count:= Element'Last;
End Return;
end Incrementor;
Procedure Swap( Index_1, Index_2 : In Integer ) is
Temp : Constant Element:= Values( Integer(Index_1) );
begin
Values( Integer(Index_1) ):= Values( Integer(Index_2) );
Values( Integer(Index_2) ):= Temp;
end Swap;
Procedure Print is
begin
Put_Line( "Length: " & Values'Length'Img );
Put( "(" );
For Index in Values'First..Integer'Pred(Values'Last) loop
Put( Values(Index)'Img & ',' );
end loop;
Put( Values(Values'Last)'Img );
Put_Line( ")" );
end Print;
Begin
Shuffle:
Declare
Package Random_Element is New
Ada.Numerics.Discrete_Random( Element );
Number : Random_Element.Generator;
Use Random_Element;
Begin
Values:= Element_Array'( Others => Incrementor );
Reset( Number );
For Index in Element'Range loop
Swap( Integer(Index), Integer(Random(Number)) );
end loop;
End Shuffle;
End Initialization;
And you can test it out with something like:
Test:
Declare
Package Q is new
Initialization( Low => 0, High => 1000 );
Begin
Q.Print;
End Test;