AI-Termites

 view release on metacpan or  search on metacpan

lib/AI/Termites.pm  view on Meta::CPAN


use strict;
use warnings;

use Math::Vector::Real;
use Math::Vector::Real::Random;

use List::Util;
use Carp;

sub new {
    my ($class, %opts) = @_;
    my ($dim, $box);
    $box = delete $opts{box};
    if (defined $box) {
	$box = V(@$box);
	$dim = @$box;
    }
    else {
	$dim = delete $opts{dim} // 3;
	my $size = delete $opts{world_size} // 1000;

lib/AI/Termites.pm  view on Meta::CPAN

		 dim => $dim };

    bless $self, $class;

    push @wood, $self->new_wood for (1..$n_wood);
    push @termites, $self->new_termite for (1..$n_termites);
    $self->iterate for (1..$iterations);
    $self;
}

sub dim { shift->{dim} }

sub box { shift->{box} }

sub new_wood {
    my $self = shift;
    my $wood = { pos => $self->{box}->random_in_box,
		 taken => 0 };
}

sub new_termite {
    my $self = shift;
    my $termite = { pos => $self->{box}->random_in_box };
}

sub iterate {
    my $self = shift;

    $self->before_termites_move;

    for my $term (@{$self->{termites}}) {
	$self->termite_move($term);
    }
    $self->before_termites_action;
    for my $term (@{$self->{termites}}) {
	$self->termite_action($term);
    }
    $self->after_termites_action;
}

sub termite_move {
    my ($self, $termite) = @_;
    $termite->{pos} = $self->{box}->wrap( $termite->{pos} +
					  Math::Vector::Real->random_normal($self->{dim},
									    $self->{speed}));
}

sub before_termites_move {}
sub before_termites_action {}
sub after_termites_action {}

sub termite_action {
    my ($self, $termite) = @_;
    if (defined $termite->{wood_ix}) {
        if ($self->termite_leave_wood_p($termite)) {
            $self->termite_leave_wood($termite);
        }
    }
    else {
        my $wood_ix = $self->termite_take_wood_p($termite);
        defined $wood_ix and $self->termite_take_wood($termite, $wood_ix);
    }
}

sub termite_take_wood {
    my ($self, $termite, $wood_ix) = @_;
    my $wood = $self->{wood}[$wood_ix];
    return if $wood->{taken};
    $wood->{taken} = 1;
    $self->{taken}++;
    # print "taken: $self->{taken}\n";
    defined $termite->{wood_ix} and die "termite is already carrying some wood";
    $termite->{wood_ix} = $wood_ix;
}

sub termite_leave_wood {
    my ($self, $termite) = @_;
    my $wood_ix = delete $termite->{wood_ix} //
	croak "termite can not leave wood because it is carrying nothing";
    $self->{taken}--;
    my $wood = $self->{wood}[$wood_ix];
    $wood->{taken} = 0;
    $wood->{pos}->set($termite->{pos});
}


lib/AI/Termites/LoginquitasPostulo.pm  view on Meta::CPAN

package AI::Termites::LoginquitasPostulo;

use strict;
use warnings;

use Math::Vector::Real;
use Math::Vector::Real::kdTree;

use parent 'AI::Termites';

sub before_termites_action {
    my $self = shift;
    my @ixs = grep !$self->{wood}[$_]{taken}, 0..$#{$self->{wood}};
    $self->{kdtree_ixs} = \@ixs;
    $self->{kdtree} = Math::Vector::Real::kdTree->new(map $_->{pos}, @{$self->{wood}}[@ixs]);
}

sub termite_take_wood_p {
    my ($self, $termite) = @_;
    my $pos = $termite->{pos};
    my $near = $self->{near};
    my $wood_ix = $self->{kdtree}->find_nearest_neighbor($pos, $near);
    if (defined $wood_ix) {
        my ($next_ix, $d) = $self->{kdtree}->find_nearest_neighbor($pos, $near, $wood_ix);
        if (not defined $next_ix or rand($near) < $d) {
            return $self->{kdtree_ixs}[$wood_ix];
        }
    }
    undef
}

sub termite_leave_wood_p {
    my ($self, $termite) = @_;
    my $pos = $termite->{pos};
    my $near = $self->{near};
    my ($wood_ix, $d) = $self->{kdtree}->find_nearest_neighbor($pos, $near);
    if (defined $wood_ix and rand($near) > $d) {
        return 1;
    }
    undef;
}

lib/AI/Termites/NemusNidor.pm  view on Meta::CPAN

use 5.010;
use strict;
use warnings;

use Math::Vector::Real;
use Math::Vector::Real::kdTree;
use Math::Vector::Real::MultiNormalMixture;

use parent 'AI::Termites';

sub before_termites_action {
    my $self = shift;
    my @ixs = grep !$self->{wood}[$_]{taken}, 0..$#{$self->{wood}};
    $self->{kdtree_ixs} = \@ixs;
    $self->{kdtree} = Math::Vector::Real::kdTree->new(map $_->{pos}, @{$self->{wood}}[@ixs]);
    my $sigma = $self->{near}**(-2) * log(2);
    # print "sigma: $sigma\n";
    my $mnm = Math::Vector::Real::MultiNormalMixture->new(mu => [map $_->{pos}, @{$self->{wood}}[@ixs]],
                                                          sigma => $sigma);
    $self->{mnm} = $mnm;
    $self->{mnm_max} = $mnm->max_density_estimation;
}

