#!/usr/bin/env perl

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

use constant PDS => Math::DifferenceSet::Planar::;

$| = 1;

my $USAGE =
    "usage: pds_sample [-s|-l|-g|-z|-r] [-nnn] [-D database] (p n|order)\n";

my $type = 'new';
my $db   = undef;
my $rand = 0;
my $mult = 1;
while (@ARGV && $ARGV[0] =~ /^-(.+)/s) {
    my $opt = $1;
    shift @ARGV;
    $type = 'std_reference',  next if 's' eq $opt || 'z' eq $opt;
    $type = 'lex_reference',  next if 'l' eq $opt;
    $type = 'gap_reference',  next if 'g' eq $opt;
    $type = 'new', $rand = 1, next if 'r' eq $opt;
    $db   = shift(@ARGV),     next if 'D' eq $opt && @ARGV;
    $db   = $1,               next if $opt =~ /^D(.+)/s;
    $mult = $opt,             next if $opt =~ /^[1-9][0-9]*\z/;
    die $USAGE;
}
$rand &&= $type eq 'new';
die $USAGE if !@ARGV || 2 < @ARGV || grep { !/^[1-9][0-9]*\z/ } @ARGV;

Math::DifferenceSet::Planar->set_database($db) if defined $db;

if (!PDS->available(@ARGV)) {
    my $order = join q[^], @ARGV;
    die "$order: no set of this order available\n";
}

my $s = PDS->$type(@ARGV);
if (!defined $s) {
    my $order = join q[^], @ARGV;
    $type =~ tr/_/ /;
    die "$order: no $type set of this order available\n";
}

foreach my $i (1..$mult) {
    if ($rand) {
        my $modulus = $s->modulus;
        my $factor  = 1 + urandomm($modulus - 1);
        while (gcd($factor, $modulus) != 1) {
            $factor = 1 + urandomm($modulus - 1);
        }
        my $delta = urandomm($modulus);
        $s = $s->multiply($factor)->translate($delta);
    }
    my @e = $s->elements_sorted;
    print "@e\n";
}

__END__

=head1 NAME

pds_sample - print a planar difference set sample of a given order

=head1 SYNOPSIS

  pds_sample [-s|-l|-g|-z|-r] [-nnn] [-D database] p n
  pds_sample [-s|-l|-g|-z|-r] [-nnn] [-D database] order

=head1 DESCRIPTION

This example program writes one or more planar difference sets of a
given type and 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 representative difference sets of the given order.
If the order is not a prime power or exceeds an implementation specific
size restriction, the program fails with an error message.

An option in the form of a negative integer means that multiple sets
are generated, as many as the absolute value of the integer.  This of
course only makes sense for random samples.

Option C<-s> chooses the standard reference set.

Option C<-l> chooses the lexically minimal reference set.

Option C<-g> chooses the big-to-small lexically minimal reference set.

Option C<-z> chooses the lexically minimal zeta-canonical reference set.
Currently, the standard reference set is the same set.

Option C<-r> chooses a random set.

Parameter C<-D> specifies an alternate sample database.

=head1 BUGS AND LIMITATIONS

When generating random sets, the randomness of the first result depends on
the amount of entropy available on the platform the tool is running on.
Additional results are distributed uniformly over the solution domain
using a pseudo random number generator.  It is sufficiently deep to
cover the whole domain but may exhibit subtle regularities due to its
deterministic nature.

=head1 AUTHOR

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

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2020-2025 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 license 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 license.

=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
