package Sim::OPT::Descend;
# Copyright (C) 2008-2015 by Gian Luca Brunetti and Politecnico di Milano.
# This is the module Sim::OPT::Descend of Sim::OPT, a program for detailed metadesign managing parametric explorations through the ESP-r building performance simulation platform and performing optimization by block coordinate descent.
# 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 2.

use v5.14;
# use v5.20;
use 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 Set::Intersection;
use List::Compare;
use IO::Tee;
use File::Copy qw( move copy );
use Data::Dumper;
#$Data::Dumper::Indent = 0;
#$Data::Dumper::Useqq  = 1;
#$Data::Dumper::Terse  = 1;
use Data::Dump qw(dump);
use feature 'say';
use Sim::OPT;
use Sim::OPT::Morph;
use Sim::OPT::Sim;
use Sim::OPT::Report;
use Sim::OPT::Takechance;


no strict; 
no warnings;
use warnings::unused;

@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( descend ); # our @EXPORT = qw( );

$VERSION = '0.43.12'; # our $VERSION = '';
$ABSTRACT = 'Sim::OPT::Descent is an module collaborating with the Sim::OPT module for performing block coordinate descent.';

#########################################################################################
# HERE FOLLOWS THE CONTENT OF "Descend.pm" - Sim::OPT::Descend
##############################################################################

