package Sim::OPT;
# Copyright (C) 2008-2018 by Gian Luca Brunetti and Politecnico di Milano.
# This is Sim::OPT, a program managing building performance simulation programs for performing optimization by block coordinate search.
# This is free software.  You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.

use v5.14;
# use v5.20;
use Exporter;
use parent 'Exporter'; # imports and subclasses Exporter

use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS );
use Math::Trig;
use Math::Round;
use List::Util qw[ min max reduce shuffle];
use List::MoreUtils qw(uniq);
use List::AllUtils qw(sum);
use Statistics::Basic qw(:all);
use Storable qw(lock_store lock_nstore lock_retrieve dclone);
use IO::Tee;
use File::Copy qw( move copy );
use Set::Intersection;
use List::Compare;
use Data::Dumper;
use POSIX;
#use Parallel::ForkManager;
#$Data::Dumper::Indent = 0;
#$Data::Dumper::Useqq  = 1;
#$Data::Dumper::Terse  = 1;d
use Data::Dump qw(dump);
use feature 'say';
#use feature qw(postderef);
#no warnings qw(experimental::postderef);
#use Sub::Signatures;
#no warnings qw(Sub::Signatures);
#no strict 'refs';
no strict;
no warnings;
use warnings::unused;
use Sim::OPT::Morph;
use Sim::OPT::Sim;
use Sim::OPT::Report;
use Sim::OPT::Descend;
use Sim::OPT::Takechance;
use Sim::OPT::Parcoord3d;
use Sim::OPT::Interlinear;

our @ISA = qw( Exporter ); # our @adamkISA = qw(Exporter);
#%EXPORT_TAGS = ( DEFAULT => [qw( &opt &prepare )]); # our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
#@EXPORT   = qw(); # our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

our @EXPORT = qw(
opt takechance
odd even _mean_ flattenvariables count_variables fromopt_tosweep fromsweep_toopt convcaseseed
convchanceseed makeflatvarnsnum calcoverlaps calcmiditers definerootcases
callcase callblock deffiles makefilename extractcase setlaunch exe start
_clean_ getblocks getblockelts getrootname definerootcases populatewinners
getitem getline getlines getstepsvar tell wash flattenbox enrichbox filterbox givesize
$configfile $mypath $exeonfiles $generatechance $file $preventsim $fileconfig $outfile $tofile $report
$simnetwork @themereports %simtitles %reporttitles %retrievedata
@keepcolumns @weights @weightsaim @varthemes_report @varthemes_variations @varthemes_steps
@rankdata @rankcolumn @reporttempsdata @reportcomfortdata %reportdata
@report_loadsortemps @files_to_filter @filter_reports @base_columns @maketabledata @filter_columns
@files_to_filter @filter_reports @base_columns @maketabledata @filter_columns %vals
@sweeps @miditers @varnumbers @caseseed @chanceseed @chancedata $dimchance $tee @pars_tocheck retrieve
report newretrieve newreport washn
$target %dowhat readsweeps $max_processes $computype $calcprocedure %specularratios @totalcases @winneritems);

$VERSION = '0.97';
$ABSTRACT = 'Sim::OPT is an optimization and parametric exploration program oriented to problem decomposition. It can be used with simulation programs receiving text files as input and emitting text files as output. It allows a free mix of sequential and parallel block coordinate searches.';

#################################################################################
# Sim::OPT
#################################################################################

# FUNCTIONS' SPACE
###########################################################
###########################################################


sub checkdone
{
	my $term = shift;
	my @arr = @{ shift( @_ ) };
	foreach my $elm ( @arr )
	{
		if ( $elm =~ /$term/ )
		{
			return( "yes" );
		}
	}
}

sub odd
{
    my $number = shift;
    return !even ($number);
}

sub even
{
    my $number = abs shift;
    return 1 if $number == 0;
    return odd ($number - 1);
}

sub odd__
{
  my ( $number ) = @_;
  if ( $number % 2 == 1 )
  {
    return ( "odd" );
  }
  else
  {
    return ( "even" );
  }
}

sub _mean_ { return @_ ? sum(@_) / @_ : 0 }

sub rotate2d
{ # SELF-EXPLAINING. IT IS HERE TO BE CALLABLE READILY FROM THE OUTSIDE
    my ( $x, $y, $angle ) = @_;

    sub deg2rad
    {
	my $degrees = shift;
	return ( ( $degrees / 180 ) * 3.14159265358979 );
    }

    sub rad2deg
    {
	my $radians = shift;
	return ( ( $radians / 3.14159265358979 ) * 180 ) ;
    }

    $angle = deg2rad( $angle );
    my $x_new = cos($angle)*$x - sin($angle)*$y;
    my $y_new = sin($angle)*$x + cos($angle)*$y;
  return ( $x_new, $y_new);
}

sub countarray
{
	my $c = 1;
	foreach (@_)
	{
		foreach (@$_)
		{
			$c++;
		}
	}
	return ($c); # TO BE CALLED WITH: countarray(@array)
}

sub countnetarray
{
	my @bag;
	foreach (@_)
	{
		foreach (@$_)
		{
			push (@bag, $_);
		}
	}
	@bag = uniq(@bag);
	return scalar(@bag); # TO BE CALLED WITH: countnetarray(@array)
}

sub sorttable # TO SORT A TABLE ON THE BASIS OF A COLUMN
{
	my $num = $_[0];
	my @table = @{ $_[1] };
	my @rows;
	foreach my $line (@table)
	{
	    chomp $line;
	    $sth->execute(line);

	    my @row = $sth->fetchrow_array;
	    unshift (@row, $line);
	    push @rows, \@row;
	}

	@rows = sort { $a->[$num] cmp $b->[$num] } @rows;

	foreach my $row (@rows) {
	    foreach (@$row) {
		print "$_";
	    }
	    print "\n";
	} #TO BE CALLED WITH: sorttable( $number_of column, \@table);
	return (@table);
}

sub _clean_
{ # IT CLEANS A BASKET FROM CASES LIKE "-", "1-", "-1", "".
	my $swap = shift;
	my @arraytoclean = @$swap;
	my @storeinfo;
	foreach (@arraytoclean)
	{
		$_ =~ s/ //;
		unless ( !( defined $_) or ($_ =~ /^-/) or ($_ =~ /-$/) or ($_ =~ /^-$/) or ($_ eq "") or ($_ eq "-") )
		{
			push(@storeinfo, $_)
		}
	}
	return  @storeinfo; # HOW TO CALL THIS FUNCTION: clean(\@arraytoclean). IT IS DESTRUCTIVE.
}

sub present
{
	foreach (@_)
	{
		say "### $_ : " . dump($_);
		say TOFILE "### $_ : " . dump($_);
	}
}


sub flattenvariables # THIS LISTS THE NUMBER OF VARIABLES PLAY IN A LIST OF BLOCK SEARCHES. ONE COUNT FOR EACH LIST ELEMENT.
{
	my @array = @_;
	foreach my $case (@array)
	{
		@casederef = @$case;
		my @basket;
		foreach my $block (@casederef)
		{
			@blockelts = @$block;
			push (@basket, @blockelts);
		}
		my @basket = sort { $a <=> $b} uniq(@basket);
		push ( @flatvarns, \@basket ); ###
		# IT HAS TO BE CALLED WITH: flatten_variables(@treeseed);
	}
}

sub count_variables # IT COUNTS THE FLATTENED VARIABLES
{
	my @flatvarns = @_;
	foreach my $group (@flatvarns)
	{
		my @array = @$group;
		push ( @flatvarnsnum, scalar(@array) );
		# IT HAS TO BE CALLED WITH: count_variables(@flatvarns);
	}
}

# flatten_variables ( [ [1, 2, 3] , [2, 3, 4] , [3, 4, 5] ], [ [1, 2], [2, 3] ] );
#count_variables ([1, 2, 3, 4, 5], [1, 2, 3]);


sub fromopt_tosweep # IT CONVERTS A TREE BLOCK SEARCH FORMAT IN THE ORIGINAL OPT'S BLOCKS SEARCH FORMAT.
{
	my %thishash = %{ $_[0] };
	my @casegroup = @{ $thishash{casegroup} } ;
	my @chancegroup = @{ $thishash{chancegroup} };
	my @sweeps;
	my $countcase = 0;
	foreach my $case (@casegroup)
	{
		my @blockrefs = @$case;
		my @chancerefs = @{ $chancegroup[$countcase] };
		my @sweepblocks;
		my $countblock = 0;
		foreach my $elt (@blockrefs)
		{
			my @blockelts = @$elt;
			my $attachpoint = $blockelts[0];
			my $blocklength = $blockelts[1];
			my @chances = @{ $chancerefs[$countblock] };
			my @sweepblock = @chances[ $attachpoint .. ($attachpoint + $blocklength - 1) ];
			push (@sweepblocks, [@sweepblock]);
			$countblock++;
		}
		push (@sweeps, [ @sweepblocks ] );
		$countcase++;
	}
	# IT HAS TO BE CALLED THIS WAY: fromopt_tosweep( { casegroup => \@caseseed, chancegroup => \@chanceseed } );
	return (@sweeps);
}

sub fromopt_tosweep_simple # IT CONVERTS A TREE BLOCK SEARCH FORMAT IN THE ORIGINAL OPT'S BLOCKS SEARCH FORMAT.
{
	my %thishash = @_;
	my $casegroupref = $thishash{casegroup};
	my @blocks = @$casegroupref;
	my $chancegroupref = $thishash{chancegroup};
	my @chances = @$chancegroupref;
	my $countblock = 0;
	foreach my $elt (@blocks)
	{
		my @blockelts = @$elt;
		my $attachpoint = $blockelts[0];
		my $blocklength = $blockelts[1];
		my $chancesref = $chances[$countblock];
		my @chances = @$chancesref;
		my @sweepblock = @chances[ $attachpoint .. ($attachpoint + $blocklength - 1) ];
		push (@sweepblocks, [@sweepblock]);
		$countblock++;
	}
	# IT HAS TO BE CALLED THIS WAY: fromopt_tosweep( casegroup => [@caserefs_alias], chancegroup => [@chancerefs_alias] ); # IT IS NOT RELATIVE TO CASE: JUST ONE CASE, THE CURRENT.
	return (@sweepblocks);
}

