3

I'm trying to create a package of generic adjacency matrices to define graphs, and the first goal is to define a static version based on two-dimensional array:

with Ada.Containers.Vectors; generic type Weight_Type is private; with function "=" (Left, Right : Weight_Type) return Boolean; No_Edge_Value : Weight_Type; package Generic_Adjacency_Matrices is type Static_Adjacency_Matrix is array (Positive range <>, Positive range <>) of Weight_Type; function Create (Vertices : Positive) return Static_Adjacency_Matrix; end Generic_Adjacency_Matrices; 
package body Generic_Adjacency_Matrices is function Create (Vertices : Positive) return Static_Adjacency_Matrix is AM : Static_Adjacency_Matrix (1 .. Vertices, 1 .. Vertices); begin for I in AM'Range(1) loop for J in AM'Range(2) loop AM(I, J) := No_Edge_Value; end loop; end loop; return AM; end Create; end Generic_Adjacency_Matrices; 

To make sure that the matrix is square, I've tried using Static_Predicate to assert the range of both dimensions is the same.

Reference manual notes (3.2.4 NOTE 2) "A Static_Predicate, like a constraint, always remains True for all objects of the subtype, except in the case of uninitialized variables and other invalid values. A Dynamic_Predicate, on the other hand, is checked as specified above, but can become False at other times. For example, the predicate of a record subtype is not checked when a subcomponent is modified."

So, in my opinion, it makes more sense to use Static_Predicate, because matrix has fixed constraints determined at declaration.

with Ada.Containers.Vectors; generic type Weight_Type is private; with function "=" (Left, Right : Weight_Type) return Boolean; No_Edge_Value : Weight_Type; package Generic_Adjacency_Matrices is type Static_Adjacency_Matrix is array (Positive range <>, Positive range <>) of Weight_Type with Static_Predicate => Static_Adjacency_Matrix'First(1) = Static_Adjacency_Matrix'First(2) and Static_Adjacency_Matrix'Last(1) = Static_Adjacency_Matrix'Last(2); function Create (Vertices : Positive) return Static_Adjacency_Matrix; end Generic_Adjacency_Matrices; 

Unfortunately, it's illegal in Ada: Static_Predicate can't be defined with 'Range, 'First, and 'Last.

Although, Dynamic_Predicate can be defined in such a way, I'd like to know other, better suited approaches.

For a example, the type Adjacency_Matrix can be declared private so the function Create, which produces square matrices, is mandatory to use. I don't like this approach, because I don't see why this type should be private at all, and it requires me to define access procedures.

0

2 Answers 2

4

You could use a record, like this:

generic type Weight_Type is private; with function "=" (Left, Right : Weight_Type) return Boolean; No_Edge_Value : Weight_Type; package Generic_Adjacency_Matrices is type Internal_Matrix is array (Positive range <>, Positive range <>) of Weight_Type; type Static_Adjacency_Matrix (Size : Positive) is record Data : Internal_Matrix (1 .. Size, 1 .. Size); end record; function Create (Vertices : Positive) return Static_Adjacency_Matrix; end Generic_Adjacency_Matrices; package body Generic_Adjacency_Matrices is function Create (Vertices : Positive) return Static_Adjacency_Matrix is AM : Static_Adjacency_Matrix (Vertices); begin for I in 1 .. AM.Size loop for J in 1 .. AM.Size loop AM.Data (I, J) := No_Edge_Value; end loop; end loop; return AM; end Create; end Generic_Adjacency_Matrices; 
Sign up to request clarification or add additional context in comments.

2 Comments

Since it is a specialized square matrix type, you can profit from the record to add some extra information, like statistics, validity (unkown, valid, invalid), etc.
I suppose it's not possible to describe it in a way I imagined with Ada, which is fine. I'm going to vote for your answer, because it resembles more what I'm going to do. Thank you for your answer!
2
generic type Index_T is (<>); type Element_Type is private; package Square_Matrix is type Matrix_T is array (Index_T, Index_T) of Element_Type; end Square_Matrix; 

Create a generic package parameter specifying an index type. Use that index type to specify the range of values for each array dimension. A test of this package is:

with Square_Matrix; with Ada.Text_IO; use Ada.Text_IO; procedure Main is type Indx_T is range 1 .. 10; package int_matrix is new Square_Matrix(Index_T => Indx_T, Element_Type => Positive); Mat : int_matrix.Matrix := (Others => (Others => 5)); begin Put_Line ("Dimension 1 Length: " & Mat'Length(1)'Image); Put_Line ("Dimension 2 Length: " & Mat'Length(2)'Image); for I in Mat'Range(1) loop for J in Mat'Range(2) loop Put(Mat(I,J)'Image); end loop; New_Line; end loop; end main; 
The output of this test is Dimension 1 Length: 10 Dimension 2 Length: 10 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 

4 Comments

That's an interesting approach, but it requires instantiating for every different size of a matrix. What about subprograms that rely no matrix type, they'll have to be instantiated too, won't they?
If you are using a consistent set of subprograms for your matrix you can declare those subprograms in the same generic package with the type. This solution allows you to create instantiations for different sizes and for arrays of different kinds of elements. Ada's array attributes allow the programmer to iterate through any size array using the 'Range attribute. In this case the first index range is 'Range(1) and the second is 'Range(2). No adjustments to the algorithm are needed due to a change in the number of elements in the ranges. See the example main program.
The Ada Reference Manual section 6.3.1 provides a package named Ada.Numerics.Generic_Real_Arrays, which provides subprograms for vector and matrix types. You can wrap an instantiation of that generic package inside your own generic package to create a subtype of Real_Matrix which is constrained to be a square matrix.
I'm going to vote for Zerte's answer, because it better resembles what I'm going to do in my program. Nevertheless, thank you for answering!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.