NAME

Set::Scalar - the basic set operations for Perl scalar/reference data

SYNOPSIS

use Set::Scalar;

or

use Set::Scalar qw(union intersection);

to import, for example, union and intersection to the current namespace. By default nothing is imported, the exportable routines are as_string union intersection symmetric_difference difference in compare equal disjoint proper_subset proper_superset subset superset, please see below for further documentation.

DESCRIPTION

Sets are created with new. Lists as arguments for new give normal sets, hash references (please see perlref) give valued sets. The special sets, null set or the none, empty, set, and the universal set or the all are created with null and universal.

$a = Set::Scalar->new('a', 'b', 'c', 'd');	# set members
$b = Set::Scalar->new('c', 'd', 'e', 'f');	# set members
$c = Set::Scalar->new(qw(d e));		# set members
$d = Set::Scalar->new({'f', 12, 'g', 34});	# 'valued' set
$e = Set::Scalar->new($a, 'h', 'i');	# sets are recursive
$n = Set::Scalar->null;			# the empty set
$u = Set::Scalar->universal;		# the 'all' set

Valued sets are "added value" sets: normal sets have only their members but valued sets have one scalar/ref value per each of their member. See the discussion about values and valued_members for how to retrieve the values.

Set inversion or the not set is done with inverse or the overloaded prefix operator -.

$i = $a->inverse;				# the 'not' set
$i = -$a;				# or with the overloaded -

Displaying sets is done with as_string or more commonly with the overloaded stringification "operator" ".

print "a = ", $a->as_string, "\n";
print "b = $b\n";			# or with the overloaded "
print "c = $c\n";
print "d = $d\n";
print "e = ", $e, "\n";
print "i = $i\n";
print "n = $n\n";
print "u = $u\n";

NOTE: please do not try to display circular sets. Yes, circular sets can be built. Yes, trying to display them will cause infinite recursion.

The usual set operations are done with union, intersection, symmetric_difference, and difference, or with their overloaded infix operator counterparts, +, *, %, and -.

print "union(a,b) = ", Set::Scalar->union($a, $b), "\n";
print "a + b = ", $a + $b, "\n";	# or with the overloaded +

print "intersection(a,b) = ", Set::Scalar->intersection($a, $b), "\n";
print "a * b = ", $a * $b, "\n";	# or with the overloaded *

print "symmdiff(a,b) = ", Set::Scalar->symmetric_difference($a, $b), "\n";
print "a % b = ", $a % $b, "\n";	# or with the overloaded %

print "difference(a,b) = ", Set::Scalar->difference($a, $b), "\n";
print "a - b = ", $a - $b, "\n";	# or with the overloaded -

NOTE: the distributive laws (please see LAWS or t/laws.t in the Set::Scalar distribution) cannot always be satisfied. This is because in set algebra the whole universe (all the possible members of all the possible sets) is supposed to be defined beforehand BUT the set operations see only two sets at a time. This can cause the distributive laws

X + (Y * Z) == (X + Y) * (X + Z)
X * (Y + Z) == (X * Y) + (X * Z)

to fail because the + and * do not necessarily "see" all the members of the X, Y, Z in time. Beware this effect especially when having simultaneously any two of the X, Y, Z, being identical in members except the other being inverted, or one the X, Y, Z, being the null set.

Modifying sets in-place is done with insert and delete or their overload counterparts += and -=. Testing for membership is done with in.

print "a  = $a\n";
$a->insert('x');
print "a' = $a\n";
print 'x is', $a->in('x') ? '' : ' not', " in a\n";
$a->delete('x');
print "a  = $a\n";
print 'x is', $a->in('x') ? '' : ' not', " in a\n";

NOTE: set copying by = is shallow. Sets are objects and the = copies only the topmost level. That is, the copy is a reference to the original set.

$x = $a;
print "a  = $a, x = $x, e = $e\n";
$a->insert('x');
print "a' = $a, x = $x, e = $e\n";	# also the 'copy' of a changes
$a->delete('x');
print "a' = $a, x = $x, e = $e\n";

For deep ("real") copying use copy (or ->new($set)).

$y = $e->copy;
print "a  = $a, y = $y, e = $e\n";
$a->insert('y');
# the (real, deep) copy does not change
print "a' = $a, y = $y, e = $e\n";
$a->delete('y');
print "a' = $a, y = $y, e = $e\n";

Testing sets is done with is_null, is_universal, is_inverted, and is_valued.

print 'a is', $a->is_null      ? '' : ' not', " null\n";
print 'a is', $a->is_universal ? '' : ' not', " universal\n";
print 'a is', $a->is_inverted  ? '' : ' not', " inverted\n";
print 'a is', $a->is_valued    ? '' : ' not', " valued\n";
print 'd is', $d->is_null      ? '' : ' not', " null\n";
print 'd is', $d->is_universal ? '' : ' not', " universal\n";
print 'd is', $a->is_inverted  ? '' : ' not', " inverted\n";
print 'd is', $d->is_valued    ? '' : ' not', " valued\n";
print 'i is', $i->is_null      ? '' : ' not', " null\n";
print 'i is', $i->is_universal ? '' : ' not', " universal\n";
print 'i is', $i->is_inverted  ? '' : ' not', " inverted\n";
print 'i is', $i->is_valued    ? '' : ' not', " valued\n";
print 'n is', $n->is_null      ? '' : ' not', " null\n";
print 'n is', $n->is_universal ? '' : ' not', " universal\n";
print 'n is', $n->is_inverted  ? '' : ' not', " inverted\n";
print 'n is', $n->is_valued    ? '' : ' not', " valued\n";
print 'u is', $u->is_null      ? '' : ' not', " null\n";
print 'u is', $u->is_universal ? '' : ' not', " universal\n";
print 'u is', $u->is_inverted  ? '' : ' not', " inverted\n";
print 'u is', $u->is_valued    ? '' : ' not', " valued\n";