sub checkduplicates
{
	my %hash = %{$_[0]};
	my @slice = @{$hash{slice}};
	my @sweepblocks = @{$hash{sweepblocks}};
	my $signal = 0;
	foreach my $blockref (@sweepblocks)
	{
		@block = @$blockref;
		if ( @slice ~~ @block )
		{
			$signal++;
		}
	}
	if ($signal == 0) { return "no"; }
	else { return "yes" };
}


sub fromsweep_toopt # IT CONVERTS THE ORIGINAL OPT'S BLOCKS SEARCH FORMAT IN A TREE BLOCK SEARCH FORMAT.
{
	my ( @bucket, @secondbucket );
	my $countcase = 0;
	foreach (@_) # CASES
	{
		my ( @blocks, @chances );
		my $countblock = 0;
		foreach(@$_) # BLOCKS
		{

			my $swap = $flatvarns[$countcase];
			my @varns = @$swap;
			my @block = @$_;
			my $blocksize = scalar(@block);
			my $lc = List::Compare->new(\@varns, \@block);
			my @intersection = $lc->get_intersection;
			my @nonbelonging;
			foreach (@varns)
			{
				my @parlist;
				unless ($_ ~~ @intersection)
				{
					push (@nonbelonging, $_);
				}
			}

			push (@blocks, [@intersection, @nonbelonging] );
			push (@chances, [0, $blocksize] );
			$countblock++;
		}
		push (@bucket, [ @blocks ] );
		push (@secondbucket, [@chances]);
		$countcase++;
	}
	@chanceseed = @bucket;
	@caseseed = @secondbucket;
	return (\@caseseed, \@chanceseed);
	# IT HAS TO BE CALLED THIS WAY: fromsweep_toopt(@sweep);
}


sub convcaseseed # IT ADEQUATES THE POINT OF ATTACHMENT OF EACH BLOCK TO THE FACT THAT THE LISTS CONSTITUTING THEM ARE THREE, JOINED.
{
	my $ref = shift;
	my %hash = %{$ref};
	my @chanceseed = @{ $hash{ chanceseed } };
	my @caseseed = @{ $hash{ caseseed } };
	my $countcase = 0;
	foreach my $case (@caseseed)
	{
		my $chance = $chanceseed[$countcase];
		my $countblock = 0;
		my @blockrefs = @$case;
		my @chancerefs = @$chance;
		foreach (@blockrefs)
		{
			my $chancelt = scalar ( @{ $chancerefs[$countblock] } );
			my $numofelts = ( $chancelt / 3 );
			${$_}[0] = ${$_}[0] + $numofelts;
			$countblock++;
		}
		$countcase++;
	} # TO BE CALLED WITH: convcaseseed(\@caseseed, \@chanceseed). @caseseed IS globsAL. TO BE CALLED WITH: convcaseseed(@caseseed);
	return(@caseseed);
}


sub convchanceseed # IT COUNTS HOW MANY PARAMETERS THERE ARE IN A SEARCH STRUCTURE,
{
	foreach (@_)
	{
		foreach (@$_)
		{
			push (@$_, @$_, @$_);
		}
	} # IT HAS TO BE CALLED WITH convchanceseed(@chanceseed). IT ACTS ON @chanceseed, WHICH IS globsAL.
	return(@_);
}


sub tellnum
{
	@arr = @_;
	my $response = (scalar(@_)/2);
	return($response); # TO BE CALLED WITH tellnum(%varnums);
}


sub calcoverlaps
{
	my @sweeps = @_;
	my ( @caseoverlaps );
	my $countcase = 0;
	foreach my $case ( @sweeps )
	{
		my @caseelts = @{ $case };
		my $countblock = 0;
		foreach my $block ( @caseelts )
		{
			my @pasttblock = @{ $block[ $countblock - 1 ]};
			my @presentblock = @{ $block[ $countblock ]};
			my $lc = List::Compare->new( \@pastblock, \@presentblock );
			my @intersection = $lc->get_intersection;
			push ( @caseoverlaps, [ @intersection ] );
			$countblock++;
		}
		$countcase++;
	}
	return( @caseoverlaps );
}


sub calcmiditers
{
	my @varnumbers = @_;
	my $countcase = 0;
	my @mediters;
	foreach ( @varnumbers )
	{
		my $countblock = 0;
		foreach ( keys %$_ )
		{
			unless ( defined $mediumters[$countcase]{$_} )
			{
				$mediters[$countcase]{$_} = ( ceil( $varnumbers[$countcase]{$_} / 2 ) );
			}
		}
		$countcase++;
	} # TO BE CALLED WITH: calcmiditers(@varnumbers)
	return ( @mediters );
}


sub getitersnum
{ # IT GETS THE NUMBER OF ITERATION. UNUSED. CUT
	my $countcase = shift;
	my $varnumber = shift;
	my @varnumbers = @_;
	my $itersnum = $varnumbers[$countcase]{$varnumber};

	return $itersnum;
	# IT HAS TO BE CALLED WITH getitersnum($countcase, $varnumber, @varnumbers);
}


sub makefilename # IT DEFINES A FILE NAME GIVEN A %carrier.
{
	my %carrier = @_;
	my $filename = "$mypath/$file" . "_";
	my $countcase = 0;
	foreach my $key (sort {$a <=> $b} (keys %carrier) )
	{
		$filename = $filename . $key . "-" . $carrier{$key} . "_";
	}
	return ($filename); # IT HAS TO BE CALLED WITH: makefilename(%carrier);
}


sub getblocks
{ # IT GETS @blocks. TO BE CALLED WITH getblocks(\@sweeps, $countcase)
	my $swap = shift;
	my @sweeps = @$swap;
	my $countcase = shift;
	my @blocks = @{ $sweeps[$countcase]};
	return (@blocks);
}

#@blocks = getblocks(\@sweeps, 0);  say "dumpA( \@blocks) " . dump(@blocks);

sub getblockelts
{ # IT GETS @blockelts. TO BE CALLED WITH getblockelts(\@sweeps, $countcase, $countblock)
	my ( $sweeps_ref, $countcase, $countblock ) = @_;
	my @sweeps = @{ $sweeps_ref };
	my @blockelts = sort { $a <=> $b } @{ $sweeps[$countcase][$countblock] };
	return ( \@blockelts );
}


sub getrootname
{
	my $swap = shift;
	my @rootnames = @$swap;
	my $countcase = shift;
	my $rootname = $rootnames[$countcase];
	return ($rootname);
}


sub extractcase # IT EXTRACTS THE ITEMS TO BE CHANCED FROM A  %carrier, UPDATES THE FILE NAME AND CREATES THE NEW ITEM'S CARRIER
{
	my $file = shift;
	my $carrierref = shift;
	my @carrierarray = %$carrierref;
	my %carrier = %$carrierref;
	my $num = ( scalar(@carrierarray) / 2 );
	my $transfile = $file;
	$transfile = "_" . "$transfile";
	my $counter = 0;
	my %provhash;
	while ($counter < $num)
	{
		$transfile =~ /_(\d+)-(\d+)_/;
		if ( ($1) and ($2) )
		{
			$provhash{$1} = "$2";
		}
		$transfile =~ s/$1-$2//;
		$counter++;
	}
	foreach my $key (keys %provhash)
	{
		$carrier{$key} = $provhash{$key};
	}
	my $to = makefilename(%carrier);
	return($to, \%carrier); # IT HAS TO BE CALLED WITH: extractcase("$string", \%carrier), WHERE STRING IS A PIECE OF FILENAME WITH PARAMETERS.
}


sub definerootcases #### DEFINES THE ROOT-CASE'S NAME.
{
	my @sweeps = @{ $_[0] }; #say $tee "\@sweeps IN DEFINEROOTCASES " . dump( @sweeps );
	my @miditers = @{ $_[1] }; #say $tee "\@miditers IN DEFINEROOTCASES " . dump( @miditers );
	my @rootnames;
	my $countcase = 0;
	foreach my $sweep (@sweeps)
	{
		my $case = $miditers[$countcase];
		my %casetopass;
		my $rootname;
		foreach my $key (sort {$a <=> $b} (keys %$case) )
		{
			$casetopass{$key} = $miditers[$countcase]{$key};
		}
		foreach $key (sort {$a <=> $b} (keys %$case) )
		{
			$rootname = $rootname . $key . "-" . $miditers[$countcase]{$key} . "_";
		}
		$rootname = "$file" . "_" . "$rootname";
		$casetopass{rootname} = $rootname;
		chomp $rootname;
		push ( @rootnames, $rootname);
		$countcase++;
	}
	return (@rootnames); # IT HAS TO BE CALLED WITH: definerootcase(@miditers).
}


sub populatewinners
{
	my @rootnames = @{ $_[0] };
	my $countcase = $_[1];
	my $countblock = $_[2];
	my @winneritems;
	foreach my $case ( @rootnames )
	{
		push ( @{ $winneritems[$countcase][$countblock] }, $case );
		$countcase++;
	}
	return( @winneritems );
}


sub getitem
{ # IT GETS THE WINNER OR LOSER LINE. To be called with getitems(\@winner_or_loser_lines, $countcase, $countblock)
	my $swap = shift;
	my @items = @$swap;
	my $countcase = shift;
	my $countblock = shift;
	my $item = $items[$countcase][$countblock];
	my @arr = @$item;
	my $elt = $arr[0];
	return ($elt);
}


sub getitem
{ # IT GETS THE WINNER OR LOSER LINE. To be called with getitems(\@winner_or_loser_lines, $countcase, $countblock)
	my $swap = shift;
	my @items = @$swap;
	my $countcase = shift;
	my $countblock = shift;
	my $item = $items[$countcase][$countblock];
	my @arr = @$item;
	my $elt = $arr[0];
	return ($elt);
}





sub getline
{
	my $item = shift;
	my $file = "$mypath/" . "$item";
	return ($file);
}


sub getlines
{
	my $swap = shift;
	my @items = @$swap;
	my @arr;
	my $countcase = 0;
	foreach (@items)
	{
		foreach ( @{ $_ } )
		{
			push ( @{ $arr[$countcase] } , getline($_) );
		}
		$countcase++;
	}
	return (@arr);
}


