Algorithm-Bertsekas
view release on metacpan or search on metacpan
lib/Algorithm/Bertsekas.pm view on Meta::CPAN
} else {
for my $i ( 0 .. $#matrix ) {
for my $j ( 0 .. $#{$matrix[$i]} ) {
$matrix[$i]->[$j] = $max_matrix_value - $matrix[$i]->[$j] ;
#$matrix[$i]->[$j] = 99 * ( $max_matrix_value - $matrix[$i]->[$j] ) / $range; # new scale: Min = 0 <---> Max = 99
}}
}
}
sub auctionRound {
my ( $matrix_ref, $epsilon, $verbose ) = @_;
my @matrix = @$matrix_ref;
my ( %info, %choose_object, %count_object, %choose_person );
my %this_person_can_choose_n_different_objects;
my %objects_with_the_same_values;
my $number_of_assignned_object = scalar keys %assignned_object;
if ( $verbose >= 8 )
{
print $output "\n Start: Matrix Size N x M: $min_size x $max_size ; epsilon_scaling = $epsilon_scaling ; Number of Global Iterations = $iter_count_global ; Number of Local Iterations = $iter_count_local ; epsilon = $epsilon ; \$number_of_assignned_...
foreach my $person ( sort { $a <=> $b } keys %assignned_person ){
my $object = $assignned_person{$person};
printf $output " \$assignned_person{%3s} --> object %3s --> \$price_object{%3s} = $price_object{$object} \n", $person, $object, $object;
}
foreach my $object ( sort { $a <=> $b } keys %price_object ){
printf $output " \$price_object{%3s} = $price_object{$object} \n", $object;
}
print $output "\n";
}
my $seen_ghost;
for my $person ( 0 .. $max_size - 1 )
{
last if $seen_ghost; # don't need to fill the matrix with zeros, that is, don't need to convert rectangular N x M to square matrix by padding zeroes. Need just one more row: N+1 x M
if ( not defined $assignned_person{$person} )
{
## ------> j object 0 object 1 object 2 object 3 ... object (M - 1)
## | person 0 price_0_0 price_0_1 price_0_2 price_0_3 price_0_j
## | person 1 price_1_0
## | person 2 price_2_0
## | ...
## i person (N - 1) price_i_0
my ( $Opt01ObjForPersonI, $Opt02ObjForPersonI, $Opt03ObjForPersonI );
my ( $Opt01ValForPersonI, $Opt02ValForPersonI, $Opt03ValForPersonI ) = ( -10 * exp ($max_matrix_value), -10 * exp ($max_matrix_value), -10 * exp ($max_matrix_value) );
my ( $Opt01ObjForPersonI_new_list, $Opt02ObjForPersonI_new_list, $Opt03ObjForPersonI_new_list );
my ( $Opt01ValForPersonI_new_list, $Opt02ValForPersonI_new_list, $Opt03ValForPersonI_new_list ) = ( -10 * exp ($max_matrix_value), -10 * exp ($max_matrix_value), -10 * exp ($max_matrix_value) );
my $Opt01ValForPersonI_old_list;
my $bidForPersonI;
my %current_value;
my @updated_price;
$seen_ghost++ if ( not defined $matrix[$person] and $min_size < $max_size );
# The @objects_with_greater_benefits list are updated dynamically by $objects_desired_by_this{$person} by considering the current price (or current value) of objects.
# For each person, the Current Value $current_value{$object} of the most desired objects contained in the @objects_with_greater_benefits list tends to converge to a specific value.
my @objects_with_greater_benefits = keys %{$objects_desired_by_this{$person}}; # sort { $a <=> $b }
# There is at least one object in the @objects_with_greater_benefits list whose price is updated ? use old list : generate new list;
for my $object ( @objects_with_greater_benefits ) # use old list
{
my $matrix_value = $seen_ghost ? 0 : $matrix[$person]->[$object];
$current_value{$object} = $matrix_value - $price_object{$object};
push @updated_price, $object if ( $objects_desired_by_this{$person}{$object} == $current_value{$object} );
if ( $current_value{$object} > $Opt01ValForPersonI ) # search for the best 3 objects
{
$Opt03ValForPersonI = $Opt02ValForPersonI;
$Opt03ObjForPersonI = $Opt02ObjForPersonI;
$Opt02ValForPersonI = $Opt01ValForPersonI;
$Opt02ObjForPersonI = $Opt01ObjForPersonI;
$Opt01ValForPersonI = $current_value{$object};
$Opt01ObjForPersonI = $object;
$Opt01ValForPersonI_old_list = $Opt01ValForPersonI;
}
elsif ( $current_value{$object} > $Opt02ValForPersonI )
{
$Opt03ValForPersonI = $Opt02ValForPersonI;
$Opt03ObjForPersonI = $Opt02ObjForPersonI;
$Opt02ValForPersonI = $current_value{$object};
$Opt02ObjForPersonI = $object;
}
elsif ( $current_value{$object} > $Opt03ValForPersonI )
{
$Opt03ValForPersonI = $current_value{$object};
$Opt03ObjForPersonI = $object;
}
if ( $verbose >= 8 ){
printf $output " personI = %3s ; objectJ = %3s ; Current Value %20.5f = \$matrix[%3s][%3s] %12.0f - \$price_object{%3s} %20.5f <old list> Max01_CurVal = %12.5f (%3s), Max02_CurVal = %12.5f (%3s), Max03_CurVal = %12.5f (%3s)\n",
$person, $object, $current_value{$object}, $person, $object, $matrix_value, $object, $price_object{$object},
$Opt01ValForPersonI, defined $Opt01ObjForPersonI ? $Opt01ObjForPersonI : '',
$Opt02ValForPersonI, defined $Opt02ObjForPersonI ? $Opt02ObjForPersonI : '',
$Opt03ValForPersonI, defined $Opt03ObjForPersonI ? $Opt03ObjForPersonI : '';
}
}
if ( not @updated_price and not $locked_list{$person} ) # if all prices are outdated
{
for my $object ( 0 .. $max_size - 1 ) # generate new list
{
next if ( defined $current_value{$object} );
my $matrix_value = $seen_ghost ? 0 : $matrix[$person]->[$object];
$current_value{$object} = $matrix_value - $price_object{$object};
if ( $current_value{$object} > $Opt01ValForPersonI_new_list ) # to find the best 3 objects in the complementary subset <new list>
{
$Opt03ValForPersonI_new_list = $Opt02ValForPersonI_new_list;
$Opt03ObjForPersonI_new_list = $Opt02ObjForPersonI_new_list;
$Opt02ValForPersonI_new_list = $Opt01ValForPersonI_new_list;
$Opt02ObjForPersonI_new_list = $Opt01ObjForPersonI_new_list;
$Opt01ValForPersonI_new_list = $current_value{$object};
$Opt01ObjForPersonI_new_list = $object;
}
elsif ( $current_value{$object} > $Opt02ValForPersonI_new_list )
{
$Opt03ValForPersonI_new_list = $Opt02ValForPersonI_new_list;
$Opt03ObjForPersonI_new_list = $Opt02ObjForPersonI_new_list;
$Opt02ValForPersonI_new_list = $current_value{$object};
$Opt02ObjForPersonI_new_list = $object;
}
elsif ( $current_value{$object} > $Opt03ValForPersonI_new_list )
{
$Opt03ValForPersonI_new_list = $current_value{$object};
$Opt03ObjForPersonI_new_list = $object;
}
if ( $verbose >= 8 ){
printf $output " personI = %3s ; objectJ = %3s ; Current Value %20.5f = \$matrix[%3s][%3s] %12.0f - \$price_object{%3s} %20.5f <new list> Max01_CurVal = %12.5f (%3s), Max02_CurVal = %12.5f (%3s), Max03_CurVal = %12.5f (%3s)\n",
$person, $object, $current_value{$object}, $person, $object, $matrix_value, $object, $price_object{$object},
$Opt01ValForPersonI_new_list, defined $Opt01ObjForPersonI_new_list ? $Opt01ObjForPersonI_new_list : '',
$Opt02ValForPersonI_new_list, defined $Opt02ObjForPersonI_new_list ? $Opt02ObjForPersonI_new_list : '',
$Opt03ValForPersonI_new_list, defined $Opt03ObjForPersonI_new_list ? $Opt03ObjForPersonI_new_list : '';
}
}
# to find the best 3 out of 6 objects
if ( $Opt01ValForPersonI_new_list > $Opt01ValForPersonI )
{
$Opt03ValForPersonI = $Opt02ValForPersonI;
$Opt03ObjForPersonI = $Opt02ObjForPersonI;
$Opt02ValForPersonI = $Opt01ValForPersonI;
$Opt02ObjForPersonI = $Opt01ObjForPersonI;
$Opt01ValForPersonI = $Opt01ValForPersonI_new_list;
$Opt01ObjForPersonI = $Opt01ObjForPersonI_new_list;
}
elsif ( $Opt01ValForPersonI_new_list > $Opt02ValForPersonI )
{
$Opt03ValForPersonI = $Opt02ValForPersonI;
$Opt03ObjForPersonI = $Opt02ObjForPersonI;
$Opt02ValForPersonI = $Opt01ValForPersonI_new_list;
$Opt02ObjForPersonI = $Opt01ObjForPersonI_new_list;
}
elsif ( $Opt01ValForPersonI_new_list > $Opt03ValForPersonI )
{
$Opt03ValForPersonI = $Opt01ValForPersonI_new_list;
$Opt03ObjForPersonI = $Opt01ObjForPersonI_new_list;
}
if ( $Opt02ValForPersonI_new_list > $Opt02ValForPersonI )
{
$Opt03ValForPersonI = $Opt02ValForPersonI;
$Opt03ObjForPersonI = $Opt02ObjForPersonI;
$Opt02ValForPersonI = $Opt02ValForPersonI_new_list;
$Opt02ObjForPersonI = $Opt02ObjForPersonI_new_list;
}
elsif ( $Opt02ValForPersonI_new_list > $Opt03ValForPersonI )
{
$Opt03ValForPersonI = $Opt02ValForPersonI_new_list;
$Opt03ObjForPersonI = $Opt02ObjForPersonI_new_list;
}
if ( $Opt03ValForPersonI_new_list > $Opt03ValForPersonI )
{
$Opt03ValForPersonI = $Opt03ValForPersonI_new_list;
$Opt03ObjForPersonI = $Opt03ObjForPersonI_new_list;
}
}
$bidForPersonI = $Opt01ValForPersonI - $Opt02ValForPersonI + $epsilon;
my @objects_with_same_values;
if ( $Opt01ValForPersonI == $Opt02ValForPersonI ) # this person can choose different objects that have the same values = $Opt01ValForPersonI
{
@objects_with_same_values = grep { $current_value{$_} == $Opt01ValForPersonI } keys %current_value;
$objects_with_the_same_values{$_}{$person} = $Opt01ValForPersonI for (@objects_with_same_values);
$count_object{$_}++ for (@objects_with_same_values);
if ( not @updated_price and defined $Opt01ValForPersonI_old_list ){
for my $object ( @objects_with_same_values ){
next unless ( $current_value{$object} > $Opt01ValForPersonI_old_list ); # objects in the new list that have values greater than the objects in the old list
$objects_desired_by_this{$person}{$object} = $current_value{$object}; # add information about the most desired objects
}
}
} else
{
$choose_object{$Opt01ObjForPersonI}++;
if ( (not defined $info{$Opt01ObjForPersonI}) || ($bidForPersonI > $info{$Opt01ObjForPersonI}{'bid'}) || ($bidForPersonI == $info{$Opt01ObjForPersonI}{'bid'} and $current_value{$Opt01ObjForPersonI} > $info{$Opt01ObjForPersonI}{'CurVal'}) )
{
$info{$Opt01ObjForPersonI}{'bid' } = $bidForPersonI; # Stores the bidding info for future use
$info{$Opt01ObjForPersonI}{'person'} = $person;
$info{$Opt01ObjForPersonI}{'CurVal'} = $current_value{$Opt01ObjForPersonI};
#printf " object = %3s ; person = %3s ; bid = %12.5f ; CurVal = %12.5f \n", $Opt01ObjForPersonI, $info{$Opt01ObjForPersonI}{'person'}, $info{$Opt01ObjForPersonI}{'bid'}, $info{$Opt01ObjForPersonI}{'CurVal'}; sleep 1;
}
}
if ( $epsilon_scaling >= 6 and $epsilon_scaling % 2 == 0 and not $seen_person{$person}++ ) # filter the old list
{
for my $object ( @objects_with_greater_benefits ){ # frequently check the quality of objects in the old list
next if ( $current_value{$object} >= $Opt03ValForPersonI );
next unless ( ($Opt03ValForPersonI - $current_value{$object}) > $min_size * $epsilon ); # critical value ($min_size * $epsilon)
delete $objects_desired_by_this{$person}{$object}; # delete objects of little benefit from the old list
printf $output "<> PersonI = %3s ; *** delete the object %3s from the old list *** \n", $person, $object if ( $verbose >= 8 );
}
}
if ( not @updated_price ) # if all prices are outdated
{
for my $object ( @objects_with_greater_benefits ){
next unless ( defined $objects_desired_by_this{$person}{$object} );
$objects_desired_by_this{$person}{$object} = $current_value{$object}; # update current values for all objects in the old list
}
$objects_desired_by_this{$person}{$Opt01ObjForPersonI} = $current_value{$Opt01ObjForPersonI}; # add information about the most desired objects
$objects_desired_by_this{$person}{$Opt02ObjForPersonI} = $current_value{$Opt02ObjForPersonI} if (defined $Opt02ObjForPersonI);
$objects_desired_by_this{$person}{$Opt03ObjForPersonI} = $current_value{$Opt03ObjForPersonI} if (defined $Opt03ObjForPersonI);
$locked_list{$person} = 1 if ( $epsilon_scaling > (1/10) * $max_epsilon_scaling and ($Opt03ValForPersonI - $Opt01ValForPersonI_new_list) > $min_size * $epsilon );
$locked_list{$person} = 1 if ( $epsilon_scaling > (3/10) * $max_epsilon_scaling ); # Lock the old list. Is this the minimum value to find a possible solution?
delete $locked_list{$person} if ( $epsilon == 1/(1+$min_size) ); # Otherwise unlock the person's old list in the last $epsilon_scaling round.
}
if ( $verbose >= 8 ){
my @old_list = sort { $a <=> $b } @objects_with_greater_benefits;
my @new_list = sort { $a <=> $b } keys %{$objects_desired_by_this{$person}};
@updated_price = sort { $a <=> $b } @updated_price;
my @best_3_objects = ( $Opt01ObjForPersonI, $Opt02ObjForPersonI, $Opt03ObjForPersonI );
my $msg = $locked_list{$person} ? '[locked list] ' : '';
@objects_with_same_values = sort { $a <=> $b } @objects_with_same_values;
$this_person_can_choose_n_different_objects{$person}{'objects'} = \@objects_with_same_values; #reference to an array
printf $output "<> PersonI = %3s ; %3s objects desired by this person (old list) = (@old_list) ; objects whose current values are still updated = (@updated_price) : %2s >= 1 ? \n", $person, scalar @old_list, scalar @updated_price;
printf $output "<> PersonI = %3s ; %3s objects desired by this person (new list) = (@new_list) $msg; \@best_3_objects = (@best_3_objects) \n", $person, scalar @new_list if ( defined $Opt03ObjForPersonI );
printf $output "<> PersonI = %3s chose ObjectJ = %3s ; \$bidForPersonI %10.5f = \$Opt01ValForPersonI %.5f - \$Opt02ValForPersonI %.5f + \$epsilon %.5f \n", $person, $Opt01ObjForPersonI, $bidForPersonI, $Opt01ValForPersonI, $Opt02ValForPersonI, $e...
printf $output "<> PersonI = %3s ; these objects (@objects_with_same_values) have the same values \$Opt01ValForPersonI = %10.5f ; \$Opt01ObjForPersonI = $Opt01ObjForPersonI ; *** equal values *** \n", $person, $Opt01ValForPersonI if (@objects_wit...
}
}
}
# first, choose objects that appear a few times
foreach my $object ( sort { $count_object{$a} <=> $count_object{$b} || $seen_assignned_objects{$a} <=> $seen_assignned_objects{$b} } keys %objects_with_the_same_values ){ # sort { $price_object{$b} <=> $price_object{$a} }
foreach my $person ( keys %{$objects_with_the_same_values{$object}} ){ # sort { $objects_with_the_same_values{$object}{$a} <=> $objects_with_the_same_values{$object}{$b} }
next if ( $choose_object{$object} );
next if ( $choose_person{$person} );
my $CurVal = $objects_with_the_same_values{$object}{$person}; # $CurVal = $current_value{$object} = $Opt01ValForPersonI.
my $Opt01ObjForPersonI = $object;
$info{$Opt01ObjForPersonI}{'bid' } = $epsilon;
$info{$Opt01ObjForPersonI}{'person'} = $person;
$objects_desired_by_this{$person}{$object} = $CurVal;
if ( $verbose >= 8 ){
my @objects_with_same_values_full = sort { $a <=> $b } @{$this_person_can_choose_n_different_objects{$person}{'objects'}};
my @objects_with_same_values_free = grep { not $choose_object{$_} } @objects_with_same_values_full;
printf $output "<*** equal values ***> \$bidForPersonI = \$epsilon = %.5f ; PersonI = %3s chose ObjectJ = %3s between these (@objects_with_same_values_full) --> free (@objects_with_same_values_free) ; \$count_object{$object} = $count_object{$objec...
}
$choose_object{$object}++;
$choose_person{$person}++;
}}
foreach my $object ( keys %info ) # sort { $a <=> $b } or sort { $info{$a}{'person'} <=> $info{$b}{'person'} }
{
my $bid = $info{$object}{'bid' };
my $person = $info{$object}{'person'};
my $other_person = $assignned_object{$object}; # Find the other person who has objectJ and make them unassigned
if ( defined $other_person ) {
if ( $verbose >= 8 ){
print $output " ***--> PersonI $person was assigned objectJ $object. Before that, remove the objectJ $object from personI $other_person --> delete \$assignned_person{$other_person} \n";
}
# The other person that was assigned to objectJ at the beginning of the iteration (if any)
# is now left without an object (and becomes eligible to bid at the next iteration).
delete $assignned_person{$other_person};
}
# Each objectJ that receives one or more bids, determines the highest of these bids, increases the price_j
# to the highest bid, and gets assigned to the personI who submitted the highest bid.
$seen_assignned_objects{$object}++;
$assignned_person{$person} = $object;
$assignned_object{$object} = $person;
( run in 1.348 second using v1.01-cache-2.11-cpan-140bd7fdf52 )