NAME

Text::Table::Read::RelationOn::Tiny - Read binary "relation on (over) a set" from a text table.

VERSION

Version v2.0.0

SYNOPSIS

use Text::Table::Read::RelationOn::Tiny;

my $obj = Text::Table::Read::RelationOn::Tiny->new();
my ($matrix, $elems, $ids) = $obj->get('my-table.txt');

DESCRIPTION

Minimum version of perl required to use this module: v5.10.1.

This module implements a class that reads a binary relation on a set (homogeneous relation, see https://en.wikipedia.org/wiki/Binary_relation#Homogeneous_relation) from a text table.

The table format must look like this:

| x\y     | this | that | foo bar |
|---------+------+------+---------+
| this    | X    |      | X       |
|---------+------+------+---------+
| that    |      |      | X       |
|---------+------+------+---------+
| foo bar |      | X    |         |
|---------+------+------+---------+
  • Tables are read by method get, see below.

  • Only two different table entries are possible, these are X and the empty string (this is default and can be changed, see description of new).

  • The entry in the table's upper left corner is simply ignored and may be empty, but you cannot ommit the upper left | character.

  • The hotizontal rules are optional.

  • There is not something like a format check for the horizontal rules or alignment. Any line starting with |- is simply ignored, regardless of the other subsequent characters, if any. Also, the | need not to be aligned, and heading spaces are ignored.

  • Unless you specified a base set in the construcor call, the entries (names) in the table's header line are the set's element names. Of course, they must be unique. One of these names may be the empty string. Names my contain spaces or punctuation chars. The |, of course, cannot be part of a name.

  • The names of the columns (header line) and the rows (first entry of each row) must be unique, but they don't have to appear in the same order. By default, the set of the header names and the set of the row names must be equal, but this can be chaned by argument allow_subset of method get.

METHODS

new

The constructor take the following optional named scalar arguments:

inc

A string. Table entry that flags that the corresponding elements are related. | is not allowed, the value must be different from value of noinc.

Default is "X".

noinc

A string. Table entry that flags that the corresponding elements are not related. | is not allowed, the value must be different from value of inc.

Default is the empty set.

set

If specified, then this must be an array of unique strings specifying the elements of the set for your relation (it may also contain arrays, see below). When the constructor was called with this argument, then method elems will return a reference to a copy of it, and elem_ids will return a hash mapping each element to its array index (otherwise both methods would return undef before the first call to get).

Method get will check if the elements in the input table are the same as those specified in the array. Furthermore, the indices in matrix will always refere to the indices in the elems array constructd from set, and elems and elem_ids will always return the same, regardless of the order of rows and columns in the input table.

It may happen that there are elements that are identical with respect to the relation and you do not want to write duplicate rows and columns in your table. To cover such a case, it is allowed that entries of set are array references again (another was is using argument eqs).

Example:

[[qw(a a1 a2 a3)], 'b', [qw(c c1)], 'd']

In this case, the elements you write in your table are a, b, c, and d (in case of a subarray always the first element is taken). Method get will add corresponding rows and columns for a1, a2, a3, and c1 to the incidence matrix. Method elems will return this (the nested arrays are flattened):

[qw(a a1 a2 a3 b c c1 d)]

Method elem_ids will return:

{
 'a'  => '0',
 'a1' => '1',
 'a2' => '2',
 'a3' => '3',
 'b'  => '4',
 'c'  => '5',
 'c1' => '6',
 'd'  => '7'
 }

Method tab_elems will return:

{
 a => 0,
 b => 4,
 c => 5,
 d => 7
 }

And method eq_ids will return:

0 => [1, 2, 3],
5 => [6]
eqs

This argument takes a reference to an array of array references. It can only be used if argument set is specified, too. If eqs is specified, then the array passed via set cannot contain arrays again.

This constructor call:

Text::Table::Read::RelationOn::Tiny->new(set => [qw(a a1 a2 a3 b c c1 d)],
                                         eqs => [[qw(a a1 a2 a3)],
                                                 [qw(c c1)]]);

produces the same as this (see description of argument set):

Text::Table::Read::RelationOn::Tiny->new(set => [[qw(a a1 a2 a3)], 'b',
                                                 [qw(c c1)], 'd']);

However, the benefit of eqs is that you can separate the declaration of the base set and the equivalent elements, meaning that you can enforce an order of the elements independent from what elements are equivalent in your relation.

get

The method reads and parses a table. It takes two named arguments.

src

Mandatory. The source from which the table is to be read. May be either a file name, an array reference or a string containing newline characters.

Argument is an array reference

The method treats the array entries as the rows of the table.

Argument is a string containing newlines

The method treats the argument as a string representation of the table and parses it.

Argument is a string not containing newlines

The method treats the argument as a file name and tries to read the table from that file.

allow_subset

Optional. Take a boolean value. If true, then rows and columns need not to be equal and may contain a subset of the relation's base set only. This way you can omit rows and columns not containing any incidences.

Note that the method will stop parsing if it recognizes a line containing not any non-white character and will ignore any subsequent lines.

If you did not specify a base set in the constructor call, then get will create the set from the table. Then, it creates a hash of hashes representing the relation (incidence matrix): each key is an integer which is an index in the element array created before. Each corresponding value is again a hash where the keys are the array indices of the elements being in relation; the values do not matter and are always undef. This hash will never contain empty subhashes. (you can obtain this hash from the returned list or from method matrix).

get will add identical rows and columns to the resulting incidence matrix for elements that have been specified to be equivalent (see description of new).

Example

This table:

| x\y   | norel |      | foo | bar |
|-------+-------+------+-----+-----|
| norel |       |      |     |     |
|-------+-------+------+-----+-----|
|       |       | X    | X   |     |
|-------+-------+------+-----+-----|
| foo   |       |      |     | X   |
|-------+-------+------+-----+-----|
| bar   |       |      | X   |     |
|-------+-------+------+-----+-----|

will result in this array:

('norel', '', 'foo', 'bar')

this hash:

('norel' => 0, '' => 1, 'foo' => 2, 'bar' => 3)

and in this hash representing the incidence matrix:

1 => {
         1 => undef,
         2 => undef
       },
3 => {
         2 => undef
       },
2 => {
         3 => undef
       }

Note that element norel (id 0), which is not in any relation, does not appear in this hash (it would be 0 => {} but as said, empty subhashes are not contained).

Return value:

In scalar context, the method returns simply the object.

In list context, the method returns a list containing three references corresponding to the accessor methods matrix, elems and elem_ids: the hash representing the incidence matrix, the element array and the element index (id) hash. Thus, wirting:

my ($matrix, $elems, $elem_ids) = $obj->get($my_input);

is the same as writing

$obj->get($my_input);
my $matrix   = $obj->matrix;
my $elems    = $obj->elems;
my $elem_ids = $obj->elem_ids;

However, the first variant is shorter and needs only one method call.

inc

Returns the current value of inc. See description of new.

noinc

Returns the current value of noinc. See description of new.

prespec

Returns 1 (true) if you specified constructor argument set when calling the constructor, otherwise it returns an empty string (false).

elems

Returns a reference to the array of elements (names from the table's header line), or undef if you did neither call get for the current object nor specified option set when calling the constructor. See description of get and new.

Note: This returns a reference to an internal member, so do not change the contents!

elem_ids

Returns a reference to a hash mapping elements to ids (indices in array returned by elems), or undef if you did neither call get for the current object nor specified argument set when calling the constructor.

Note: This returns a reference to an internal member, so do not change the contents!

tab_elems

Returns a reference to a hash whose keys are the elements that may appear in the table. If you did not specify equivalent elements (see description of new), then the contents of this hash is identical with elem_ids.

Note: This returns a reference to an internal member, so do not change the contents!

eq_ids

Returns a reference to a hash. If you specified equivalent elements (see description of new), then the keys are the indices (see elem_ids and elems) of the representants and each value is an array of indices of the corresponding equivalent elements (without the representant).

If you did not specify equivalent elements, the this method return undef after the constructor call, but the first call to get sets it to an empty hash.

Note: This returns a reference to an internal member, so do not change the contents!

matrix

Returns the incidence matrix (reference to a hash of hashes) produced by the most recent call of get, or undef if you did not yet call get for the current object. See description of get.

It takes a single optional boolean named argument bless. If true, then the matrix is blessed with Text::Table::Read::RelationOn::Tiny::_Relation_Matrix Then you can use the matrix as an object having exactly one method named related. This method again takes two arguments (integers) and check if these are related with respect to the incidence matrix. Note that c<related> does not do any parameter check.

Example:

$rel_obj->bless_matrix;
my $matrix = $rel_obj->matrix(bless => 1);
if ($matrix->related(2, 5)) {
  # ...
}

Note: This returns a reference to an internal member, so do not change the contents!

matrix_named

Returns an incidence matrix just as matrix does, but the keys are the element names rather than their indices It takes a single optional boolean named argument bless doing a job corresponding to the bless argument of matrix.

Note: Unlike matrix the matrix returned by matrix_named is not a data member and thus it is computed everytime you call thie method.

AUTHOR

Abdul al Hazred, <451 at gmx.eu>

BUGS

Please report any bugs or feature requests to bug-text-table-read-relationon-tiny at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Text-Table-Read-RelationOn-Tiny. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Text::Table::Read::RelationOn::Tiny

You can also look for information at:

LICENSE AND COPYRIGHT

This software is Copyright (c) 2021 by Abdul al Hazred.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)