The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

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

VERSION

Version v2.3.1

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 omit the upper left | character.

  • The hotizontal rules are optional.

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

    However, a format check can be enabled by specifying get argument pedantic with a true value.

  • If you have not specified a base set in the construcor call, the entries (names) in the table header are the element names of the set. 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 changed by argument allow_subset of method get.

METHODS

new

The constructor takes the following optional named 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. Heading and trailing spaces are removed.

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. Heading and trailing spaces are removed.

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 refer to the indices in the elems array constructed 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 references to array of strings again (another way 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 the first element is always 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.

ext

"External data". If this boolean option is true, then the array referenced by set is not copied. Instead, the contructor uses directly the reference you passed by set and elems will return this reference. This means, that you must specify set if you set ext to true.

You can also specify elem_ids along with set and ext. In this case, the constructor first checks this hash for consistency and then uses the data without copying it. See description of set for more details about the elem_ids hash.

Restriction: you can't use array references as entries in the set array if you set ext to true. However, you can still use eqs if you want to specify equivalent elements.

Default is false.

elem_ids

This can only be specified in conjunction with ext and set. See description of argument set.

get

The method reads and parses a table. It takes the following 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. Takes 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.

Default is false.

pedantic

Optional. Takes a boolean value. If true, then some additional table format checks are done:

  • Each row (incl. the header) must have a trailing | character

  • | characters (and + characters of row seperators) must be aligned.

  • Row separators are also checked, but they are still optional.

  • Indentation (if any) must be the same for all table rows.

Default is false.

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 [DUP]

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.

If optinal scalar argument DUP has a true value, then a reference to a clone of this array is returned. Default is false.

Note: Without passing a true value via DUP this returns a reference to an internal member, so don't change the content in this case!

elem_ids [DUP]

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.

If optinal scalar argument DUP has a true value, then a reference to a clone of this hash is returned. Default is false.

Note: Without passing a true value via DUP this returns a reference to an internal member, so don't change the content in this case!

tab_elems [DUP]

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.

If optinal scalar argument DUP has a true value, then a reference to a clone of this hash is returned. Default is false.

Note: Without passing a true value via DUP this returns a reference to an internal member, so don't change the content in this case!

eq_ids [DUP]

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.

If optinal scalar argument DUP has a true value, then a reference to a clone of this hash is returned. Default is false.

Note: Without passing a true value via DUP this returns a reference to an internal member, so don't change the content in this case!

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.

This method takes the following optional named scalar arguments:

bless

Boolean. 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 related does not do any parameter check.

Example:

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

Default is false.

dup

Boolean. If this has a true value, then a reference to a clone of the matrix is returned. Default is false.

Note: Without setting dup to true this returns a reference to an internal member, so don't change the content!

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 this method. This also means that you can change the content of the returned matrix without damaging anything.

PITFALLS

Basically, you do not need spaces around the | separators. This table, for example, is perfectly fine:

     |.|a|b|c|
     |-+-+-+-|
     |c| |X| |
     |-+-+-+-|
     |b| | | |
     |-+-+-+-|
     |a| | |X|

However, if you have element names with a dash at the beginning, then you need a space at least after the first | character. Example:

WRONG
    | x\y   | this | that |-blah   |-    |
    |-------+------+------+--------+-----|
    | this  | X    |      | X      |  X  |
    |-------+------+------+--------+-----|
    | that  |      |      | X      |     |
    |-------+------+------+--------+-----|
    |-blah  |      | X    |        |     |
    |-------+------+------+--------+-----|
    |-      |      |      |        |     |
    |-------+------+------+--------+-----|
    | x\y   | this | that |-blah   |-    |
    |-------+------+------+--------+-----|
    | this  | X    |      | X      |  X  |
    |-------+------+------+--------+-----|
    | that  |      |      | X      |     |
    |-------+------+------+--------+-----|
    | -blah |      | X    |        |     |
    |-------+------+------+--------+-----|
    | -     |      |      |        |     |
    |-------+------+------+--------+-----|

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)