#!/usr/bin/perl -w
use vars qw($VERSION);
$VERSION = "1.0 - 16 APR 2010";
use strict;
use warnings;
use Getopt::Long qw(:config no_ignore_case); #bundling
use Pod::Usage;
my %opt;
my ($opt_help, $opt_man, $opt_versions);
GetOptions(
'acceleration=i' => \$opt{acceleration},
'delay=i' => \$opt{delay},
'Distances:s' => \$opt{Distances},
'grid=i' => \$opt{size},
'Grid:s' => \$opt{Grid},
'iterations=i' => \$opt{loop},
'Locations:s' => \$opt{Locations},
'signal=f' => \$opt{multiplier},
'Signals:s' => \$opt{Signals},
'help!' => \$opt_help,
'man!' => \$opt_man,
'versions!' => \$opt_versions
) or pod2usage(-verbose => 0);
pod2usage(-verbose => 1) if defined $opt_help;
pod2usage(-verbose => 2) if defined $opt_man;
if(defined $opt_versions){
print
"\nModules, Perl, OS, Program info:\n",
" $0\n",
" Version $VERSION\n",
" strict $strict::VERSION\n",
" warnings $warnings::VERSION\n",
" Pod::Usage $Pod::Usage::VERSION\n",
" Getopt::Long $Getopt::Long::VERSION\n",
" Perl version $]\n",
" Perl executable $^X\n",
" OS $^O\n",
"\n\n";
exit
}
# Start Program
########################################################
if ((!@ARGV) || ($ARGV[0] !~ /^\d+$/)) {
pod2usage(-verbose => 0, -message => "$0: number of nodes required\n")
}
if ($ARGV[0] < 2) {
pod2usage(-verbose => 0, -message => "$0: number of nodes >= 2\n")
}
my @nodes;
my $numnodes = $ARGV[0];
my $delay = $opt{delay} || 0;
my $acceleration = $opt{acceleration} || 2;
$acceleration += 1;
my $size = $opt{size} || 5*$numnodes;
$size -= 1;
my $iterations = $opt{loop} || -1;
my $multiplier = $opt{multiplier} || 1;
if ($size <= $numnodes) {
$size = 5*$numnodes - 1;
}
if ($multiplier <= 0) {
$multiplier = 1
}
# Initialize Nodes
for my $i (1..$numnodes) {
my %coords;
$coords{x} = $coords{y} = int($size/2);
$nodes[$i] = \%coords;
}
my $i = 0;
while ($i++ != $iterations) {
move(\@nodes, $size);
if (defined($opt{Distances}) || defined($opt{Grid}) || defined($opt{Locations}) || defined($opt{Signals})) {
print "---- ITERATION $i ----\n"
}
if (defined($opt{Locations})) {
print "LOCATIONS\n";
print_locations(\@nodes);
if ($opt{Locations} ne '') {
if ($^O eq 'MSWin32') {
system('cls')
} else {
system('clear')
}
}
}
my ($distances, $signals) = compute(\@nodes);
if (defined($opt{Distances})) {
print "DISTANCES\n";
print_metrics(\@nodes, $distances);
if ($opt{Distances} ne '') {
if ($^O eq 'MSWin32') {
system('cls')
} else {
system('clear')
}
}
}
if (defined($opt{Signals})) {
print "SIGNALS\n";
print_metrics(\@nodes, $signals);
if ($opt{Signals} ne '') {
if ($^O eq 'MSWin32') {
system('cls')
} else {
system('clear')
}
}
}
print "UNION/INTERSECTION\n";
print_union(\@nodes, $signals);
if (defined($opt{Grid})) {
print "GRID\n";
print_grid(\@nodes, $size);
if ($opt{Grid} ne '') {
if ($^O eq 'MSWin32') {
system('cls')
} else {
system('clear')
}
}
}
sleep ($delay);
}
########################################
sub compute {
my ($node) = @_;
my @distance;
my @signal;
for my $i (1..$#{$node}) {
for my $j ($i+1..$#{$node}) {
# Pythagoras
$distance[$i][$j] = sqrt(
(($node->[$i]->{x} - $node->[$j]->{x}) *
($node->[$i]->{x} - $node->[$j]->{x}))
+
(($node->[$i]->{y} - $node->[$j]->{y}) *
($node->[$i]->{y} - $node->[$j]->{y}))
);
# Signal by distance
if ($distance[$i][$j] <= 1 * $multiplier) {
$signal[$i][$j] = 5;
} elsif ($distance[$i][$j] <= 2 * $multiplier) {
$signal[$i][$j] = 4;
} elsif ($distance[$i][$j] <= 3 * $multiplier) {
$signal[$i][$j] = 3;
} elsif ($distance[$i][$j] <= 4 * $multiplier) {
$signal[$i][$j] = 2;
} elsif ($distance[$i][$j] <= 5 * $multiplier) {
$signal[$i][$j] = 1;
} else {
$signal[$i][$j] = 0;
}
}
}
return (\@distance, \@signal)
}
sub move {
my ($node, $size) = @_;
for my $i (1..$#{$node}) {
my $speed = int(rand($acceleration));
my $dir = int(rand(9));
if ($speed > 0) {
# Direction is as follows. Node starts at 4
#
# 0 1 2
# 3 4 5
# 6 7 8
#
if ($dir == 0) {
if (($node->[$i]->{x} - $speed) >= 0) {
$node->[$i]->{x} -= $speed
}
if (($node->[$i]->{y} - $speed) >= 0) {
$node->[$i]->{y} -= $speed
}
} elsif ($dir == 1) {
if (($node->[$i]->{y} - $speed) >= 0) {
$node->[$i]->{y} -= $speed
}
} elsif ($dir == 2) {
if (($node->[$i]->{x} + $speed) <= $size) {
$node->[$i]->{x} += $speed
}
if (($node->[$i]->{y} - $speed) >= 0) {
$node->[$i]->{y} -= $speed
}
} elsif ($dir == 3) {
if (($node->[$i]->{x} - $speed) >= 0) {
$node->[$i]->{x} -= $speed
}
} elsif ($dir == 4) {
# no move
} elsif ($dir == 5) {
if (($node->[$i]->{x} + $speed) <= $size) {
$node->[$i]->{x} += $speed
}
} elsif ($dir == 6) {
if (($node->[$i]->{x} - $speed) >= 0) {
$node->[$i]->{x} -= $speed
}
if (($node->[$i]->{y} + $speed) <= $size) {
$node->[$i]->{y} += $speed
}
} elsif ($dir == 7) {
if (($node->[$i]->{y} + $speed) <= $size) {
$node->[$i]->{y} += $speed
}
} elsif ($dir == 8) {
if (($node->[$i]->{x} + $speed) <= $size) {
$node->[$i]->{x} += $speed;
}
if (($node->[$i]->{y} + $speed) <= $size) {
$node->[$i]->{y} += $speed
}
}
}
}
}
sub print_locations {
my ($node) = @_;
for my $i (1..$#{$node}) {
printf "$i => (%i,%i)\n", $node->[$i]->{x}, $node->[$i]->{y}
}
print "\n"
}
sub print_grid {
my ($node, $size) = @_;
my @grid;
for my $i (1..$#{$node}) {
$grid[$node->[$i]->{x}][$node->[$i]->{y}] = $i
}
print "-" for (0..$size+2);
print "\n";
for my $y (0..$size) {
print "|";
for my $x (0..$size) {
printf "%s", defined($grid[$x][$y]) ? $grid[$x][$y] : " "
}
print "|\n"
}
print "-" for (0..$size+2);
print "\n"
}
sub print_metrics {
my ($node, $metric) = @_;
print " ";
for my $i (2..$#{$node}) {
printf "%5i ", $i
}
print "\n ";
for my $i (2..$#{$node}) {
printf "----- ",
}
print "\n";
for my $i (1..$#{$node}-1) {
printf "%2i] ", $i;
for my $j (2..$#{$node}) {
my $p = sprintf "%2.2f", defined($metric->[$i][$j]) ? $metric->[$i][$j] : 9999;
printf "%5s ", ($p == 9999) ? " - " : $p
}
print "\n"
}
print "\n"
}
sub print_union {
my ($node, $signal) = @_;
# PERL CODE found for union/intersection
#
# foreach $e (@a) { $union{$e} = 1 }
# foreach $e (@b) {
# if ( $union{$e} ) { $isect{$e} = 1 }
# $union{$e} = 1;
# }
# @union = keys %union;
# @isect = keys %isect;
my (@srcs, @dsts);
for my $i (1..$#{$node}-1) {
for my $j (2..$#{$node}) {
if (defined($signal->[$i][$j])) {
if ($signal->[$i][$j] > 0) {
push @srcs, $i;
push @dsts, $j;
push @srcs, $j;
push @dsts, $i
}
}
}
}
my %neighbors;
for my $n (1..$#{$node}) {
my @neighbor;
# print "$n -> ";
for my $i (0..$#srcs) {
if ($srcs[$i] == $n) {
# print "$dsts[$i] ";
push @neighbor, $dsts[$i]
}
}
$neighbors{$n} = \@neighbor;
# print "\n"
}
my %allnodes;
my %seen;
my @onstack;
my $FULL= 0;
my $DONE = 0;
my @nodeneigh;
for my $n (1..$#{$node}) {
if (!exists($allnodes{$n})) {
(%seen, @onstack) = ();
while (1) {
if (!exists($seen{$n})) {
$seen{$n} = 1;
$allnodes{$n} = 1;
push @onstack, $n
}
my $a = pop @onstack;
if (!defined($a)) {
last
}
do_it($a, \%neighbors, \%seen, \%allnodes, \@onstack);
if ((my $hshcount = keys %seen) == $#{$node}) {
$FULL = 1;
last
}
if ((my $hshcount = keys %allnodes) == $#{$node}) {
$DONE = 1;
last
}
}
if ($FULL) {
last
} else {
my @temp;
push @temp, $_ for (keys %seen);
$nodeneigh[$n] = \@temp;
if ($DONE) {
last
}
}
}
}
if ($FULL) {
print "FULL\n"
} else {
for my $i (@nodeneigh) {
my $NEWLINE;
for my $j (@{$i}) {
if (defined($j)) {
print "$j ";
$NEWLINE = 1
}
}
if ($NEWLINE) {
print "\n"
}
}
}
print "\n";
sub do_it {
my ($n, $neighbors, $seen, $allnodes, $onstack) = @_;
for my $neighbor (@{$neighbors->{$n}}) {
if (!exists($seen->{$neighbor})) {
$seen->{$neighbor} = 1;
$allnodes->{$neighbor} = 1;
push @{$onstack}, $neighbor;
do_it($neighbor, $neighbors, $seen, $allnodes, $onstack)
}
}
}
}
########################################################
# End Program
__END__
=head1 NAME
MANET - Simulate MANET
=head1 SYNOPSIS
manet [options] nodes
=head1 DESCRIPTION
Mobile Ad-Hoc Network (MANET) simulator takes a variable number of
nodes and creates an appropriate grid size to randomly move the nodes
about. Distance and signal strength are computed for each iteration
of node moves.
=head1 ARGUMENTS
nodes The number of nodes.
=head1 OPTIONS:
-a # Use # as an optional acceleration multiplier for
--acceleration each node move. A random number x: 0 <= x <= #
is chosen to accelerate the move in the randomly
selected direction for each node on each iteration.
DEFAULT: (or not specified) 2.
-D [1] Print distance between each node matrix.
--Distances Optional argument causes screen refresh after each
iteration.
-g # Force grid size of # x #. nodes < # < MAX_INT
--grid DEFAULT: (or not specified) nodes*5 x nodes*5.
-G [1] Print visual representation of grid with nodes.
-Grid Optional argument causes screen refresh after each
iteration.
-i # Run the simulation # times.
-iterations DEFAULT: (or not specified) Loop forever.
-L [1] Print node coordinates.
-Locations Optional argument causes screen refresh after each
iteration.
-s # Signal multiplier. There are 6 signal levels:
-signal 0 = no signal
1 = weak
2 = weak-to-moderate
3 = moderate
4 = moderate-to-strong
5 = strong
By default, signal is inversely proportional to
node distance.
Distance between nodes <= 1 --> Signal 5
Distance between nodes <= 2 --> Signal 4
Distance between nodes <= 3 --> Signal 3
Distance between nodes <= 4 --> Signal 2
Distance between nodes <= 5 --> Signal 1
Distance between nodes > 5 --> Signal 0
This option # allows for a floating point number
multiplier to adjust signal calculation as below:
Distance between nodes <= 1 * # --> Signal 5
Distance between nodes <= 2 * # --> Signal 4
Distance between nodes <= 3 * # --> Signal 3
Distance between nodes <= 4 * # --> Signal 2
Distance between nodes <= 5 * # --> Signal 1
Distance between nodes > 5 * # --> Signal 0
DEFAULT: (or not specified) 1.
-S [1] Print signal strenght between each node matrix.
-Signals Optional argument causes screen refresh after each
iteration.
--help Print Options and Arguments.
--man Print complete man page.
--versions Print Modules, Perl, OS, Program info.
=head1 LICENSE
This software is released under the same terms as Perl itself.
If you don't know what that means visit L.
=head1 AUTHOR
Copyright (C) Michael Vincent 2010
L
All rights reserved
=cut