sub washn
{
	my ( @arr ) = @_;
	if ( ref( @arr[0] ) eq "ARRAY" )
	{
		@arr = @{ $arr[0] }; #say $tee "335 getcase \$itemref " . dump( $itemref );
	}
	return( @arr );
}


sub getcase
{
	my ( $varn_r, $countcase ) = @_; #say $tee "333 getcase \$countcase " . dump( $countcase );
	my @varnumbers = @{ $varn_r }; #say $tee "333 getcase \@varnumbers " . dump( @varnumbers );
	my ( $itemref, %item);
	if ( ref( @varnumbers[0] ) eq "HASH" )
	{
		$itemref = $varnumbers[$countcase]; #say $tee "333 getcase \$itemref " . dump( $itemref );
		%item = %{ $itemref }; #say $tee "333 getcase \%item " . dump( %item );
	}
	else
	{
		@varnumbers = @{ $varnumbers[$countcase] }; #say $tee "335 getcase \$itemref " . dump( $itemref );
	  $itemref = $varnumbers[$countcase]; #say $tee "335 getcase \$itemref " . dump( $itemref );
	  my %item = %{ $itemref }; #say $tee "335 getcase \%item " . dump( %item );
	} #say $tee "333 getcase leaving \@varnumbers " . dump( @varnumbers );
	return ( %item );
}


sub getstepsvar
{ 	# IT EXTRACTS $stepsvar
	my ( $countvar, $countcase, $varnumbers_r ) = @_; #say $tee "555 getstepsvar \$countvar " . dump( $countvar );
	my @varnumbers = @{ $varnumbers_r }; #say $tee "555 getstepsvar \@varnumbers" . dump( @varnumbers );
	#say $tee "555 getstepsvar \$varnumbers[ \$countcase ]" . dump( $varnumbers[ $countcase ] );
	my %varnums = getcase( \@varnumbers, $countcase ); #say $tee "555 getstepsvar \%varnums" . dump( %varnums );
	my $stepsvar = $varnums{$countvar}; #say $tee "555 getstepsvar \$stepsvar" . dump( $stepsvar );
	return ( $stepsvar )
} #getstepsvar($countvar, $countcase, \@varnumbers);


sub givesize
{	# IT RETURNS THE SEARCH SIZE OF A BLOCK.
	my $sliceref = shift;
	my @slice = @$sliceref;
	my $countcase = shift;
	my $varnumberref = shift;
	my $product = 1;
	foreach my $elt (@slice)
	{
		my $stepsize = Sim::OPT::getstepsvar($elt, $countcase, $varnumberref);
		$product = $product * $stepsize;
	}
	return ($product); # TO BE CALLED WITH: givesize(\@slice, $countcase, \@varnumbers);, WHERE SLICE MAY BE @blockelts in SIM::OPT OR @presentslice OR @pastslice IN Sim::OPT::Takechance
}


sub wash # UNUSED. CUT.
{
	my @instances = @_;
	my @bag;
	my @rightbag;
	foreach my $instanceref (@instances)
	{
		my %d = %{ $instanceref };
		my $to = $d{to};
		push (@bag, $to);
	}
	my $count = 0;
	foreach my $instanceref (@instances)
	{
		my %d = %{ $instanceref };
		my $to = $d{to};
		if ( not ( $to ~~ @bag ) )
		{
			push ( @rightbag, \%d );
		}
	}
	return (@rightbag); # TO BE CALLED WITH wash(@instances);
}


sub flattenbox
{
	my @basket;
	foreach my $eltsref (@_)
	{
		my @elts = @$eltsref;
		push (@basket, @elts);
	}
	return(@basket);
}


sub integratebox
{
	my @arrelts = @{ $_[0] };
	my %carrier = %{ $_[1] };
	my $file = $_[2];
	my @newbox;
	foreach my $eltref ( @arrelts )
	{
		my @elts = @{ $eltref };
		my $target = $elts[0];
		my $origin = $elts[3];
		my @result = extractcase( $target, \%carrier );
		my $righttarget = $result[0];
		my @result = extractcase( $origin, \%carrier );
		my $rightorigin = $result[0];
		push (@newbox, [ $righttarget, $elts[1], $elts[2], $rightorigin ] );
	}
	return (@newbox); # TO BE CALLED WITH: integratebox(\@flattened, \%mids), $file); # %mids is %carrier. $file is the blank root folder.
}


sub filterbox
{
	@arr = @_;
	my @basket;
	my @box;
	foreach my $case ( @arr )
	{
		my $elt = $case->[0];
		if ( not ( $elt ~~ @box ) )
		{
			my @bucket;
			foreach my $caseagain ( @arr )
			{
				my $el = $caseagain->[0];
				if ( $elt ~~ $el )
				{
					push ( @bucket, $case );
				}
			}
			my $parent = $bucket[0];
			push ( @basket, $parent );
			foreach ( @basket )
			{	my %varnums = %{ $varnumsref };

				push ( @box, $_->[0] );
			}
		}
	}
	return( @basket );
}


sub tellstring
{
	my ( $mids_ref, $file ) = @_;
	my %mids = %{ $mids_ref };
	my $starstring;
	foreach my $key ( sort {$a <=> $b} ( keys %mids ) )
	{
		$starstring = "$starstring" . "$key" . "-" . $mids{$key} . "_";
	}
	if ( $starstring ne "" )
	{
		$starstring = $file . "_" . $starstring;
	}
	return( $starstring );
}


sub prunethis
{
	my $aref = shift;
	my @arr = @{ $aref };
	my @newarr = map
	{
		if ( ref( $_ ) )
		{ prunethis( $_ ); }
		elsif ( $_ =~/>/ )
		{
			();
		}
		else
		{
			$_;
		}
	} @arr;
	return ( \@newarr );
}


sub cleansweeps
{
	my @struct = @{ $_[0] };
	my @sourcestruct = @{ dclone( \@struct ) };
	my @outbag;
	foreach my $e ( @struct )
	{
		my @midbag;
		foreach my $el ( @{ $e } )
		{
			my @inbag;
			foreach my $elt ( @{ $el } )
			{
				$elt =~ s/>// ;
				$elt =~ s/[A-za-z]+//g ;
				push( @inbag, $elt );
			}
			push( @midbag, [ @inbag ] );
		}
		push( @outbag, [ @midbag ] );
	}
	return ( \@outbag, \@sourcestruct );
}


sub gencen
{
  my @varnums =  @{ $_[0] };
  my @newmids;
  foreach my $hs_ref ( @varnums )
  {
    my %newhs;
    my %hs = %{ $hs_ref };
    foreach my $key ( sort { $a <=> $b } ( keys %hs ) )
    {
      my $newval = ( int( $hs{$key} / 2 ) + 1 );
      $newhs{$key} = $newval;
    }
    push( @newmids, \%newhs );
  }
  return( \@newmids );
}


sub genextremes
{
  my @varnums =  @{ $_[0] };
  my @newmids;
  foreach my $hs_ref ( @varnums )
  {
    my %newhs;
    my %hs = %{ $hs_ref };
    foreach my $key ( sort { $a <=> $b } ( keys %hs ) )
    {
      my $newval = 1 ;
      $newhs{$key} = $newval;
    }
    push( @newmids, \%newhs );
    push( @newmids, \%hs );
  }
  return( \@newmids );
}


sub gencentres
{
  my ( $vars_ref ) =  @_;
  my @vars = @{ $vars_ref };
  my @varcopy = @vars;
  my $numelts = scalar( @vars );
  my $numcases = ( $numelts / 2 );
  my $c = 0;
  while ( $c < ( $numelts -1 ) )
  {
    my %newhs;
    my @box;
    my %hsmin = %{ $vars[$c] };
    my %hsmax = %{ $vars[$c+1] };
    my $signal = 0;
    my $inv;
    foreach my $key ( sort { $a <=> $b } ( keys %hsmax ) )
    {
      my $newval = ( int( ( $hsmax{$key} - $hsmin{$key} ) / 2 ) + $hsmin{$key} ) ; #say "\$newval: " . dump ( $newval );
      if ( ( $newval == $hsmax{$key} ) or ( $newval == $hsmin{$key} ) )
      {
        my @newpair;
        my $answer = odd__( $signal ); #say "\$answer: " . dump ( $answer );
        if ( $answer eq "even" )
        {
          $value = $array[ int(rand(@array)) ];
          my @ar = ( $hsmax{$key}, $hsmin{$key} );
          $newval = $ar[ int( rand( @ar ) ) ]; #say "newpair1: " . dump ( @newpair );
          if ( $hsmax{$key} == $newval )
          {
            $inv = "no";
          }
          else
          {
            $inv = "yes";
          }
        }
        else
        {
          if ( $inv = "no" )
          {
            @newpair = ( $hsmin{$key}, $hsmax{$key} ); #say "newpair 2: " . dump ( @newpair );
          }
          else
          {
            @newpair = ( $hsmax{$key}, $hsmin{$key} ); #say "newpair 3: " . dump ( @newpair );
          }
          $newval = $newpair[0];
        }
        $signal++;
      }
      $newhs{$key} = $newval;
    }
    splice( @varcopy, ( ( $c * 2 ) + 1 ), 0, \%newhs );
    $c++;
  }
  return( \@varcopy );
}


sub starsweep
{
  my ( $varns_r, $sweeps_r ) = @_;
  my %firstvarn = %{ $varns_r->[0] }; #say $tee "IN STARSWEEP \%firstvarn: " . dump( \%firstvarn );
  my @firstsweep = @{ shift( @{ $sweeps_r } ) }; #say $tee "IN STARSWEEP \@firstsweep: " . dump( \@firstsweep );
	my @restsweeps = @{ $sweeps_r }; #say $tee "IN STARSWEEP \@restsweeps: " . dump( \@restsweeps );
	my ( @box );
  foreach $par ( sort { $a <=> $b } ( keys %firstvarn ) )
  {
		push( @box, [ $par ] ); #say "\$par: " . dump( \$par );
  } #say "\@box: " . dump( \@box );
  unshift( @restsweeps, ( [ @box ] ) ); #say "\@sweeps: " . dump( \@sweeps );
  return( \@restsweeps );  #say $tee "IN STARSWEEP \@restdirs: " . dump( \@restdirs );  say $tee "IN STARSWEEP \@restords: " . dump( \@restords );
}


