Algorithm-AM

 view release on metacpan or  search on metacpan

lib/Algorithm/AM/lattice.pod  view on Meta::CPAN


The value of I<n>, and thus the size of the lattice, is determined by
the length of the I<feature vector> of the test item (see F<AM.pod>
for more explanation).  There is a set corresponding to each I<n>-bit
positive integer; furthermore, if set I<A> corresponds to integer I<a>
and set I<B> corresponds to integer I<b>, then I<A> is a superset of
(or "below") I<B> if I<a> & I<b> = I<b>.

=item *

Many of the elements of the supracontextual lattice are equal as sets;
i.e., they have precisely the same members.  Thus, for those of you
who know a lot of math, it is important not to confuse the
supracontextual lattice with the Boolean algebra generated by the
power set of a set.  The supracontextual lattice I<is> a Boolean
algebra of sets; where these sets come from is explained in F<AM.pod>.

To store the supracontextual lattice, it is enough to create an array
C<lattice[]> of length 2^I<n>, where C<lattice[>I<a>C<]> contains a
pointer to a structure containing information about the elements of
the set corresponding to I<a>.

Of course, the size of C<lattice[]> grows exponentially with I<n>; to
overcome that, see the section on L<lattices as products of smaller
lattices|"LATTICES AS PRODUCTS OF SMALLER LATTICES">.

=item *

The supracontextual lattice is built up by adding elements to these
sets one at a time.  When a new element is added to a set, it is a
simple thing to C<memcpy> (actually, we use Perl's safe equivalent,
C<Copy>) the original set to a new location, append the new element,
and change the pointer.  We only have to do this once; F<Parallel.xs>
keeps track of the creation of new sets, so sometimes all that is
necessary is the changing of a pointer.

=back

=head1 TRAVERSING A LATTICE

During the course of the AM algorithm, it is necessary to visit all
the supracontexts that lie "below" a given supracontext.  For
example, given that a supracontext is labeled

 1001011

AM requires an iterator that produces

 1001111
 1011011
 1011111
 1101011
 1101111
 1111011
 1111111

though the order in which these seven are produced is immaterial.

F<Parallel.xs> does this by using a I<Gray code>.  This is a method by
which only one bit flips (either from 0 to 1 or from 1 to 0) at each
step.  Deciding which bit to flip is done as follows:

=over 4

=item 1

List the "gaps"; for

 1001011

the gaps are

 0100000 = gaps[0]
 0010000 = gaps[1]
 0000100 = gaps[2]

Each gap has exactly one 1 bit which lines up with a 0 in the original
number.

=item 2

If there are I<g> gaps, list the I<g>-bit integers in reverse order:
in this case, 111, 110, ..., 001, 000.

=item 3

Take each of these numbers in succession.  Determine where the
rightmost 1 is; its position determines which bit to flip:

 1001011
 1101011 = 1001011 ^               0100000 (rightmost 1 of 111 is bit 0, use gap[0])
 1111011 = 1101011 ^        0010000        (rightmost 1 of 110 is bit 1, use gap[1])
 1011011 = 1111011 ^               0100000 (rightmost 1 of 101 is bit 0, use gap[0])
 1011111 = 1011011 ^ 0000100               (rightmost 1 of 100 is bit 2, use gap[2])
 1111111 = 1011111 ^               0100000 (rightmost 1 of 011 is bit 0, use gap[0])
 1101111 = 1111111 ^        0010000        (rightmost 1 of 010 is bit 1, use gap[1])
 1001111 = 1101111 ^               0100000 (rightmost 1 of 001 is bit 0, use gap[0])

=back

(As I write this, I see that finding the bit to flip is the same
problem of deciding which disk to move in the Towers of Hanoi
problem.)

=head1 LATTICES AS PRODUCTS OF SMALLER LATTICES

Consider the following lattice: the first number is the binary label,
and the other numbers represent the elements of the set with that
label:

 label  elements

  0000

  0001  3
  0010
  0100  6
  1000

  0011  3
  0101  3 6
  0110  6
  1001  1 3
  1010  4
  1100  5 6

  0111  2 3 6
  1011  1 3 4 7
  1101  1 3 5 6
  1110  4 5 6

  1111  1 2 3 4 5 6 7

(Verify that this is a lattice.)

This lattice can be stored as two smaller lattices:

 label  elements

    00  3
    01  2 3 6
    10  1 3 4 7
    11  1 2 3 4 5 6 7

 label  elements

    00  5 6
    01  1 3 5 6
    10  4 5 6
    11  1 2 3 4 5 6 7

The set labeled by 1001 in the large lattice is precisely the
intersection of the sets labeled by 10 and 01 respectively in the
smaller lattices: {1, 3} is the intersection of {1, 3, 4, 7} and {1,
3, 5, 6}.

C<AM::Parallel> breaks the supracontextual lattice up into 4 smaller
lattices, resulting in a great savings of memory at the expense of
finding a lot of intersections.  But since the elements of the sets
are listed as increasing sequences of positive integers, finding the
intersection is actually quite straightforward.



( run in 1.008 second using v1.01-cache-2.11-cpan-d7f47b0818f )