#!/usr/bin/perl -w

use 5.034;

# en esta v.3 se trata de interpolar entre el mínimo f() de error negativo y el máximo f() de error positivo 
# definido error como objetivo - función de estimación

my $N = 401;    # abundante
my @datos;
my $s = 0;
for (0..$N-1){  # son 401 datos para una ecuación SUM $w_i * $datos_i = OBJETIVO
    push @datos, int (rand()*123456789);
    $s += $datos[-1];
}
say "Datos generados. $N parámetros. Suma = $s";

### Comienzo de main
my $t0 = time();
my @cand;
my $err;
my $k = 0;
my $record = 9e99;
my @candidato;
my $objetivo = -55555.55555;             # OBJETIVO, importante
my $et = 60*15;                          # 15 minutos de presupuesto de tiempo
my (@min, @max);
my $ok = 0;
my ($dir,$dirmin,$dirmax);
push @candidato, (rand()-0.5)/10_000 for (0..$N-1);

loop1:                          # un nuevo reinicio aleatorio     
@cand = @candidato;

while (1){                          # tras pequeña modificación, loop. Es el principal, porque llama al sub function()
    select(undef,undef,undef,0.001);
    $err = $objetivo - function(@cand);
    $dir = abs($err);
    
    if ( $dir <= $record ){
	if ($dir < $record) {
	    say "$k) OBJ = $objetivo -> error $err   ", time()-$t0, " seconds.";
	    if ($err < 0){
		@min = @cand;
		$dirmin = $dir;
		$ok++ if ($ok == 0);
	    }elsif ($err > 0){
		@max = @cand;
		$dirmax = $dir;
		$ok++ if ($ok == 1);
	    }
	}
	$record = $dir;
	@candidato = @cand;
	if ($ok == 2) {
	    @candidato = ();
	    for my $i (0 .. $N-1){
		$candidato[$i] = ($dirmax*$min[$i]+$dirmin*$max[$i])/($dirmin+$dirmax);
	    }
	}
	exit 3 if $err == 0;
    }elsif (++$k % 100_000 == 0){
	goto loop1;
    }

    last if (time()-$t0 > $et);
    muta();
}

exit 2;

sub muta {
    my $p = int( rand() * $N );
    my $q = 2 * rand() / $N;
    if ( $err < 0 ) {
	$cand[$p] = -1*$q;
    }else{
	$cand[$p] = $q;
    }
}

sub function {
    my @w = @_;
    my $sum = 0;
    $sum += $_ * $datos[$_] for (@w);
    return $sum;
}

__END__