sub readsweeps
{
	my @struct = @_;
	my @sourcestruct = @{ dclone( \@struct ) };
	foreach ( @struct )
	{
		foreach ( @$_ )
		{
			#prunethis( $_ );
			;
		}
	}
	return ( \@struct, \@sourcestruct );
}


sub stararrange
{
	my ( $sweeps_ref, $blockelts_ref, $varnumbers_ref, $countcase, $countblock, $file ) = @_;
	my @sweeps = @{ $sweeps_ref };
	my @blockelts = @{ $blockelts_ref };
	my @varnumbers = @{ $varnumbers_ref }; #say $tee "IN STARARRANGE \@varnumbers " . dump( @varnumbers );
	my %varnums = getcase( \@varnumbers, $countcase );
	my @vars = ( keys %varnums );
	my @diffs = Sim::OPT::Interlinear::diff( \@vars, \@blockelts ); #say $tee "IN STARARRANGE @diffs " . dump( @diffs );

	my @newhash;
	foreach my $var ( @blockelts )
	{
		push( @newhash, $var );
		push( @newhash, $varnums{$var} );
	}

	foreach my $diff ( @diffs )
	{
		push( @newhash, $diff );
		push( @newhash, 1 );
	} #say $tee "IN STARARRANGE \@newhash " . dump( @newhash );
	my %temp = @newhash; #say $tee "IN STARARRANGE \%temp " . dump( \%temp );
	$varnumbers[$countcase] = \%temp; #say $tee "IN STARARRANGE \$varnumbers[\$countcase] " . dump( $varnumbers[$countcase] );
	return( \@varnumbers );
}


