#!/usr/bin/env perl

use strict;
use warnings;
use Math::Prime::Util qw(mulmod);
use Math::DifferenceSet::Planar 1.000;

$| = 1;

my $USAGE = "usage: pds_rotators [-D database] [-f|-m] (p n|q)\n";

my $full = 0;
my $min  = 0;
my $db   = undef;
while (@ARGV && $ARGV[0] =~ /^-(.+)\z/s) {
    my $opt = $1;
    shift @ARGV;
    last                       if '-' eq $opt;
    $full = 1, $min = 0,  last if 'f' eq $opt;
    $full = 0, $min = 1,  last if 'm' eq $opt;
    $db   = shift(@ARGV), next if 'D' eq $opt && @ARGV;
    $db   = $1,           next if $opt =~ /^D(.+)/s;
    die $USAGE;
}
if (@ARGV < 1 || 2 < @ARGV  || grep {!/^[1-9][0-9]*\z/} @ARGV) {
    die $USAGE;
}
Math::DifferenceSet::Planar->set_database($db) if defined $db;

my $it = Math::DifferenceSet::Planar->iterate_rotators(@ARGV);

if ($full || $min) {
    my @mu = Math::DifferenceSet::Planar->multipliers(@ARGV);
    my $mo;
    if (@ARGV == 1) {
        my $or = $ARGV[0];
        $mo = ($or + 1) * $or + 1;
    }
    else {
        my $ex = $ARGV[1];
        $mo = $mu[$ex << 1] + $mu[$ex] + 1;
    }
    shift @mu;
    while (my $ro = $it->()) {
        my @eqv = sort { $a <=> $b } $ro, map { mulmod($_, $ro, $mo) } @mu;
        print $full? "@eqv\n": "$eqv[0]\n";
    }
}
else {
    while (my $ro = $it->()) {
        print $ro, "\n";
    }
}

__END__

=head1 NAME

pds_rotators - enumerate planar difference set rotators of a given order

=head1 SYNOPSIS

  pds_rotators [-D database] [-f|-m] p n
  pds_rotators [-D database] [-f|-m] order

=head1 DESCRIPTION

This example program writes rotators (reduced residue systems) for
planar difference sets of a given order to standard output.  The order
can be specified as a prime number and an exponent, or as a prime power.
The output will be lines with one integer number per line, for all
rotators of the given order.

With option B<-m>, the smallest from each equivalence set of residues
will be output rather than an arbitrary representative.

With option B<-f>, output lines consist of complete equivalence sets
of rotator values separated by blanks.  Thus all values coprime to the
modulus will appear, grouped by plane.

=head1 AUTHOR

Martin Becker, E<lt>becker-cpan-mp I<at> cozap.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2022-2024 by Martin Becker, Blaubeuren.

This library is free software; you can distribute it and/or modify it
under the terms of the Artistic License 2.0 (see the LICENSE file).

The licence grants freedom for related software development but does
not cover incorporating code or documentation into AI training material.
Please contact the copyright holder if you want to use the library whole
or in part for other purposes than stated in the licence.

=head1 DISCLAIMER OF WARRANTY

This library is distributed in the hope that it will be useful, but
without any warranty; without even the implied warranty of merchantability
or fitness for a particular purpose.

=cut