Comparing sets is done with

	compare
	equal
	disjoint
        intersect
	proper_subset
	proper_superset
	subset
	superset

or more commonly with their overloaded infix operator counterparts

	<=>
	==
	!=
    	<>
	<
	>
	<=
	=>

NOTE: The compare is a multivalued relational operator, not a binary (two-valued) one. It returns a string that is one of

==
!=
<>
<
>
<=
=>

The equal, disjoint, intersect, proper_subset, proper_superset, subset, and superset, are binary (true or false) relational operators.

The difference between disjoint and intersect is that the former means completely disjoint, no common members at all, and the latter means partly disjoint, some common members, some not.

print "a <=> a = '", $a <=> $a, "'\n";
print "a == c\n" if ($a == $c);
print "b <=> c = '", $b <=> $c, "'\n";
print "c <=> b = '", $c <=> $b, "'\n";
print "b >= c\n" if ($b >= $c);
print "c <  b\n" if ($c <  $b);
print "a <=> c = '", $a <=> $c, "'\n";
print "a <=> d = '", $a <=> $d, "'\n";

NOTE: please do not try to "sort" sets based on the subset and superset relational operators. This will not work in general case because sets can have circular relationships. Circular sets will cause infinite recursion.

The set members can be accessed with members. For the valued sets either the values can be accessed with values as a list or both the members and the values with valued_members as a hash. None of these returns the items in any particular order, the sets of Set::Scalar are unordered.

for $i ($a->members) {		print "a: $i\n"; }

for $i (Set::Scalar->values($d)) {	print "d: $i\n"; }

%d = $d->valued_members;
while (($k, $v) = each %d) {	print "d: $k $v\n"; }

Sets can be greped and mapped.

%g = $a->grep(sub { $_[0] eq 'b' });
$g = Set::Scalar->new(keys %g);
print "g = $g\n";

%m = $d->map(sub { my ($k, $v, $d) = @_;
                   $k =~ tr/a-z/A-Z/;
                   $v *= $v;
                   $d = $k ne 'G';
                   ($k, $v, $d); });
$m = Set::Scalar->new({ %m });
print "m = $m\n";

The power set (the set of all the possible subsets of a set) is generated with power_set.

$p = $a->power_set;
print "p = $p\n";

Displaying sets can be fine-tuned either per set or by changing the global default display attributes using the display_attr with two arguments. The display attributes can be examined using the display_attr with one argument.

The display attributes are:

format, a string which should contain magic sequences %s which marks the place of the signedness (normal or inverted) of set, and %m, which marks the place of the members of the set. The default is %s(%m)

inverse, a string that tells how to mark an inverted set (the %s in format). The default is -.

exists, a string that tells how to mark an "existing" set. An "existing" set? It is a set that is not inverted, that is, a set that is "not not", (the %s in format). The default is ''.

member_separator, a string that tells how to separate the members of the set, (the %m in format). The default is ' '.

value_style, a string that tells how to display valued sets. Only two styles are defined: parallel (the default) or serial. The former means that the order is

m1 v1 m2 v2 ...

and the latter means that the order is

m1 m2 ... v1 v2 ...

value_indicator, a string that tells how to separate the members from the values in the case of valued sets. In the parallel style there are as many value_indicators shown as there are members (or values), in the serial style only one value_indicator is shown.

value_separator, a string that tells how to separate the members and the values in case of serial display of valued sets, (the %m in format). The default is ' '.

sort, a name of a subroutine that tells how to order the members of the set. The default is '_DISPLAY_SORT' which sorts the members alphabetically. This is why the displayed form is something like this

(a b c d)

and not anything random (to be exact, in hash order). Sets do not have any particular order per se (please see the members discussion).

print "format(a) = ", $a->display_attr('format'), "\n";
print "memsep(a) = ", $a->display_attr('member_separator'), "\n";
print "format(b) = ", $b->display_attr('format'), "\n";
print "memsep(b) = ", $b->display_attr('member_separator'), "\n";

# changing the per-set display attributes

$a->display_attr('format', '%s{%m}');
$a->display_attr('member_separator', ',');
print "a = $a, b = $b\n";
print "format(a) = ", $a->display_attr('format'), "\n";
print "memsep(a) = ", $a->display_attr('member_separator'), "\n";
print "format(b) = ", $b->display_attr('format'), "\n";
print "memsep(b) = ", $b->display_attr('member_separator'), "\n";

# changing the default display attributes

print "memsep = '", Set::Scalar->display_attr('member_separator'), "'\n";
Set::Scalar->display_attr('member_separator', ':');
print "memsep = '", Set::Scalar->display_attr('member_separator'), "'\n";
print "a = $a, b = $b\n";
Set::Scalar->display_attr('member_separator', ' ');

AUTHOR

Jarkko Hietaniemi, Jarkko.Hietaniemi@iki.fi