sub termite_take_wood_p {
    my ($self, $termite) = @_;
    my $pos = $termite->{pos};
    my $near = $self->{near};
    my $wood_ix = $self->{kdtree}->find_nearest_neighbor($pos, $near);
    if (defined $wood_ix) {
        my @near = $self->{kdtree}->find_in_ball($pos, $near * 3, $wood_ix);
        my $density = $self->{mnm}->density_portion($pos, @near);
        my $max = $self->{mnm_max};
        $self->{mnm_max} = $max = $density if $density > $max;
        # printf "take  -> max: %6g, density: %6g. ratio: %02.7f\n", $max, $density, $density/$max * 100;
        return $self->{kdtree_ixs}[$wood_ix] if $density < rand($max);
    }
    undef
}

sub termite_leave_wood_p {
    my ($self, $termite) = @_;
    my $pos = $termite->{pos};
    my $near = $self->{near};
    my @near = $self->{kdtree}->find_in_ball($pos, $near * 3);
    my $density = $self->{mnm}->density_portion($pos, @near);
    my $max = $self->{mnm_max};
    $self->{mnm_max} = $max = $density if $density > $max;
    # printf "leave -> max: %6g, density: %6g. ratio: %02.7f\n", $max, $density, $density/$max * 100;
    return 1 if $density > rand($max);
    undef;

lib/AI/Termites/PeractioBaro.pm  view on Meta::CPAN


use 5.010;
use strict;
use warnings;

use Math::Vector::Real;
use Math::Vector::Real::kdTree;

use parent 'AI::Termites';

sub before_termites_action {
    my $self = shift;
    my @ixs = grep !$self->{wood}[$_]{taken}, 0..$#{$self->{wood}};
    # say '@ixs: ', scalar @ixs;
    $self->{kdtree_ixs} = \@ixs;
    $self->{kdtree} = Math::Vector::Real::kdTree->new(map $_->{pos}, @{$self->{wood}}[@ixs]);
}

sub termite_take_wood_p {
    my ($self, $termite) = @_;
    my $pos = $termite->{pos};
    my $near = $self->{near};
    my $wood_ix = $self->{kdtree}->find_nearest_neighbor($pos, $near);
    if (defined $wood_ix) {
        # say "one near $pos, $near";
        my $second = $self->{kdtree}->find_nearest_neighbor($pos, $near, $wood_ix);
        return $self->{kdtree_ixs}[$wood_ix] unless defined $second;
        # say "two near $wood_ix - $second";
    }
    undef
}

sub termite_leave_wood_p {
    my ($self, $termite) = @_;
    my $pos = $termite->{pos};
    my $near = $self->{near};
    return defined $self->{kdtree}->find_nearest_neighbor($pos, $near);
    undef;
}

1;

lib/AI/Termites/VicinusOccurro.pm  view on Meta::CPAN

use warnings;

use Math::Vector::Real;
use Math::Vector::Real::kdTree;
use Math::nSphere qw(nsphere_volumen);

use parent 'AI::Termites';

my $nlog2 = -log 2;

sub before_termites_action {
    my $self = shift;
    my @ixs = grep !$self->{wood}[$_]{taken}, 0..$#{$self->{wood}};
    $self->{kdtree_ixs} = \@ixs;
    $self->{kdtree} = Math::Vector::Real::kdTree->new(map $_->{pos}, @{$self->{wood}}[@ixs]);
    # print "dim: $self->{dim}, near: $self->{near}, density: $self->{wood_density}\n";
    $self->{alpha} = $nlog2/(nsphere_volumen($self->{dim} - 1, $self->{near}) * $self->{wood_density});



}

sub termite_take_wood_p {
    my ($self, $termite) = @_;
    my $pos = $termite->{pos};
    my $near = $self->{near};
    my $wood_ix = $self->{kdtree}->find_nearest_neighbor($pos, $near);
    if (defined $wood_ix) {
        my $count = $self->{kdtree}->find_in_ball($pos, $near, $wood_ix);
        if (exp($self->{alpha} * $count) > rand) {
            return $self->{kdtree_ixs}[$wood_ix];
        }
    }
    undef
}

sub termite_leave_wood_p {
    my ($self, $termite) = @_;
    my $pos = $termite->{pos};
    my $near = $self->{near};
    my $count = $self->{kdtree}->find_in_ball($pos, $near);
    if (exp($self->{alpha} * $count) < rand) {
        return 1;
    }
    undef;
}

samples/termites.pl  view on Meta::CPAN

                         "near=s"       => \$near,
                         "one-of=i"     => \$one_of,
                         "width=i"      => \$width,
                         "dim=i"        => \$dim,
                         "taken"        => \$taken,
                         "output=s"     => \$output,
                         "truecolor"    => \$truecolor,
                         "top=i"          => \$top,
                       );

sub scl {
    my $p = shift;
    @{$width * $p}[0, 1];
}

sub sscl {
    my $s = shift;
    $width * $s;
}

$| = 1;

my $class = "AI::Termites::$specie";
eval "require $class; 1" or die "unable to load $class: $@";

my $ters = $class->new(dim => $dim, world_size => $world,



( run in 0.304 second using v1.01-cache-2.11-cpan-a5abf4f5562 )