#!/usr/bin/perl -w

use 5.034;

# presupuestos ordenados de + a - y en U represupestar hacia arriba

# Requisitos: % incremento postivo máximo del total y de cada partida,
# incluyendo decrementos 

# Se aleatoriza dentro de los rangos y se mide la idoneidad por el mayor
# incremento postivos de las partidas de arriba (más prioridad)

# Esto se puede hacer a través de un índice de las mejores 3, 5, etc partidas

####

# año 2020, Ayto

############################################ (c) Jesús Lozano Mosterín, 2023 ###################################################################

# my $ingresos = 233_020_000;  # 2021


if (0){
"
  GASTOS DE PERSONAL
  65.947.900,00

GASTOS CORRIENTES EN BIENES Y SERVICIOS
  40.242.345,03
  
GASTOS FINANCIEROS
  247.522,04

TRANSFERENCIAS CORRIENTES
  96.899.900,00
  
FONDO DE CONTINGENCIA Y OTROS IMPREVISTOS
  500.000,00

INVERSIONES REALES
  12.183.872,81
  
TRANSFERENCIAS DE CAPITAL
  7.715.724,39

ACTIVOS FINANCIEROS
  2.714.183,16
  
PASIVOS FINANCIEROS
  20.621.086,82

TOTAL
  247.072.534,25
  ";
}

# version 4 (2024) -> aditional requirements. I.e. minorate negative cuts

my @gasto = qw(Personal CorrientesByS Financieros Transf_Corrientes Provisiones Inversiones Transf_Capital Activos_fin Pasivos_fin);              
# my @partida = qw(62008400 46165000 674714 88865500 400000 11268893 7956853 3614700 18864802);  # 2021
my @partida = (65_947_900,40_242_345,247_522,96_899_900,500_000,12_183_872,7_715_724,2_714_183,20_621_086);   # 2022 PRESUPUESTADO
my $ingresos = 0;
$ingresos += $_ for (@partida);

my @prio = qw(0 1 2 4 5 3 6 8 7);  # ordenación por prioridades, THE HACK!

my $INCREMENTO = 0.06;  # este va a ser el objetivo
my ($low, $high) = (-0.05, 0.15);
my $range = $high - $low;
my $n = scalar @partida;
my @r;
# my $nsol = 20; # número de soluciones
# my $c = 0;

my $resultant = $low;
my (@ppto, $result, $sum, $cuts, $MINcuts);
$MINcuts = 9e99;

alarm (60*5); # 5 minutos  
say "TIMEOUT = 5 min.";
say "";

for (my $c; ; ){
    $r[$_] = $low + rand() * $range for (0 .. $n-1);
    @r = sort { $b <=> $a } @r;  # de más a menos
    $cuts = 0;
    
    my $s = 0;                           # sum of any good and bad iteration
    for my $j (@prio){
	$ppto[$j] = (1+$r[$j]) * $partida[$j];
	$s += $ppto[$j];
	if ( $r[$j] < 0 ){    # cut detected
	    $cuts += $ppto[$j];
	}
    }
    $result = ($s / $ingresos) - 1;    
    next if ( $result > $INCREMENTO );
    
    if ($result >= $resultant){
	if ( $cuts <= $MINcuts ){
	    $MINcuts = $cuts;
	    $c++;                    # succes
	}else{
	    next;
	}
	$resultant = $result;
	say "-" x 70;
	say "\n          Numeración de propuesta: $c";      # espacio reservado para publicidad 
	say "GASTO $gasto[$_] = $ppto[$_]€ (",100*$r[$_]," %)" for (@prio);
	say "\nIncremento = $result (tanto por uno)";
	say "Recortes de presupuesto = $cuts €";
	$sum = 0;
	$sum += $_ for @ppto;
	say "Sumas y saldos:   gasto total próximo año = $sum€   ingresos anterior año = $ingresos€";
	say "Incremento comprobado = ", 100*( ($sum / $ingresos) -1), " %";
	say "";
	sleep 1;
    }
}

exit 3;

__END__
  
Con un plazo de 5 minutos parece dar muchas versiones "buenas"
  La v.4 introduce supuestos realistas para minimizar las soluciones factibles
  y la progresión hacia mayor adaptación de requisitos.

Recommended usage:
  $ perl ppto4 > LISTADO.txt