sub descend 
{
	my $swap = shift; #say TOFILE "swapINDESCEND: " . dump($swap);
	my %dat = %$swap;
	my @instances = @{ $dat{instances} }; #say "scalar(\@instances): " . scalar(@instances);
	my $countcase = $dat{countcase}; #say "dump(\$countcase): " . dump($countcase); # IT WILL BE SHADOWED. CUT ZZZ
	my $countblock = $dat{countblock}; #say "dump(\$countblock): " . dump($countblock); # IT WILL BE SHADOWED. CUT ZZZ		
	my %dirfiles = %{ $dat{dirfiles} }; #say "dump(\%dirfiles): " . dump(%dirfiles); 
	my $repfile = $dat{repfile}; 
		
	$configfile = $main::configfile; #say "dump(\$configfile): " . dump($configfile);
	@sweeps = @main::sweeps; #say "dump(\@sweeps): " . dump(@sweeps);
	@varinumbers = @main::varinumbers; #say "dump(\@varinumbers): " . dump(@varinumbers);
	@mediumiters = @main::mediumiters;
	@rootnames = @main::rootnames; #say "dump(\@rootnames): " . dump(@rootnames);
	%vals = %main::vals; #say "dump(\%vals): " . dump(%vals);
	
	$mypath = $main::mypath;  #say TOFILE "dumpINDESCEND(\$mypath): " . dump($mypath);
	$exeonfiles = $main::exeonfiles; #say TOFILE "dumpINDESCEND(\$exeonfiles): " . dump($exeonfiles);
	$generatechance = $main::generatechance; 
	$file = $main::file;
	$preventsim = $main::preventsim;
	$fileconfig = $main::fileconfig; #say TOFILE "dumpINDESCEND(\$fileconfig): " . dump($fileconfig); # NOW GLOBAL. TO MAKE IT PRIVATE, FIX PASSING OF PARAMETERS IN CONTRAINTS PROPAGATION SECONDARY SUBROUTINES
	$outfile = $main::outfile;
	$tofile = $main::tofile;
	$report = $main::report;
	$simnetwork = $main::simnetwork;
	
	#open( OUTFILE, ">>$outfile" ) or die "Can't open $outfile: $!"; 
	open( TOFILE, ">>$tofile" ) or die "Can't open $tofile: $!";  
	$tee = new IO::Tee(\*STDOUT, ">>$tofile"); # GLOBAL ZZZ
	say "\nNow in Sim::OPT::Descend.\n";
	say $tee "\n#Now in Sim::OPT::Descend.\n";
	
	#say TOFILE "dump(\$repfile): " . dump($repfile); 
	%dowhat = %main::dowhat;

	%simtitles = %main::simtitles; #say "dumpINDESCEND(\@simtitles): " . dump(@simtitles);
	%retrievedata = %main::retrievedata;
	@keepcolumns = @main::keepcolumns;
	@weights = @main::weights;
	@weightsaim = @main::weightsaim;
	@varthemes_report = @main::varthemes_report;
	@varthemes_variations = @vmain::arthemes_variations;
	@varthemes_steps = @main::varthemes_steps;
	@rankdata = @main::rankdata; # CUT ZZZ
	@rankcolumn = @main::rankcolumn;
	%reportdata = %main::reportdata;
	@report_loadsortemps = @main::report_loadsortemps;
	@files_to_filter = @main::files_to_filter;
	@filter_reports = @main::filter_reports;
	@base_columns = @main::base_columns;
	@maketabledata = @main::maketabledata;
	@filter_columns = @main::filter_columns;
	%vals = %main::vals;
	
	my @simcases = @{ $dirfiles{simcases} }; #say "dump(\@simcases): " . dump(@simcases);
	my @simstruct = @{ $dirfiles{simstruct} }; #say "dump(\@simstruct): " . dump(@simstruct);
	my @morphcases = @{ $dirfiles{morphcases} };
	my @morphstruct = @{ $dirfiles{morphstruct} };
	my @retcases = @{ $dirfiles{retcases} }; say TOFILE "dumpINDESCEND2(\@retcases): " . dump(@retcases);
	my @retstruct = @{ $dirfiles{retstruct} }; say TOFILE"dump(\@retstruct): " . dump(@retstruct);
	my @repcases = @{ $dirfiles{repcases} };  say TOFILE"dumpINDESCEND(\@repcases): " . dump(@repcases);
	my @repstruct = @{ $dirfiles{repstruct} }; say TOFILE"dumpINDESCEND(\@repstruct): " . dump(@repstruct);
	my @mergecases = @{ $dirfiles{mergecases} }; say TOFILE"dumpINDESCEND(\@mergecases): " . dump(@mergecases);
	my @mergestruct = @{ $dirfiles{mergestruct} }; say TOFILE"dumpINDESCEND(\@mergestruct): " . dump(@mergestruct);
	my @descendcases = @{ $dirfiles{descendcases} }; say TOFILE"dumpINDESCEND(\@descendcases): " . dump(@descendcases);
	my @descendstruct = @{ $dirfiles{descendstruct} }; say TOFILE"dumpINDESCEND(\@descendstruct): " . dump(@descendstruct);
	
	my $morphlist = $dirfiles{morphlist}; #say "dump(\$dat{morphlist}): " . dump($dat{morphlist});
	my $morphblock = $dirfiles{morphblock};
	my $simlist = $dirfiles{simlist}; #say "dump(\$simlist): " . dump($simlist);
	my $simblock = $dirfiles{simblock};
	my $retlist = $dirfiles{retlist};
	my $retblock = $dirfiles{retblock};
	my $replist = $dirfiles{replist}; say TOFILE"dumpINDESCEND(\$replist): " . dump($replist);
	my $repblock = $dirfiles{repblock}; say TOFILE"dumpINDESCEND(\$repblock): " . dump($repblock);
	my $descendlist = $dirfiles{descendlist}; say TOFILE"dumpINDESCEND(\$descendlist): " . dump($descendlist);
	my $descendblock = $dirfiles{descendblock}; say TOFILE"dumpINDESCEND(\$descendblock): " . dump($descendblock);
	
	my $skipfile = $vals{skipfile}; say TOFILE "dump(\$skipfile): " . dump($skipfile);
	my $skipsim = $vals{skipsim}; say TOFILE "dump(\$skipsim): " . dump($skipsim);
	my $skipreport = $vals{skipreport}; say TOFILE "dump(\$skipreport): " . dump($skipreport);
		
	#my $getpars = shift;
	#eval( $getpars );

	#if ( fileno (MORPHLIST)            

	#my $getpars = shift;
	#eval( $getpars );
	
	my $instance = $instances[0]; # THIS WOULD HAVE TO BE A LOOP HERE TO MIX ALL THE MERGECASES!!! ### ZZZ
	
	my %d = %{$instance};
	my $countcase = $d{countcase}; say TOFILE "dump(\$countcase): " . dump($countcase);
	my $countblock = $d{countblock}; say TOFILE "dump(\$countblock): " . dump($countblock);
	my @miditers = @{ $d{miditers} }; say TOFILE "BEGINDESCENDdump(\@miditers): " . dump(@miditers);
	my @winneritems = @{ $d{winneritems} }; say TOFILE "dumpIN( \@winneritems) " . dump(@winneritems);
	my $countvar = $d{countvar}; say TOFILE "dump(\$countvar): " . dump($countvar);
	my $countstep = $d{countstep}; say TOFILE "dump(\$countstep): " . dump($countstep);						
	my $to = $d{to}; say TOFILE "dump(\$to): " . dump($to);
	my $origin = $d{origin}; say TOFILE "dump(\$origin): " . dump($origin);
	my @uplift = @{ $d{uplift} }; say TOFILE "dump(\@uplift): " . dump(@uplift);
	#eval($getparshere);
	
	my $skip = $vals{$countvar}{skip}; say TOFILE "dumpinreport(\$skip): " . dump($skip);
	
	my $rootname = Sim::OPT::getrootname(\@rootnames, $countcase); say TOFILE "dump(\$rootname): " . dump($rootname);
	my @blockelts = Sim::OPT::getblockelts(\@sweeps, $countcase, $countblock); say TOFILE "dumpIN( \@blockelts) " . dump(@blockelts);
	my @blocks = Sim::OPT::getblocks(\@sweeps, $countcase);  say TOFILE "dumpIN( \@blocks) " . dump(@blocks);
	my $toitem = Sim::OPT::getitem(\@winneritems, $countcase, $countblock); say TOFILE "dump(\$toitem): " . dump($toitem);
	my $from = Sim::OPT::getline($toitem); say TOFILE "dumpIN(\$from): " . dump($from);
	my %varnums = Sim::OPT::getcase(\@varinumbers, $countcase); say TOFILE "dumpIN---(\%varnums): " . dump(%varnums); 
	my %mids = Sim::OPT::getcase(\@miditers, $countcase); say TOFILE "dumpIN---(\%mids): " . dump(%mids); 
	#eval($getfly);
	
	my $stepsvar = Sim::OPT::getstepsvar($countvar, $countcase, \@varinumbers); say TOFILE "dump(\$stepsvar): " . dump($stepsvar); 
	my $varnumber = $countvar; say TOFILE "dump---(\$varnumber): " . dump($varnumber) . "\n\n";  # LEGACY VARIABLE
	my $contblocksplus = ($countblock + 1);
	my $countcaseplus = ($countcase + 1);
	
	say $tee "Descending into case $countcaseplus, block $contblocksplus.";

	my @columns_to_report = @{ $reporttempsdata[1] };  say TOFILE "dump(\@columns_to_report): " . dump(@columns_to_report); 
	my $number_of_columns_to_report = scalar(@columns_to_report); say TOFILE "dump(\$number_of_columns_to_report): " . dump($number_of_columns_to_report); 
	my $number_of_dates_to_mix = scalar(@simtitles); say TOFILE "dump(\$number_of_dates_to_mix): " . dump($number_of_dates_to_mix); 
	my @dates                    = @simtitles; say TOFILE "dump(\@dates): " . dump(@dates); 

	my $cleanmixed = "$repfile-clean.csv"; say TOFILE "dump(\$cleanmixed): " . dump($cleanmixed); 
	my $throwclean = $cleanmixed; $throwclean =~ s/\.csv//;
	my $selectmixed = "$throwclean-select.csv"; say TOFILE "dump(\$selectmixed): " . dump($selectmixed); 
	
	sub cleanselect
	{ 	# IT CLEANS THE MIXED FILE AND SELECTS SOME COLUMNS, THEN COPIES THEM IN ANOTHER FILE
		say $tee "Cleaning results for case $countcaseplus, block $contblocksplus.";
		open( MIXFILE, $repfile ) or die( "$!" ); say TOFILE "dump(\$repfile IN SUB cleanselect): " . dump($repfile); 
		my @lines = <MIXFILE>; say TOFILE "dump(MIXFILE \@lines): " . dump(@lines); 
		close MIXFILE;
		open( CLEANMIXED, ">$cleanmixed" ) or die( "$!" );
		foreach my $line ( @lines )
		{
			$line =~ s/\n/°/g;
			$line =~ s/\s+/,/g;
			$line =~ s/°/\n/g;
			print CLEANMIXED "$line";
		}
		close CLEANMIXED;
	
		# IT SELECTS SOME COLUMNS AND COPIES THEM IN ANOTHER FILE
		open( CLEANMIXED, $cleanmixed ) or die( "$!" );
		my @lines = <CLEANMIXED>; say TOFILE "dump(CLEANMIXED \@lines): " . dump(@lines); 
		close CLEANMIXED;
		
		open( SELECTEDMIXED, ">$selectmixed" ) or die( "$!" );
		foreach my $line (@lines)
		{
			my @elts = split(/\s+|,/, $line); ### DDD
			$elts[0] =~ /^(.*)_-(.*)/;
			my $touse = $1; say "dump(CLEANMIXED \$touse): " . dump($touse); 
			$touse =~ s/$mypath\///;
			print SELECTEDMIXED "$touse,";
			my $countout = 0;
			foreach my $elmref (@keepcolumns)
			{
				my @cols = @{$elmref};
				my $countin = 0;
				foreach my $elm (@cols)
				{
					if ( Sim::OPT::odd($countin) )
					{
						print SELECTEDMIXED "$elts[$elm]";
					}
					else
					{
						print SELECTEDMIXED "$elm";
					}
						
					if ( ( $countout < $#keepcolumns  ) or ( $countin < $#cols) )
					{
						print  SELECTEDMIXED ",";
					}
					else 
					{
						print  SELECTEDMIXED "\n";
					}
					$countin++;
				}
				$countout++;
			}
		}
		close SELECTEDMIXED;
	}
	&cleanselect();
	
	my $throw = $selectmixed; $throw =~ s/\.csv//;
	my $weight = "$throw-weight.csv"; say TOFILE "dump(\$weight): " . dump($weight);  # THIS WILL HOST PARTIALLY SCALED VALUES, MADE POSITIVE AND WITH A CEILING OF 1
	sub weight
	{	
		say $tee "Scaling results for case $countcaseplus, block $contblocksplus.";
		open( SELECTEDMIXED, $selectmixed ) or die( "$!" ); say TOFILE "dump(\$selectmixed IN SUB weight ): " . dump($selectmixed);
		my @lines = <SELECTEDMIXED>; say TOFILE "dump(SELECTEDMIXED \@lines): " . dump(@lines); 
		close SELECTEDMIXED;
		my $counterline = 0;
		open( WEIGHT, ">$weight" ) or die( "$!" );
		
		my @containerone;
		my @containernames;
		foreach my $line (@lines)
		{
			$line =~ s/^[\n]//;
			my @elts = split(/\s+|,/, $line);
			my $touse = shift(@elts);
			my $countcol = 0;
			my $countel = 0;
			foreach my $elt (@elts)
			{
				if ( Sim::OPT::odd($countel) )
				{
					push ( @{$containerone[$countcol]}, $elt); #print TOFILE "ELT: $elt\n";
					$countcol++;
				}
				push (@containernames, $touse);
				$countel++;
			}
		} 
		say TOFILE "dump(SELECTEDMIXED \@containernames): " . dump(@containernames); 
			
		my @containertwo;
		my @containerthree;
		$countcolm = 0;
		my @optimals;
		foreach my $colref ( @containerone )
		{
			my @column = @{ $colref }; # DEREFERENCE
			
			if ( $weights[$countcolm] < 0 ) # TURNS EVERYTHING POSITIVE
			{
				foreach my $el (@column)
				{
					$el = ($el * -1);
				}
			}
			
			if ( max(@column) != 0) # FILLS THE UNTRACTABLE VALUES
			{
				push (@maxes, max(@column));
			}
			else
			{
				push (@maxes, "NOTHING1");
			}
					
			print TOFILE "MAXES: " . Dumper(@maxes) . "\n";
			print TOFILE "DUMPCOLUMN: " . Dumper(@column) . "\n";
			
			foreach my $el (@column)
			{
				my $eltrans;
				if ( $maxes[$countcolm] != 0 )
				{
					print TOFILE "\$weights[\$countcolm]: $weights[$countcolm]\n";
					$eltrans = ( $el / $maxes[$countcolm] ) ;
				}
				else
				{
					$eltrans = "NOTHING2" ;
				}
				push ( @{$containertwo[$countcolm]}, $eltrans) ; print TOFILE "ELTRANS: $eltrans\n";
			}
			$countcolm++;
		} 
		print TOFILE "CONTAINERTWO " . Dumper(@containertwo) . "\n";
				
		my $countline = 0;
		foreach my $line (@lines)
		{
			$line =~ s/^[\n]//;
			my @elts = split(/\s+|,/, $line);		
			my $countcolm = 0;
			foreach $eltref (@containertwo)
			{
				my @col =  @{$eltref};
				my $max = max(@col); print TOFILE "MAX IN SUB weight: $max\n";
				my $min = min(@col); print TOFILE "MIN IN SUB weight: $min\n";
				my $floordistance = ($max - $min);
				my $el = $col[$countline];
				my $rescaledel;
				if ( $floordistance != 0 )
				{
					$rescaledel = ( ( $el - $min ) / $floordistance ) ;
				}
				else
				{
					$rescaledel = 1;
				}
				if ( $weightsaim[$countcolm] < 0)
				{
					$rescaledel = ( 1 - $rescaledel);
				}
				push (@elts, $rescaledel);
				$countcolm++;
			}
			
			$countline++;
			
			my $counter = 0;
			foreach my $el (@elts)
			{		
				print WEIGHT "$el";
				if ($counter < $#elts)
				{ 
					print WEIGHT ",";
				}
				else
				{
					print WEIGHT "\n";
				}
				$containerthree[$counterline][$counter] = $el;
				$counter++;
			}
			$counterline++;
		}
		close WEIGHT;
		print TOFILE "CONTAINERTHREE: " . Dumper(@containerthree) . "\n";
	}
	&weight(); #
	
	my $weighttwo = "$throw-weighttwo.csv"; # THIS WILL HOST PARTIALLY SCALED VALUES, MADE POSITIVE AND WITH A CELING OF 1
	sub weighttwo
	{
		say $tee "Weighting results for case $countcaseplus, block $contblocksplus.";
		open( WEIGHT, $weight ); say TOFILE "dump(\$weight IN SUB weighttwo): " . dump($weight);
		my @lines = <WEIGHT>;
		close WEIGHT;
		open( WEIGHTTWO, ">$weighttwo" ); say TOFILE "dump(\$weighttwo): " . dump($weighttwo);
		my $counterline;
		foreach my $line (@lines)
		{
			$line =~ s/^[\n]//;
			my @elts = split(/\s+|,/, $line);
			my $counterelt = 0;
			my $counterin = 0;
			my $sum = 0;
			my $avg;
			my $numberels = scalar(@keepcolumns);
			foreach my $elt (@elts)
			{
				my $newelt;
				if ($counterelt > ( $#elts - $numberels ))
				{
					print TOFILE "ELT: $elt\n";
					$newelt = ( $elt * abs($weights[$counterin]) ); # print TOFILE "NEWELT: $newelt\n";
					print TOFILE "ABS" . abs($weights[$counterin]) . "\n";
					$sum = ( $sum + $newelt ) ; # print TOFILE "SUM: $sum\n";
					$counterin++;
				}
				$counterelt++;
			}
			$avg = ($sum / scalar(@keepcolumns) );
			push ( @elts, $avg);
			
			my $counter = 0;
			foreach my $elt (@elts)
			{		
				print WEIGHTTWO "$elt";
				if ($counter < $#elts)
				{ 
					print WEIGHTTWO ",";
				}
				else
				{
					print WEIGHTTWO "\n";
				}
				$counter++;
			}
			$counterline++;
		}
	}
	&weighttwo();	
	
	say TOFILE "dump(\$repfile BEFORE SUB sortmixed): " . dump( $repfile );
	my $sortmixed = "$repfile-sortmixed.csv"; say TOFILE "dump(\$sortmixed BEFORE SUB sortmixed): " . dump( $sortmixed );
	#if ($repfile) { $sortmixed = "$repfile-sortmixed.csv"; } else { die( "$!" ); } # globsAL!
	sub sortmixed
	{
		say $tee "Processing results for case $countcaseplus, block $contblocksplus.";
		open( WEIGHTTWO, $weighttwo ) or die( "$!" ); say TOFILE "dump(\$weighttwo IN SUB sortmixed): " . dump($weighttwo);
		open( SORTMIXED_, ">$sortmixed" ) or die( "$!" ); say TOFILE "dump(\$sortmixed): " . dump($sortmixed);
		my @lines = <WEIGHTTWO>;
		close WEIGHTTWO;
		my $count = 0;
		foreach ( @lines )
		{
			$_ = "$containernames[$count]," . "$_";
			$count++;
		}
		say TOFILE "TAKEOPTIMA--dump(\@lines): " . dump(@lines);
		
		my $line = $lines[0];
		my @eltstemp = split(/,/, $line);
		my $numberelts = scalar( @eltstemp );
		
		#my @sorted = sort { (split(/,/, $b))[$#eltstemp] <=> (split(/,/, $a))[$#eltstemp] } @lines;
		my @sorted = sort { (split(/,/, $a))[$#eltstemp] <=> (split(/,/, $b))[$#eltstemp] } @lines;
		for (my $h = 0; $h <= $#sorted; ++$h) 
		{
			$sorted[$h] =~ s/^,//;
			print SORTMIXED_ $sorted[$h];
		}
		
		#if ($numberelts > 0) { print SORTMIXED_ `sort -t, -k$numberelts -n $weighttwo`; } 
		
		#my @sorted = sort { $b->[1] <=> $a->[1] } @lines;
		
		#print SORTMIXED_ map $_->[0],
		#sort { $a->[$#eltstemp] <=> $b->[$#eltstemp] }
		#map { [ [ @lines ] , /,/ ] }
		#foreach my $elt (@sorted)
		#{
		#	print SORTMIXED "$elt";
		#}

		#if ($numberelts > 0) { print SORTMIXED_ `sort -n -k$numberelts,$numberelts -t , $weighttwo`; } ### ZZZ
		# print SORTMIXED_ `sort -n -k$numberelts -n $weighttwo`; 
		close SORTMIXED_;
	}
	&sortmixed;
	
	##########################################################
	
	
	sub takeoptima
	{
		#my $pass_signal = ""; # IF VOID, GAUSS SEIDEL METHOD. IF 0, JACOBI METHOD. ...
		
		#say TOFILE `cat $sortmixed`;
		#say TOFILE "TAKEOPTIMA cat \$sortmixed: $sortmixed";
		
		open( SORTMIXED_, $sortmixed ) or die( "$!" );
		my @lines = <SORTMIXED_>;
		close SORTMIXED_;
		
		my $winnerentry = $lines[0]; #ay TOFILE "dump( IN SUB TAKEOPTIMA\$winnerentry): " . dump($winnerentry);
		chomp $winnerentry;
		
		my @winnerelms = split(/\s+|,/, $winnerentry);
		my $winnerline = $winnerelms[0]; say TOFILE "dump(TAKEOPTIMA\$winnerline): " . dump($winnerline);
		my $winnerval = $winnerelms[$#winnerelms];
		push ( @{ $uplift[$countcase][$countblock] }, $winnerval); say TOFILE "TAKEOPTIMA->\@winneritems " . dump(@winneritems);
		
		my $message;
		unless ( ( "$^O" eq "MSWin32" ) or ( "$^O" eq "MSWin64" ) ) 
		{
			$message = "$mypath/attention.txt";
		}
		else
		{
			$message = "$mypath\\attention.txt";
		}
		
		open( MESSAGE, ">>$message");
		my $countelm = 0;
		foreach my $elm (@lines)
		{
			my @lineelms = split( /\s+|,/, $elm );
			my $val = $lineelms[$#lineelms];
			my $case = $lineelms[0];
			{
				if ($countelm > 0)
				{
					if ( $val ==  $winnerval)
					{
						say MESSAGE "Attention. At case $countcaseplus, block $contblocksplus. There is a tie between optimal cases. Besides case $winnerline, producing a compound objective function of $winnerval, there is the case $case producing the same objective function value. Case $winnerline has been used for the search procedures which follow.\n";
					}
				}
			}
			$countelm++;
		}
		close (MESSAGE);
		
		my $copy = $winnerline;
		$copy =~ s/$mypath\/$file//;
		my @taken = Sim::OPT::extractcase("$copy", \%mids); say TOFILE "TAKEOPTIMA--->taken: " . dump(@taken);
		my $newtarget = $taken[0]; say TOFILE "TAKEOPTIMA\$newtarget--->: $newtarget";
		$newtarget =~ s/$mypath\///;
		my %newcarrier = %{$taken[1]}; say TOFILE "TAKEOPTIMA\%newcarrier--->" . dump(%newcarrier);
		say TOFILE "TAKEOPTIMA BEFORE->\@miditers: " . dump(@miditers);
		%{ $miditers[$countcase] } = %newcarrier; say TOFILE "TAKEOPTIMA AFTER->\@miditers: " . dump(@miditers);
		
		#say "2\$countcase : " . dump($countcase);
		#say "2\@rootnames : " . dump(@rootnames);
		#say "2\$countblock : " . dump($countblock);
		#say "2\@sweeps : " . dump(@sweeps);
		#say "2\@varinumbers : " . dump(@varinumbers);
		#say "2\@miditers : " . dump(@miditers);
		#say "2\@winneritems : " . dump(@winneritems);
		#say "2\@morphcases : " . dump(@morphcases);
		#say "2\@morphstruct : " . dump(@morphstruct);
		
		say TOFILE "TAKEOPTIMA FINAL ->\$countcase " . dump($countcase);
		say TOFILE "TAKEOPTIMA FINAL ->\$countblock " . dump($countblock);
		say TOFILE "TAKEOPTIMA FINAL ->\@miditers " . dump(@miditers);
		say TOFILE "TAKEOPTIMA FINAL ->\@winneritems " . dump(@winneritems);
		say TOFILE "TAKEOPTIMA FINAL ->\%dirfiles " . dump(%dirfiles);
		say TOFILE "TAKEOPTIMA FINAL ->\@uplift " . dump(@uplift);
		
		$countblock++; ### !!!
		
		say $tee "TAKEOPTIMA FINAL ->\$countblock " . dump($countblock);
		say $tee "TAKEOPTIMA FINAL ->\scalar( \@blocks ) " . dump( scalar( @blocks ) );
		
		# STOP CONDITION
		if ( $countblock == scalar( @blocks ) ) # NUMBER OF BLOCK OF THE CURRENT CASE
		{ 
			say $tee "TAKEOPTIMA FINAL ->\$countblock " . dump($countblock);
			my @morphcases = grep -d, <$mypath/$file_*>;
			say $tee "#Optimal option for case  $countcaseplus: $newtarget";
			#my $instnum = Sim::OPT::countarray( @{ $morphstruct[$countcase] } );
			say $tee "#Gross number of instances: $instnum." ;
			my $netinstnum = scalar(@morphcases);
			say $tee "#Net number of instances: $netinstnum." ;
			open( RESPONSE , ">$mypath/response.txt" );
			say RESPONSE "#Optimal option for case  $countcaseplus: $newtarget";
			say RESPONSE "#Gross number of instances: $instnum." ;
			say RESPONSE "#Net number of instances: $netinstnum." ;
				
			$countblock = 0;
			$countcase = $countcase++;
			if ( $countcase == scalar( @sweeps ) )# NUMBER OF CASES OF THE CURRENT PROBLEM
			{
				exit (say $tee "#END RUN.");					
			}
		}
		else
		{
			push ( @{ $winneritems[$countcase][$countblock] }, $newtarget); say TOFILE "TAKEOPTIMA->\@winneritems " . dump(@winneritems);
			"#Leaving case " . ($countcase + 1) . ", block " . ($countblock + 1) . " and descending!\ ";
			Sim::OPT::callcase( { countcase => $countcase, countblock => $countblock, 
			miditers => \@miditers,  winneritems => \@winneritems, 
			dirfiles => \%dirfiles, uplift => \@uplift } );
		}
	}
	&takeoptima();
	close OUTFILE;
	close TOFILE;
}    # END SUB descend

1;

__END__

=head1 NAME

Sim::OPT::Descend.

=head1 SYNOPSIS

  use Sim::OPT;
  opt;

=head1 DESCRIPTION

Sim::OPT::Descent is an module collaborating with the Sim::OPT module for performing block coordinate descent. It closes the loop formed by Sim::OPT -> Sim::OPT::Morph -> Sim::OPT::Sim -> Sim::OPT::Report::retrieve -> Sim::OPT::Report::report -> Sim::OPT::Descent -> Sim::OPT, which repeats at every block search cycle. It is a circularly recursive loop. 

The objective function for rating the performances of the candidate solutions can be obtained by the weighting of objective functions (performance indicators) performed by the Sim::OPT::Report module, which follows user-specified criteria.

=head2 EXPORT

"descend".

=head1 SEE ALSO

An example of configuration instructions for Sim::OPT::Descend is included in the comments in the "esp.pl" file, which is packed in "optw.tar.gz" file in "examples" directory in this distribution. But mostly, 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-2015 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 2 or later.


=cut