sub callblock # IT CALLS THE SEARCH ON BLOCKS.
{
	my %d = %{ $_[0] };
	my $countcase = $d{countcase}; say $tee"IN callblock ( \$countcase) " . dump($countcase);
	my $countblock = $d{countblock}; say $tee"IN callblock ( \$countblock) " . dump($countblock);
	my @sweeps = @{ $d{sweeps} }; say $tee"IN callblock \@sweeps " . dump(@sweeps);
	my @sourcesweeps = @{ $d{sourcesweeps} }; say $tee"IN callblock \@sourcesweeps " . dump(@sourcesweeps);
	my @miditers = @{ $d{miditers} }; say $tee "IN callblock \@miditers " . dump( @miditers );
	my @winneritems = @{ $d{winneritems} }; say $tee "IN callblock \@winneritems " . dump( @winneritems );
	my %dirfiles = %{ $d{dirfiles} }; #say $tee "IN callblock \%dirfiles " . dump( %dirfiles );
	my %datastruc = %{ $d{datastruc} };
	my %dowhat = %{ $d{dowhat} }; #say $tee "IN callblock \%dowhat" . dump( %dowhat );
	my @varnumbers = @{ $d{varnumbers} }; say $tee"IN callblock ( \@varnumbers) " . dump( @varnumbers );

	if ( $countcase > $#sweeps )# NUMBER OF CASES OF THE CURRENT PROBLEM
  {
    exit(say $tee "#END RUN.");
  }

	my $rootname = getrootname(\@rootnames, $countcase);
	my @blockelts = @{ getblockelts( \@sweeps, $countcase, $countblock ) }; say $tee "IN callblock \@blockelts " . dump( @blockelts );

	my @sourceblockelts = @{ getblockelts( \@sourcesweeps, $countcase, $countblock ) }; say $tee "IN callblock \@sourceblockelts " . dump( @sourceblockelts );


	my $entryname;
	if ( $sourceblockelts[0] =~ /^([A-Za-z]+)/ )
	{
		$entryname = $1;
		$dirfiles{entryname} = $entryname;
	}
	else
	{
		$dirfiles{entryname} = "";
	} say $tee "IN callblock 2 \$entryname " . dump( $entryname );


	my $exitname;
	if ( $sourceblockelts[-1] =~ /([A-Za-z]+)$/ )
	{
		$exitname = $1;
		$dirfiles{exitname} = $exitname;
	}
	else
	{
		$dirfiles{exitname} = "";
	} say $tee "IN callblock 3 \$exitname " . dump( $exitname );


	if ( $sourceblockelts[0] =~ /^(\d+)>/ )
	{
		$dirfiles{starsign} = "yes"; # FOR THE INNER STAR SEARCH
		$dirfiles{stardivisions} =	my $entryname;
	if ( $sourceblockelts[0] =~ /^([A-Za-z]+)/ )
	{
		$entryname = $1;
		$dirfiles{entryname} = $entryname;
	}
	else
	{
		$dirfiles{entryname} = "";
	} say $tee "IN callblock 2 \$entryname " . dump( $entryname ); $1;
	}
	else
	{
		$dirfiles{starsign} = "no";
		$dirfiles{stardivisions} = "";
	} say $tee "IN callblock 3 \$dirfiles{starsign} " . dump( $dirfiles{starsign} );
	say $tee "IN callblock 3 \$dirfiles{stardivisions} " . dump( $dirfiles{stardivisions} );


	my @blocks = getblocks( \@sweeps, $countcase );
	my $toitem = getitem( \@winneritems, $countcase, $countblock );
	my $from = getline($toitem);
	my %varnums = getcase( \@varnumbers, $countcase ); say $tee "IN callblock \%varnums" . dump( \%varnums );
	my %mids = getcase( \@miditers, $countcase ); say $tee "IN callblock \%mids" . dump( \%mids );
	my $file = $dowhat{file};


	###########################################################


	my @tempvarnumbers;
	if ( $dirfiles{starsign} eq "yes" )
	{
		my @newvarnumbers = @{ stararrange( \@sweeps, \@blockelts, \@varnumbers, $countcase, $countblock, $file ) };
		say $tee "IN callblock \@newvarnumbers " . dump( @newvarnumbers );
		$dowhat{varnumbershold} = dclone( \@varnumbers ); say $tee "IN callblock  \$dowhat{varnumbershold} " . dump( $dowhat{varnumbershold} );
		@varnumbers = @{ dclone( \@newvarnumbers ) }; say $tee "IN callblock dcloned \@varnumbers " . dump( @varnumbers );
	}


	sub solvestar
	{
		my %d = %{ $_[0] };
		my %dirfiles = %{ $d{dirfiles} };
		my %dowhat = %{ $d{dowhat} };
		my @varnumbers = @{ $d{varnumbers} };

		$dirfiles{direction} = "star";
		$dirfiles{starorder} = $dowhat{starorder}->[countcase]->[0];

		my ( @gencetres, @genextremes, @genpoints, $genextremes_ref, $gencentres_ref, @starpositions, @dummysweeps, @dummyblockelts );

		if ( ( $dirfiles{stardivisions} ne "" ) and ( $dirfiles{starpositions} eq "" ) )
		{
			$dirfiles{starpositions} = genstar( \%dirfiles, \@varnumbers );

			( $dirfiles{dummysweeps}, $dirfiles{dummyblockelts} ) = @{ someprocedure( \@sweeps, \@blockelts, \%countcase, \$countblock ) };
		}

		$dirfiles{starnumber} = scalar( @{ $dirfiles{starpositions} } ); say $tee "AFTER \$dowhat{starnumber}: " . dump( $dowhat{starnumber} );

		if ( not( scalar( @{ $dirfiles{starpositions} } ) == 0 ) )
		{
			$dirfiles{direction} => [ [ "star" ] ],
			$dirfiles{randomsweeps} => "no", # to randomize the order specified in @sweeps.
			$dirfiles{randominit} => "no", # to randomize the init levels specified in @miditers.
			$dirfiles{randomdirs} => "no", # to randomize the directions of descent.
		}
		return( { dirfiles => \%dirfiles } )
	}


	if ( $dirfiles{starsign} eq "yes" )
	{
		%dirfiles = %{ solvestar( { dirfiles => \%dirfiles, dowhat => \%dowhat, varnumbers => @varnumbers, \@sweeps } ) };
	}




  ###########################################################

	$dirfiles{simlist} = "$mypath/$file-simlist--$countcase";
	$dirfiles{morphlist} = "$mypath/$file-morphlist--$countcase";
	$dirfiles{retlist} = "$mypath/$file-retlist$dummysweeps_ref--$countcase";
	$dirfiles{replist} = "$mypath/$file-replist--$countcase"; # # FOR RETRIEVAL
	$dirfiles{descendlist} = "$mypath/$file-descendlist--$countcase"; # UNUSED FOR NOW
	$dirfiles{simblock} = "$mypath/$file-simblock--$countcase-$countblock";
	$dirfiles{morphblock} = "$mypath/$file-morphblock--$countcase-$countblock";
	$dirfiles{retblock} = "$mypath/$file-retblock--$countcase-$countblock";
	$dirfiles{repblock} = "$mypath/$file-repblock--$countcase-$countblock"; # # FOR RETRIEVAL
	$dirfiles{descendblock} = "$mypath/$file-descendblock--$countcase-$countblock"; # UNUSED FOR NOW
	$dirfiles{repfile} = "$mypath/$file-report-$countcase-$countblock.csv"; #say "IN CALLBLOCK REPFILE:" . ( $dirfiles{repfile} ) . " .";
	$dirfiles{sortmixed} = "$dirfiles{repfile}" . "-sortm.csv"; #say "IN CALLBLOCK sortmixed:" . ( $dirfiles{sortmixed} ) . " .";
	$dirfiles{totres} = "$mypath/$file-$countcase" . "-totres.csv"; #say "IN CALLBLOCK totres:" . ( $dirfiles{totres} ) . " .";
	$dirfiles{ordres} = "$mypath/$file-$countcase" . "-ordres.csv"; #say "IN CALLBLOCK ordres:" . ( $dirfiles{ordres} ) . " .";

	my $starstring = tellstring( \%mids, $file ); #say $tee "IN callblock \$starstring " . dump( $starstring );
	$dirfiles{starstring} = $starstring; # FOR THE OUTTER STAR SEARCH

	my $blockdata = {
		countcase => $countcase, countblock => $countblock,
		miditers => \@miditers,  winneritems => \@winneritems,
		dirfiles => \%dirfiles,
		sweeps => \@sweeps, sourcesweeps => \@sourcesweeps, datastruc => \%datastruc,
		dowhat => \%dowhat, varnumbers => \@varnumbers };

	if ( $dirfiles{starsign} eq "yes" )
	{
		my $d = 0;
		foreach my $starmids_ref ( @{ $dirfiles{starpositions} } )
		{
			my $c = 0;
			foreach $dummyblockelts_ref ( @{ $dirfiles{dummyblockelts} } )
			{
				deffiles( $blockdata, $starmids_ref, $d, $dummyblockelts_ref, $c );
				$c++;
			}
		}
		$d++;
	}
	else
	{
		deffiles( $blockdata ); say $tee "NOW IN";
	}
}

sub deffiles # IT DEFINED THE FILES TO BE PROCESSED
{
	my %d = %{ $_[0] };
	my $starmids_ref = $_[1];
	$dirfiles{d} = $_[2];
	my $dummyblockelts_ref = $_[3];
	$dirfiles{c} = $_[4];

	my $countcase = $d{countcase}; say $tee "IN DEFFILES \$countcase : " . dump( $countcase );
  my $countblock = $d{countblock}; say $tee "IN DEFFILES \$countblock : " . dump( $countblock );
	my @sweeps = @{ $d{sweeps} }; #say $tee "IN DEFFILES \@sweeps : " . dump( @sweeps );
	my @sourcesweeps = @{ $d{sourcesweeps} }; #say $tee "IN DEFFILES \@sourcesweeps : " . dump( @sourcesweeps );
	my @miditers = @{ $d{miditers} }; #say $tee "IN DEFFILES \@miditers : " . dump( @miditers );
	my @winneritems = @{ $d{winneritems} }; #say $tee "\@winneritems : " . dump( @winneritems );
	my %dirfiles = %{ $d{dirfiles} }; #say $tee "IN deffiles \%dirfiles " . dump( %dirfiles );
	my %datastruc = %{ $d{datastruc} }; #say $tee "\%datastruc : " . dump( %datastruc );
	my @varnumbers = @{ $d{varnumbers} }; #say $tee "IN DEFFILES \@varnumbers" . dump( @varnumbers );
	my %dowhat = %{ $d{dowhat} }; #say $tee "IN DEFFILES \%dowhat" . dump( %dowhat );

	my $rootname = getrootname( \@rootnames, $countcase ); #say $tee "\$rootname : " . dump( $rootname );

	( my $blockelts_ref ) = getblockelts( \@sweeps, $countcase, $countblock );
	my @blockelts = @{ $blockelts_ref };

	my @blocks = getblocks( \@sweeps, $countcase ); #say $tee "IN DEFFILES \@blocks : " . dump( @blocks );
	my $toitem = getitem( \@winneritems, $countcase, $countblock ); #say $tee "IN DEFFILES \$toitem : " . dump( $toitem );
	my $from = getline( $toitem ); #say $tee "IN DEFFILES \$from : " . dump( $from );
	#say $tee "IN DEFFILES \$varnumbers[\$countcase]" . dump( $varnumbers[$countcase] );


	my %varnums = getcase( \@varnumbers, $countcase ); #say $tee "IN DEFFILES \%varnums" . dump( %varnums );

	my %mids = getcase(\@miditers, $countcase); #say $tee "IN DEFFILES \%mids" . dump( %mids );

	if ( $dirfiles{starsign} eq "yes" )
	{
		%mids = %{ $starmids_ref };
	}

	my $rootitem = "$file" . "_"; #say $tee "IN DEFFILES \$rootitem : " . dump( $rootitem );
	my (@basket, @box);
	push (@basket, [ $rootitem ] ); #say $tee "IN DEFFILES \@basket : " . dump( @basket );

	if ( $dirfiles{starsign} eq "yes" )
	{
		@blockelts = @{ $dummyblockelts_ref };
	}


	foreach my $var ( @blockelts )
	{
		my @bucket;
		my $maxvalue = $varnums{$var}; #say $tee "\$maxvalue : " . dump( $maxvalue );
		foreach my $elt (@basket)
		{
			my $root = $elt->[0]; #say $tee "\$root : " . dump( $root );
			my $cnstep = 1;
			while ( $cnstep <= $maxvalue)
			{	#say $tee "\$countblock : " . dump( $countblock );
				my $olditem = $root; #say $tee "\$olditem : " . dump( $olditem );
				my $item = "$root" . "$var" . "-" . "$cnstep" . "_" ;  #say $tee "\$item : " . dump( $item );
				push ( @bucket, [$item, $var, $cnstep, $olditem] ); #say $tee "\@bucket: " . dump( @bucket );
				$cnstep++; #say $tee "\$cnstep : " . dump( $cnstep );
			}
		}
		@basket = ();
		@basket = @bucket;
		push ( @box, [ @bucket ] );
	}

	#say $tee "IN DEFFILES \@box: " . dump( @box );
	my @flattened = flattenbox(@box); #say $tee "IN DEFFILES \@flattened: " . dump( @flattened );
	my @integrated = integratebox(\@flattened, \%mids, $file); #say $tee "IN DEFFILES \@integrated: " . dump( @integrated );
	my @finalbox = filterbox(@integrated); #say $tee "IN DEFFILES \@finalbox: " . dump( @finalbox );

	my $datatowork =
	{
		countcase => $countcase, countblock => $countblock,
		miditers => \@miditers,  winneritems => \@winneritems,
		dirfiles => \%dirfiles, basket => \@finalbox,
		sweeps => \@sweeps, sourcesweeps => \@sourcesweeps,
		datastruc => \%datastruc, dowhat => \%dowhat,
		varnumbers => \@varnumbers
	} ;
	setlaunch( $datatowork );
}

sub setlaunch # IT SETS THE DATA FOR THE SEARCH ON THE ACTIVE BLOCK.
{
	my %d = %{ $_[0] };
	my $countcase = $d{countcase}; #say $tee "IN SETLAUNCH \$countcase " . dump( $countcase );
	my $countblock = $d{countblock}; #say $tee "IN SETLAUNCH \$countblock " . dump( $countblock );
	my @sweeps = @{ $d{sweeps} };
	my @sourcesweeps = @{ $d{sourcesweeps} }; #say $tee "IN SETLAUNCH \@sourcesweeps " . dump( @sourcesweeps );
	my @miditers = @{ $d{miditers} }; #say $tee "IN SETLAUNCH \@miditers " . dump( @miditers );
	my @winneritems = @{ $d{winneritems} };
	my %dirfiles = %{ $d{dirfiles} };
	my @basket = @{ $d{basket} }; #say $tee "IN SETLAUNCH \@basket" . dump( @basket );
	my %datastruc = %{ $d{datastruc} };
	my @varnumbers = @{ $d{varnumbers} }; #say $tee "IN SETLAUNCH \@varnumbers " . dump( @varnumbers );
	my %dowhat = %{ $d{dowhat} }; #say $tee "IN SETLAUNCH \%dowhat" . dump( %dowhat );

	my $rootname = getrootname(\@rootnames, $countcase);
	my ( $blockelts_ref ) = getblockelts(\@sweeps, $countcase, $countblock );
	my @blockelts = @{ $blockelts_ref };


	my @blocks = getblocks(\@sweeps, $countcase); #say $tee "IN SETLAUNCH \@blocks " . dump( @blocks );
	my $toitem = getitem(\@winneritems, $countcase, $countblock);
	my $from = getline($toitem);
	my %varnums = getcase(\@varnumbers, $countcase); #say $tee "IN SETLAUNCH \%varnums" . dump( %varnums );
	my %mids = getcase(\@miditers, $countcase); #say $tee "IN SETLAUNCH \%mids" . dump( %mids );

	my ( @instances, %carrier);
	#if ($countblock == 0)
	#{
	#	%carrier = %mids;
	#}
	#else
	#{
	#	my $prov = "_" . "$winnerline";
	#	%carrier = extractcase( $prov , \%carrier );
	#}

	foreach my $elt ( @basket )
	{
		my $newpars = $$elt[0];
		my $countvar = $$elt[1];
		my $countstep = $$elt[2];
		my $oldpars = $$elt[3];
		my @taken = extractcase("$newpars", \%mids);
		my $to = $taken[0]; #say $tee "IN SETLAUNCH \$to" . dump( $to );
		my @olds = extractcase( "$oldpars", \%mids);
		my $origin = $olds[0]; #say $tee "IN SETLAUNCH \$origin" . dump( $origin );
		push ( @instances,
		{
			countcase => $countcase, countblock => $countblock,
			miditers => \@miditers,  winneritems => \@winneritems,
			dirfiles => \%dirfiles,
			to => $to, countvar => $countvar, countstep => $countstep,
			origin => $origin, sweeps => \@sweeps,
			sourcesweeps => \@sourcesweeps, datastruc => \%datastruc,
			dowhat => \%dowhat, varnumbers => \@varnumbers
		} );
	} #say $tee "IN SETLAUNCH \@instances " . dump( @instances );
	exe( { instances => \@instances, countcase => $countcase, countblock => $countblock,
	miditers => \@miditers,  winneritems => \@winneritems,
	dirfiles => \%dirfiles, sweeps => \@sweeps,
	sourcesweeps => \@sourcesweeps, datastruc => \%datastruc,
	dowhat => \%dowhat, varnumbers => \@varnumbers } );
}

sub exe
{
	my %d = %{ $_[0] };
	my @instances = @{ $d{instances} }; #say $tee "IN EXE \@instances " . dump( @instances );
	my $countcase = $d{countcase}; say $tee "IN EXE \$countcase " . dump( $countcase );
	my $countblock = $d{countblock}; say $tee "IN EXE \$countblock " . dump( $countblock );
	my @varnumbers = @{ $d{varnumbers} }; #say $tee "IN EXE \@varnumbers " . dump( @varnumbers );
	my @miditers = $d{miditers}; #say $tee "IN EXE \@miditers " . dump( @miditers );
	my @sweeps = @{ $d{sweeps} }; #say $tee "IN EXE \@miditers " . dump( @miditers );
	my @sourcesweeps = @{ $d{sourcesweeps} }; #say $tee "IN EXE \@sourcesweeps " . dump( @sourcesweeps );
	my %dirfiles = %{ $d{dirfiles} }; #say $tee "IN EXE \%dirfiles " . dump( %dirfiles );
	my %datastruc = %{ $d{datastruc} }; #say $tee "IN EXE \%datastruc " . dump( %datastruc );
	my %dowhat = %{ $d{dowhat} }; #say $tee "IN EXE \%dowhat " . dump( %dowhat );

	my $direction = ${$dowhat{direction}}[$countcase][$countblock]; #say $tee "IN EXE \$direction " . dump( $direction ); #NEW
	my $starorder = ${$dowhat{starorder}}[$countcase][$countblock]; #say $tee "IN EXE \$starorder " . dump( $starorder ); #NEW
  my $precomputed = $dowhat{precomputed}; #say $tee "IN EXE \$precomputed " . dump( $precomputed ); #NEW
  my @takecolumns = @{ $dowhat{takecolumns} }; #say $tee "IN EXE \@takecolumns " . dump( @takecolumns ); #NEW
	my ( @simcases, @simstruct );
	say $tee "#Performing a search on case " . ($countcase +1) . ", block " . ($countblock + 1) . ".";

	if ( $dowhat{morph} eq "y" )
	{
		say $tee "#Calling morphing operations for case " . ($countcase +1) . ", block " . ($countblock + 1) . ".";

		my @result = Sim::OPT::Morph::morph(
		{
			configfile => $configfile, instances => \@instances, countcase => $countcase,
			countblock => $countblock, dirfiles => \%dirfiles, datastruc => \%datastruc,
			dowhat => \%dowhat, sweeps => \@sweeps, sourceweeps => \@sourcesweeps,
			miditers => \@miditers, varnumbers => \@varnumbers, rootnames => \@rootnames
		} );
		$dirfiles{morphcases} = $result[0];
		$dirfiles{morphstruct} = $result[1];
	}

	if ( ( $dowhat{simulate} eq "y" ) or ( $dowhat{newreport} eq "y" ) )
	{

		say $tee "#Calling simulations, reporting and retrieving for case " . ($countcase +1) . ", block " . ($countblock + 1) . ".";
		my ( $simcases_ref, $simstruct_ref, $repcases_ref, $repstruct_ref,
	    $mergestruct_ref, $mergecases_ref ) = Sim::OPT::Sim::sim(
		{
			  instances => \@instances, countcase => $countcase, countblock => $countblock,
				dirfiles => \%dirfiles, datastruc => \%datastruc,
				dowhat => \%dowhat, miditers => \@miditers, varnumbers => \@varnumbers,
				rootnames => \@rootnames, sweeps => \@sweeps,
				sourceweeps => \@sourcesweeps,
		} );
		@simcases = @{ $simcases_ref};
		@simstruct = @{ $simstruct_ref};
		$dirfiles{repcases} = $repcases_ref;
		$dirfiles{repstruct} = $repstruct_ref;
		$dirfiles{mergestruct} = $mergestruct_ref;
		$dirfiles{mergecases} = $mergecases_ref;
	}
  elsif ( $dowhat{simulate} eq "y" )
	{
			say $tee "#Calling simulations for case " . ($countcase +1) . ", block " . ($countblock + 1) . ".";
			my ( $simcases_ref, $simstruct_ref, $repcases_ref, $repstruct_ref,
		    $mergestruct_ref, $mergecases_ref )  = Sim::OPT::Sim::sim(
		{
				instances => \@instances, countcase => $countcase, countblock => $countblock,
				dirfiles => \%dirfiles, datastruc => \%datastruc,
				dowhat => \%dowhat, miditers => \@miditers, varnumbers => \@varnumbers,
				rootnames => \@rootnames, sweeps => \@sweeps,
				sourceweeps => \@sourcesweeps,
		} );
		@simcases = @{ $simcases_ref};
		@simstruct = @{ $simstruct_ref};
		$dirfiles{repcases} = $repcases_ref;
		$dirfiles{repstruct} = $repstruct_ref;
		$dirfiles{mergestruct} = $mergestruct_ref;
		$dirfiles{mergecases} = $mergecases_ref;
	}

	if ( $dowhat{descend} eq "y" )
	{
		say $tee "#Calling descent for case " . ($countcase + 1) . ", block " . ($countblock + 1) . ".";
		#say $tee "\@sourcesweeps: " . dump( @sourcesweeps );
		my @result = Sim::OPT::Descend::descend(
		{
				instances => \@instances, countcase => $countcase, countblock => $countblock,
				dirfiles => \%dirfiles, datastruc => \%datastruc,
				dowhat => \%dowhat, sourcesweeps => \@sourcesweeps,
				miditers => \@miditers, varnumbers => \@varnumbers,
				rootnames => \@rootnames, sweeps => \@sweeps,
		} );
		$dirfiles{descendcases} = $result[0];
		$dirfiles{descendstruct} = $result[1];
	}

	if ( $dowhat{substitutenames} eq "y" )
	{
		 Sim::OPT::Report::filter_reports(
		{
			  instances => \@instances, countcase => $countcase, countblock => $countblock,
				dirfiles => \%dirfiles, dowhat => \%dowhat,
				miditers => \@miditers, varnumbers => \@varnumbers,
				rootnames => \@rootnames, sweeps => \@sweeps,
				sourceweeps => \@sourcesweeps,
		} );
	}

	if ( $dowhat{filterconverted} eq "y" )
	{
		 Sim::OPT::Report::convert_filtered_reports(
		{
			  instances => \@instances, countcase => $countcase, countblock => $countblock,
				dirfiles => \%dirfiles, dowhat => \%dowhat,
				miditers => \@miditers, varnumbers => \@varnumbers,
				rootnames => \@rootnames, sweeps => \@sweeps,
				sourceweeps => \@sourcesweeps,
		} );
	}

	if ( $dowhat{make3dtable} eq "y" )
	{
		 Sim::OPT::Report::maketable(
		{
			  instances => \@instances, countcase => $countcase, countblock => $countblock,
				dirfiles => \%dirfiles, dowhat => \%dowhat,
				miditers => \@miditers, varnumbers => \@varnumbers,
				rootnames => \@rootnames, sweeps => \@sweeps,
				sourceweeps => \@sourcesweeps,
		} );
	}
} # END SUB exe


sub genstar
{
	my ( $dowhat_ref, $varnumbers_ref ) = @_;
	my %dowhat = %{ $dowhat_ref };
	my @varnumbers = @{ $varnumbers_ref };

	my (  @genextremes, @gencentres );
	if ( $dowhat{stardivisions} == 1 )
	{
		$gencentres_ref = gencen( \@varnumbers ); #say $tee "\$dowhat{starpositions}: " . dump( $dowhat{starpositions} );
		@gencentres = @{ $gencentres_ref };
		push( @{ $dowhat{starpositions} }, @gencentres );
	}
	elsif ( $dowhat{stardivisions} > 1 )
	{
		$genextremes_ref = genextremes( \@varnumbers );
		my $i = 0;
		while ( $i < $dowhat{stardivisions} )
		{
			$genextremes_ref = gencentres( $genextremes_ref );
			@genpoints = @{ $genextremes_ref }; #say $tee "GENCENTRES \@gencentres: " . dump( @gencentres );
			$i++;
		}
		push( @{ $dowhat{starpositions} }, @genpoints );
	}
	return( $dowhat{starpositions} );
}


sub start
{


###########################################
say "\nHi. This is Sim::OPT, version $VERSION.
Please insert the name of a configuration file (Unix path).\n";
###########################################
	$configfile = <STDIN>;
	chomp $configfile;
	if (-e $configfile ) { ; }
	else { &start; }
}



###########################################################################################

sub opt
{
	&start;
	#eval `cat $configfile`; # The file where the program data are
	my ( @miditers, @varnumbers );
	require $configfile;

	if ( scalar( @miditers == 0 ) )
	{
		@miditers = @mediumiters;
	}

	if ( scalar( @varnumbers == 0 ) )
	{
		@varnumbers = @varinumbers;
	}


	#if ( not ( $outfile ) ) { $outfile = "$mypath/$file-$fileconfig-feedback.txt"; }
	if ( not ( $tofile ) )
	{
		$tofile = "$mypath/$file-tofile.txt";
	}

	$tee = new IO::Tee(\*STDOUT, ">>$tofile"); # GLOBAL ZZZ

#	if ($casefile) { eval `cat $casefile` or die( "$!" ); }
#	if ($chancefile) { eval `cat $chancefile` or die( "$!" ); }

	print "\nNow in Sim::OPT. \n";
	$dowhat{file} = $file;

  if ( $dowhat{randomsweeps} eq "yes" ) #IT SHUFFLES  @sweeps UNDER REQUESTED SETTING.
  {
    my @newsweeps;
    foreach my $arrayref ( @sweeps )
    {
        my @newarr;
        my @array = @{ $arrayref };
        @array = shuffle( @array );
        foreach my $arefref ( @array )
        {
          my @arrayy = @{ $arefref };
          @arrayy = shuffle( @arrayy );
          push ( @newarr, [ @arrayy ] );
        }
        push ( @newsweeps, [ @newarr ] );
      }
      @sweeps = @newsweeps;
      #print "NEW SWEEPS: " . dump( @sweeps ) . "\n";
  }

  my $i = 0;
  my @newarr;
  if ( $dowhat{randomdirs} eq "yes" )
  { #IT SHUFFLES  $dowhat{direction} UNDER REQUESTED SETTINGS.
    foreach my $directionref ( @{ $dowhat{direction} } )
    {
      my @varnumber = %{ $varnumbers[$i] };
      my $numcases = ( scalar( @varnumber ) / 2 ) ;
      my @directions;
      my $x = 0;
      foreach ( @{ $directionref } )
      {
        while ( $x < $numcases )
        {
          my @bag = ( ">", "<", "=" );
          @bag = shuffle( @bag );
          push ( @directions, $bag[0] );
          $x++;
        }
      }
      push ( @newarr, [ @directions ] );
      $i++;
    }
    $dowhat{direction} = [ @newarr ];
    #say "NEW RANDOMIZED DIRECTIONS: " . dump( $dowhat{direction} );
  }


  { #IT FILLS THE MISSING $dowhat{direction} UNDER REQUESTED SETTINGS.
    my $i = 0;
    my @newarr;
    foreach my $dirref ( @{ $dowhat{direction} } )
    {
			#say "112 \$dirref: " . dump( $dirref );
      my @thesesweeps = @{ $sweeps[$i] }; #say "112 \@thesesweeps: " . dump( @thesesweeps );
      my $numcases =  scalar( @thesesweeps )  ; #say "112 \$numcases: " . dump( $numcases );

      my @directions;
      my $itemsnum = scalar( @{ $dirref } ); #say "112 \$itemsnum: " . dump( $itemsnum );
      my $c = 0;
      while ( ( $itemsnum + $c ) <= $numcases )
      {
        push ( @directions, ${ $dirref }[0] );
        $c++;
      }
			#say "112-0 \@directions: " . dump( @directions );
      push ( @newarr, [ @directions ] );
      $i++;
    }
		#say "112-0 \@newarr: " . dump( @newarr );
    $dowhat{direction} = [ @newarr ];
    #say "NEW FILLED DIRECTIONS: " . dump( $dowhat{direction} );
  }
	#say "112-0 \$dowhat{direction}: " . dump( $dowhat{direction} );

	{ #IT FILLS THE MISSING $dowhat{starorder} UNDER APPROPRIATE SETTINGS.
    my $i = 0;
    my @newarr;
    foreach my $dirref ( @{ $dowhat{starorder} } )
    {
			#say "112 \$dirref: " . dump( $dirref );
      my @thesesweeps = @{ $sweeps[$i] }; #say "112 \@thesesweeps: " . dump( @thesesweeps );
      my $numcases =  scalar( @thesesweeps )  ; #say "112 \$numcases: " . dump( $numcases );

      my @directions;
      my $itemsnum = scalar( @{ $dirref } ); #say "112 \$itemsnum: " . dump( $itemsnum );
      my $c = 0;
      while ( ( $itemsnum + $c ) <= $numcases )
      {
        push ( @directions, ${ $dirref }[0] );
        $c++;
      }
			#say "112-0 \@directions: " . dump( @directions );
      push ( @newarr, [ @directions ] );
      $i++;
    }
		#say "112-0 \@newarr: " . dump( @newarr );
    $dowhat{starorder} = [ @newarr ];
    #say "NEW FILLED STAR ORDERING: " . dump( $dowhat{starorder} );
  }
	#say "112-0 \$dowhat{starorder}: " . dump( $dowhat{starorder} );

  if ( $dowhat{randominit} eq "yes" )
  {
    my %i = 0;
    foreach $arr ( @varnumbers )
    {
      my %hash = %{ $arr };
      foreach my $elt ( sort {$a <=> $b} ( keys %hash ) )
      {
        my $num = $hash{$elt};
        my $newnum = ( 1+ int( rand( $num ) ) );
        ${ $miditers[i] }{$elt} = $newnum;
      }
      $i++;
    }
    #say "NEW INIT LEVELS: " . dump( @miditers );
  }

	#open( OUTFILE, ">>$outfile" ) or die "Can't open $outfile: $!";
#	open( TOFILE, ">>$tofile" ) or die "Can't ING: " . dump( $starstring );open $tofile: $!";

	#unless (-e "$mypath")
	#{
	#	if ($exeonfiles eq "y")
	#	{
	#		`mkdir $mypath`;
	#	}
	#}
	#unless (-e "$mypath")
	#{
	#	print TOFILE "mkdir $mypath\n\n";
	#}

	if ( not ( $target ) ) { $target = "opt"; }

	#####################################################################################
	# INSTRUCTIONS THAT LAUNCH OPT AT EACH SWEEP (SUBSPACE SEARCH) CYCLE

	if ( not ( ( @chanceseed ) and ( @caseseed ) and ( @chancedata ) ) )
	{
		if ( ( @sweepseed ) and ( @chancedata ) ) # IF THIS VALUE IS DEFINED. TO BE FIXED. ZZZ
		{
			my $yield = fromsweep_toopt( @sweeps );
			@caseseed = @{ $yield[0] };
			@chanceseed = @{ $yield[1] };
		}
	}

	@chanceseed = convchanceseed(@chanceseed);
	@caseseed = convcaseseed( { caseseed => \@caseseed, chanceseed => \@chanceseed } );

	my (@sweeps_);

	if ( ( $target eq "takechance" ) and (@chancedata) and ( $dimchance ) )
	{
		my @obt = Sim::OPT::Takechance::takechance( \@caseseed, \@chanceseed, \@chancedata, $dimchance );              #say $tee "PASSED: \@sweeps: " . dump(@sweeps);
		@sweeps_ = @{ $obt[0] };
		@caseseed_ = @{ $obt[1] };
		@chanceseed_ = @{ $obt[2] };
		open( MESSAGE, ">./search_structure_that_may_be_adopted.txt" );
		say MESSAGE "\@sweeps_ " . Dumper(@sweeps_);
		say MESSAGE "\THESE VALUES OF \@sweeps IS EQUIVALENT TO THE FOLLOWING VALUES OF \@caseseed AND \@chanceseed: ";
		say MESSAGE "\n\@caseseed " . Dumper(@caseseed_);
		say MESSAGE "\n\@chanceseed_ " . Dumper(@chanceseed_);
		close MESSAGE;

		if ( not (@sweeps) ) # CONSERVATIVE CONDITION. IT MAY BE CHANCED. ZZZ
		{
			@sweeps = @sweeps_ ;
		}
	}
	elsif ( $target eq "opt" )
	{
		if ( scalar( @miditers ) == 0 ) { calcmiditers( @varnumbers ); }
		#$itersnum = getitersnum($countcase, $varnumber, @varnumbers);

		@rootnames = definerootcases( \@sweeps, \@miditers );
		#say $tee "PRE CALLCASE \@rootnames: " . dump( @rootnames );

		my $countcase = 0;
		my $countblock = 0;
		my %datastruc;

		my @winneritems = populatewinners( \@rootnames, $countcase, $countblock );
		say $tee "PRE CALLCASE \@winneritems: " . dump( @winneritems );

		my $count = 0;
		my @arr;
		foreach ( @varnumbers )
		{
			my $elt = getitem( \@winneritems, $count, 0 );
			push ( @arr, $elt );
			$count++;
		}
		$datastruc{pinwinneritem} = [ @arr ];

		#say $tee "\$dowhat{stardivisions}_: " . dump( $dowhat{stardivisions} );
		my ( @gencetres, @genextremes, @genpoints, $genextremes_ref, $gencentres_ref );

		if ( ( $dowhat{stardivisions} ne "" ) and ( $dowhat{starpositions} eq "" ) and ( $dowhat{starmode} eq "outstar" ) )
		{
			$dowhat{starpositions} = genstar( \%dowhat, \@varnumbers );
		}

		#say $tee "AFTER \$dowhat{starpositions}: " . dump( \@{ $dowhat{starpositions} } );

		$dowhat{starnumber} = scalar( @{ $dowhat{starpositions} } ); #say $tee "AFTER \$dowhat{starnumber}: " . dump( $dowhat{starnumber} );

		if ( not( scalar( @{ $dowhat{starpositions} } ) == 0 ) )
		{
			#say $tee "AFTER0 \@{ \$dowhat{starpositions} }: " . dump( @{ $dowhat{starpositions} } );

			$dowhat{direction} => [ [ "star" ] ],
			$dowhat{randomsweeps} => "no", # to randomize the order specified in @sweeps.
			$dowhat{randominit} => "no", # to randomize the init levels specified in @miditers.
			$dowhat{randomdirs} => "no", # to randomize the directions of descent.

			my @sweeps = @{ starsweep( \@varnumbers, \@sweeps ) }; #say $tee "AFTER0 \@sweeps: " . dump( @sweeps );

			my $number = scalar( @varnumbers ); #say $tee "AFTER0 \$number: " . dump( $number );

			my ( @addition, @addition2, @addition3, @sweepaddition );
			my $cn = 0;
			while ( $cn < $dowhat{starnumber} )
			{
				push( @addition, $varnumbers[0] );
				push( @addition2, $dowhat{direction}[0] );
				push( @addition3, $dowhat{starorder}[0] );
				push( @sweepaddition, $sweeps[0] );
				$cn++;
			} #say $tee "AFTER0 \@addition: " . dump( @addition );

			@varnumbers = @addition;
			$dowhat{direction} = \@addition2;
			$dowhat{starorder} = \@addition3;
			my @sweeps = @sweepaddition;

			my @bag; #say $tee "AFTER0 \@miditers: " . dump( @miditers );
			my @miditers = @miditers[1 ... $#miditers]; #say $tee "AFTER1 \@miditers: " . dump( @miditers );
			push( @bag, @{ $dowhat{starpositions} }, @miditers );
			my @miditers = @bag; #say $tee "AFTER3 \@miditers: " . dump( @miditers );

			$countstring = 1;

			my ( $sweepz_ref, $sourcesweeps_ref ) = readsweeps( @sweeps );
			my @sweepz = @$sweepz_ref;
			my @sourcesweeps = @$sourcesweeps_ref;
			if ( @sweepz )
			{
				@sweeps = @sweepz;
			}

			@calcoverlaps = calcoverlaps( @sweeps );

	    #@miditers = @pinmiditers;
			#my %mids = getcase( \@miditers, $countcase ); #say $tee "IN CALLCASE \%mids" . dump( %mids );
			$dirfiles{countstring} = $countstring;
			#my $totres_read = "$mypath/$file-totres-$countcase-$countblock.csv";
			#$dirfiles{totres_read} = $totres_read;
			#my $totres_write = "$mypath/$file-totres-$countcase-$countblock.csv";
			#$dirfiles{totres_write} = $totres_write;

			#say $tee "PRE CALLCASE \@sweeps: " . dump( @sweeps );
			#say $tee "PRE CALLCASE \@varnumbers: " . dump( @varnumbers );
			#say $tee "PRE CALLCASE \@miditers: " . dump ( @miditers );
			#say $tee "PRE CALLCASE \$dowhat{direction}" . dump( $dowhat{direction} );
			#say $tee "PRE CALLCASE \$dowhat{starorder}" . dump( $dowhat{starorder} );

			$dirfiles{tottot} = "$mypath/$file-$countcase" . "-tottot.csv"; #say "IN CALLBLOCK tottot:" . ( $dirfiles{tottot} ) . " .";
			$dirfiles{ordtot} = "$mypath/$file-$countcase" . "-ordtot.csv"; #say "IN CALLBLOCK ordtot:" . ( $dirfiles{ordtot} ) . " .";



			callblock( { countcase => $countcase, rootnames => \@rootnames, countblock => $countblock,
				miditers => \@miditers, varnumbers => \@varnumbers, winneritems => \@winneritems, sweeps => \@sweeps,
				sourcesweeps => \@sourcesweeps, datastruc => \%datastruc, dirfiles => \%dirfiles,
				dowhat => \%dowhat } );
				$countstring++;
				$dirfiles{countstring} = $countstring;
		}
		else
		{
			my ( $sweepz_ref, $sourcesweeps_ref ) = cleansweeps( \@sweeps );
			my @sweepz = @{ $sweepz_ref }; #say $tee "AFTER CLEANSWEEPS \@sweepz: " . dump ( @sweepz );
			my @sourcesweeps = @{ $sourcesweeps_ref }; #say $tee "AFTER CLEANSWEEPS \@sourcesweeps: " . dump ( @sourcesweeps );
			if ( @sweepz )
			{
				@sweeps = @sweepz;
			}

			#@calcoverlaps = calcoverlaps( @sweeps );
			$dirfiles{tottot} = "$mypath/$file-$countcase" . "-tottot.csv"; #say "IN CALLBLOCK tottot:" . ( $dirfiles{tottot} ) . " .";
			$dirfiles{ordtot} = "$mypath/$file-$countcase" . "-ordtot.csv"; #say "IN CALLBLOCK ordtot:" . ( $dirfiles{ordtot} ) . " .";
			#@miditers = @pinmiditers;
			#say $tee "miditers: " . dump ( @miditers );

			if ( scalar( @miditers ) == 0 ) { calcmiditers( @varnumbers ); }
			#$itersnum = getitersnum( $countcase, $varnumber, @varnumbers );

			@rootnames = definerootcases( \@sweeps, \@miditers ); #say $tee "\@rootnames: " . dump ( @rootnames );

			my $countcase = 0;
			my $countblock = 0;
			my %datastruc;

			my @winneritems = populatewinners( \@rootnames, $countcase, $countblock ); #say $tee "\@winneritems: " . dump ( @winneritems );

			my $count = 0;
			my @arr;
			foreach ( @varnumbers )
			{
				my $elt = getitem(\@winneritems, $count, 0);
				push ( @arr, $elt );
				$count++;
			}
			$datastruc = [ @arr ];

			#say $tee "PRE CALLCASE \%dowhat" . dump( %dowhat );
			callblock
			(	{ countcase => $countcase, rootnames => \@rootnames, countblock => $countblock,
					miditers => \@miditers, varnumbers => \@varnumbers, winneritems => \@winneritems,
					sweeps => \@sweeps, sourcesweeps => \@sourcesweeps,
					datastruc => \%datastruc, dowhat => \%dowhat,
					dirfiles => \%dirfiles } );
		}
	}
	elsif ( ( $target eq "parcoord3d" ) and (@chancedata) and ( $dimchance ) )
	{
		Sim::OPT::Parcoord3d::parcoord3d;
	}

	close(OUTFILE);
	close(TOFILE);
	exit;
} # ENDsub opt

#############################################################################

1;

__END__

=head1 NAME

Sim::OPT.

=head1 SYNOPSIS

  use Sim::OPT;
  opt;

=head1 DESCRIPTION

Sim::OPT is an optimization and parametric exploration program oriented to problem decomposition. It can be used with simulation programs receiving text files as input and emitting text files as output. Some of the Sim::OPT's optimization modules (Sim::OPT, Sim::OPT::Descent) pursue optimization through block search, allowing blocks (subspaces) to overlap, and allowing a free intermix of sequential searches (inexact Gauss-Seidel method) and parallell ones (inexact Jacobi method). The Sim::OPT::Takechange module can seek for the least explored search paths when exploring new search spaces sequentially (following rules presented in: http://dx.doi.org/10.1016/j.autcon.2016.08.014). Sim::OPT::Morph, the morphing module, manipulates chosen parameters in the configuration files (constituted by text files) describing models for simulation programs, recognizing variables by position.
Other modules unders the Sim::OPT namespace are Sim::OPT::Parcoord3d, a module which converts 2D parallel coordinates plots in Autolisp instructions for obtaining 3D plots as Autocad drawings; and Sim::OPT::Interlinear, which can build metamodels starting from sparse multidimensional data.
The module Sim::OPT::Modish, capable of altering the shading values calculated with the ESP-r simulation platform to take into account the solar reflections from obstructions, is no more included in this distribution, because a modificed version of it has been included in the ESP-r distribution, available at the address http://www.esru.strath.ac.uk/Programs/ESP-r.htm.
The Sim::OPT's morphing and reporting modules contain several additional functions specifically targeting the ESP-r building performance simulation platform. A working knowledge of ESP-r is necessary to use those functionalities.

To install Sim::OPT, the command <cpanm Sim::OPT> has to be issued as a superuser. Sim::OPT can then be loaded through the command <use Sim::OPT> in a Perl repl. But to ease the launch, the batch file "opt" (which can be found packed in the "optw.tar.gz" file in "examples" folder in this distribution) may be copied in a work directory and the command <opt> may be issued. That command will call OPT with the settings specified in the configuration file. When launched, Sim::OPT will ask the path to that file, which must contain a suitable description of the operations to be accomplished and point to an existing simulation model.

The "$mypath" variable in the configuration file must be set to the work directory where the base model reside.

Besides an OPT configuration file, separate configuration files for propagation of constraints may be created. Those can be useful to give the morphing operations greater flexibility. Propagation of constraints can regard the geometry of a model, solar shadings, mass/flow network, controls, and generic text files descripting a simulation model.

The simulation model folders and the result files that will be created in a parametric search will be named as the base model, plus numbers and other characters naming the model instances. For example, the instance produced in the first iteration for a root model named "model" in a search constituted by 3 morphing phases and 5 iteration steps each will be named "model_1-1_2-1_3-1"; and the last one "model_1-5_2-5_3-5".

The structure of the block searches is described through the variable "@sweeps" in a configuration file. Each case is listed inside square brackets; and each search subspace (block) in each case is listed inside square brakets. For example: a sequence constituted by two sequential full-factorial force searches, one regarding parameters 1, 2, 3 and the other regarding parameters 1, 4, 5, 7, would be described with: @sweeps = ( [ [ 1, 2, 3 ] ] , [ [ 1, 4, 5, 7 ] ] ) . And a sequential block search with the first subspace regarding parameters 1, 2, 3 and the second regarding parameters 3, 4, 5, 6 would be described with: @sweeps = ( [ [ 1, 2, 3 ] , [ 3, 4, 5, 6 ] ] ).

The number of iterations to be taken into account for each parameter for each case is specified in the "@varnumbers" variable. To specifiy that the parameters of the last example are to be tried for three values (iterations) each, @varnumbers has to be set to ( { 1 => 3, 2 => 3, 3 => 3, 4 => 3, 5 => 3, 6 => 3 } ).

The instance number that has to trated as the basic instance, corresponding to the root case, is specified by the variable "@miditers". "@miditers" for the last example may be for instance set to ( { 1 => 2, 2 => 2, 3 => 2, 4 => 2, 5 => 2, 6 => 2 } ).

OPT can work on a given set of pre-simulated results without launching new simulations, and it can randomize the sequence of the parameter search and the initialization level of the parameters (see the included examples).

By default the behaviour of the program is sequential. To make it parallel locally, subspaces have to be named with a name not containing numbers, so as to work as a collector cells. If the name "name", for example, has to be given to a block, the letters "name" must be joined at the beginning of the first number describing an iteration number in a block. If that number is 1, for example, the first element of that block should be named "name1". As an effect, that block will receive values from all the blocks "pointing" to a block named "name". To point the search outcome of a block to another block, the name of the block pointed to has to be appended to the last number describing an iteration number in a block. If that number is 3 and the name of the block pointed to is "surname", for example, the last element of that block should be named "3surname". A block of in which both the mentioned situations took place could be named for example [ "name1", 2, "3surname" ].

If the search has to start from more than one block in parallel, the first block should be named and all the other starting blocks should be named like it.

The possibility of articulating a mix of parallel and sequential searches is of absolute importance, because it makes possible to design search structures with a depth, embodying precedence, and therefore procedural time, in them. Deriving from this, there is the fact that the representation tools in question are sufficient for describing directed graphs.

Where Sim::OPT may be fit for a task? Where a certain exploration is complex and/or when it is to be confronted through decomposition, by dividing a problem in overlapping subproblems; when there aren't slick tools suitable to decomposition-based, simulation-based optimization; when spednding a day, or two, or three setting up a model may spare months of work.

Where it may not be suitable for the task? Due to the investment which is necessary for getting acquainted with its raw interface, for quick shots at small explorations.

The program works under Linux.

=head2 EXPORT

"opt".

=head1 SEE ALSO

Annotated examples ("esp.pl" for ESP-r, "ep.pl" for EnergyPlus - the two perform the same morphing operations on models describing the same building -, "des.pl" about block search, and "f.pl" about a search in a pre-simulated dataset) can be found packed in the "optw.tar.gz" file in "examples" directory in this distribution. They constitute the available documentation. For more information, reference to the source code should be made.

=head1 AUTHOR

Gian Luca Brunetti, E<lt>gianluca.brunetti@polimi.itE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2008-2017 by Gian Luca Brunetti and Politecnico di Milano. This is free software. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.


=cut
