view release on metacpan or search on metacpan
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
use PDL;
use Scalar::Util qw/ blessed /;
has chosen_scans => ( isa => 'ArrayRef', is => 'rw' );
has _iter_idx => ( isa => 'Int', is => 'rw', default => sub { 0; }, );
has _num_boards => ( isa => 'Int', is => 'ro', init_arg => 'num_boards', );
has _orig_scans_data => ( isa => 'PDL', is => 'rw' );
has _optimize_for => ( isa => 'Str', is => 'ro', init_arg => 'optimize_for', );
has _scans_data => ( isa => 'PDL', is => 'rw' );
has _selected_scans =>
( isa => 'ArrayRef', is => 'ro', init_arg => 'selected_scans', );
has _status => ( isa => 'Str', is => 'rw' );
has _quotas => ( isa => 'ArrayRef[Int]', is => 'ro', init_arg => 'quotas' );
has _total_boards_solved => ( isa => 'Int', is => 'rw' );
has _total_iters => ( is => 'rw' );
has _trace_cb =>
( isa => 'Maybe[CodeRef]', is => 'ro', init_arg => 'trace_cb' );
has _scans_meta_data => ( isa => 'ArrayRef', is => 'ro', init_arg => 'scans' );
has _scans_iters_pdls =>
( isa => 'HashRef', is => 'rw', init_arg => 'scans_iters_pdls' );
has _stats_factors => (
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
map {
my $id = $_->id();
my $pdl = $self->_scans_iters_pdls()->{$id};
my $factor = $self->_stats_factors->{$id};
(
defined($factor)
? ( ( $pdl >= 0 ) * ( ( $pdl / $factor )->ceil() ) +
( $pdl < 0 ) * $pdl )
: $pdl
);
} @{ $self->_selected_scans() }
);
$self->_orig_scans_data($scans_data);
$self->_scans_data( $self->_orig_scans_data()->copy() );
return 0;
}
my $BOARDS_DIM = 0;
my $SCANS_DIM = 1;
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
return _my_sum_over( $pdl->xchg( 0, 1 ) );
}
sub _get_iter_state_params_len
{
my $self = shift;
my $iters_quota = 0;
my $num_solved_in_iter = 0;
my $selected_scan_idx;
# If no boards were solved, then try with a larger quota
while ( $num_solved_in_iter == 0 )
{
my $q_more = $self->_get_next_quota();
if ( !defined($q_more) )
{
AI::Pathfinding::OptimizeMultiple::Error::OutOfQuotas->throw(
error => "No q_more", );
}
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
my $iters = $self->_scans_data()->slice(":,:,0");
my $solved = ( ( $iters <= $iters_quota ) & ( $iters > 0 ) );
my $num_moves = $self->_scans_data->slice(":,:,2");
my $solved_moves = $solved * $num_moves;
my $solved_moves_sums = _my_sum_over($solved_moves);
my $solved_moves_counts = _my_sum_over($solved);
my $solved_moves_avgs = $solved_moves_sums / $solved_moves_counts;
( undef, undef, $selected_scan_idx, undef ) =
$solved_moves_avgs->minmaximum();
$num_solved_in_iter = $solved_moves_counts->at($selected_scan_idx);
}
return {
quota => $iters_quota,
num_solved => $num_solved_in_iter,
scan_idx => $selected_scan_idx,
};
}
sub _get_iter_state_params_minmax_len
{
my $self = shift;
my $iters_quota = 0;
my $num_solved_in_iter = 0;
my $selected_scan_idx;
# If no boards were solved, then try with a larger quota
while ( $num_solved_in_iter == 0 )
{
my $q_more = $self->_get_next_quota();
if ( !defined($q_more) )
{
AI::Pathfinding::OptimizeMultiple::Error::OutOfQuotas->throw(
error => "No q_more", );
}
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
$iters_quota += $q_more;
my $iters = $self->_scans_data()->slice(":,:,0");
my $solved = ( ( $iters <= $iters_quota ) & ( $iters > 0 ) );
my $num_moves = $self->_scans_data->slice(":,:,2");
my $solved_moves = $solved * $num_moves;
my $solved_moves_maxima = $solved_moves->maximum()->slice(":,(0),(0)");
my $solved_moves_counts = _my_sum_over($solved);
( undef, undef, $selected_scan_idx, undef ) =
$solved_moves_maxima->minmaximum();
$num_solved_in_iter = $solved_moves_counts->at($selected_scan_idx);
}
return {
quota => $iters_quota,
num_solved => $num_solved_in_iter,
scan_idx => $selected_scan_idx,
};
}
sub _get_iter_state_params_speed
{
my $self = shift;
my $iters_quota = 0;
my $num_solved_in_iter = 0;
my $selected_scan_idx;
# If no boards were solved, then try with a larger quota
while ( $num_solved_in_iter == 0 )
{
my $q_more = $self->_get_next_quota();
if ( !defined($q_more) )
{
AI::Pathfinding::OptimizeMultiple::Error::OutOfQuotas->throw(
error => "No q_more" );
}
$iters_quota += $q_more;
( undef, $num_solved_in_iter, undef, $selected_scan_idx ) =
PDL::minmaximum(
PDL::sumover(
( $self->_scans_data() <= $iters_quota ) &
( $self->_scans_data() > 0 )
)
);
}
return {
quota => $iters_quota,
num_solved => $num_solved_in_iter->at(0),
scan_idx => $selected_scan_idx->at(0),
};
}
sub _get_selected_scan
{
my $self = shift;
my $iter_state =
AI::Pathfinding::OptimizeMultiple::IterState->new(
$self->_get_iter_state_params(), );
$iter_state->attach_to($self);
return $iter_state;
}
sub _inspect_quota
{
my $self = shift;
my $state = $self->_get_selected_scan();
$state->register_params();
$state->update_total_iters();
if ( $self->_total_boards_solved() == $self->_num_boards() )
{
$self->_status("solved_all");
}
else
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
sub _get_num_scans
{
my $self = shift;
return ( ( $self->_scans_data()->dims() )[$SCANS_DIM] );
}
sub _calc_chosen_scan
{
my ( $self, $selected_scan_idx, $iters_quota ) = @_;
return AI::Pathfinding::OptimizeMultiple::ScanRun->new(
{
iters => (
$iters_quota * (
$self->_stats_factors->{
( $self->_selected_scans->[$selected_scan_idx]->id() ),
} // 1
)
),
scan_idx => $selected_scan_idx,
}
);
}
sub calc_flares_meta_scan
{
my $self = shift;
$self->chosen_scans( [] );
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
my $next_num_iters_for_each_scan_x_scan =
( ( $ones_constant x $flares_num_iters ) );
my $num_moves = $self->_scans_data->slice(":,:,1");
# The number of moves for dimension 0,1,2 above.
my $num_moves_repeat = $num_moves->clump( 1 .. 2 )->xchg( 0, 1 )
->dummy( 0, $self->_get_num_scans() );
my $selected_scan_idx;
my $loop_iter_num = 0;
my $UNSOLVED_NUM_MOVES_CONSTANT = 64 * 1024 * 1024;
my $last_avg = $UNSOLVED_NUM_MOVES_CONSTANT;
FLARES_LOOP:
while ( my $q_more = $self->_get_next_quota() )
{
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
$which_minima_are_solved * $minimal_num_moves_solved;
my $solved_moves_sums = _my_xchg_sum_over($minimal_with_zeroes);
my $solved_moves_counts = _my_xchg_sum_over($which_minima_are_solved);
my $solved_moves_avgs = $solved_moves_sums / $solved_moves_counts;
# print join(",", $solved_moves_avgs->minmaximum()), "\n";
my $min_avg;
( $min_avg, undef, $selected_scan_idx, undef ) =
$solved_moves_avgs->minmaximum();
$last_avg = $min_avg;
push @{ $self->chosen_scans() },
$self->_calc_chosen_scan( $selected_scan_idx, $iters_quota );
$flares_num_iters->set( $selected_scan_idx,
$flares_num_iters->at($selected_scan_idx) + $iters_quota );
$self->_selected_scans()->[$selected_scan_idx]->mark_as_used();
$iters_quota = 0;
my $num_solved = $solved_moves_counts->at($selected_scan_idx);
my $flares_num_iters_repeat =
$flares_num_iters->dummy( 0, $self->_num_boards() );
# A boolean tensor:
# Dimension 0 - board.
# Dimension 1 - scans.
my $solved_with_which_iter =
( $flares_num_iters_repeat >= $iters->clump( 1 .. 2 ) ) &
( $iters->clump( 1 .. 2 ) >= 0 );
lib/AI/Pathfinding/OptimizeMultiple.pm view on Meta::CPAN
{
scans => \@scans,
num_boards => 32_000,
optimize_for => 'speed',
scans_iters_pdls =>
{
first_search => $first_search_pdl,
second_search => $second_search_pdl,
},
quotas => [400, 300, 200],
selected_scans =>
[
AI::Pathfinding::OptimizeMultiple::Scan->new(
id => 'first_search',
cmd_line => "--preset first_search",
),
AI::Pathfinding::OptimizeMultiple::Scan->new(
id => 'second_search',
cmd_line => "--preset second_search",
),
AI::Pathfinding::OptimizeMultiple::Scan->new(
lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm view on Meta::CPAN
{
do_rle => $self->_should_rle_be_done(),
offset_quotas => $self->_offset_quotas(),
}
)
);
return;
}
sub _selected_scans
{
my $self = shift;
return $self->_input_obj->selected_scans();
}
sub _map_all_but_last
{
my $self = shift;
my ( $cb, $arr_ref ) = (@_);
return [
( map { $cb->($_) } @$arr_ref[ 0 .. $#$arr_ref - 1 ] ),
lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm view on Meta::CPAN
sub _line_ends_mapping
{
my $self = shift;
return $self->_map_all_but_last( sub { "$_[0] \\\n" }, shift );
}
sub _get_used_scans
{
my $self = shift;
return [ grep { $_->is_used() } @{ $self->_selected_scans() } ];
}
sub _get_scan_line
{
my ( $self, $line ) = @_;
return
$line->{'cmd_line'}
. " -step 500 "
. join( " ",
lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm view on Meta::CPAN
{
return $quota;
}
}
sub _map_scan_idx_to_id
{
my $self = shift;
my $index = shift;
return $self->_selected_scans()->[$index]->id();
}
sub _format_prelude_iter
{
my $self = shift;
my $iter = shift;
return
( $self->_is_flares() ? "Run:" : "" )
lib/AI/Pathfinding/OptimizeMultiple/App/CmdLine.pm view on Meta::CPAN
: "get_scans_iters_pdls"
);
return $self->_input_obj->$method();
}
sub _arbitrator_trace_cb
{
my $args = shift;
printf( "%s \@ %s (%s solved)\n",
@$args{qw(iters_quota selected_scan_idx total_boards_solved)} );
}
sub _init_arbitrator
{
my $self = shift;
return $self->_arbitrator(
AI::Pathfinding::OptimizeMultiple->new(
{
'scans' => [
map { +{ name => $_->id() } }
@{ $self->_input_obj->_suitable_scans_list() },
],
'quotas' => $self->_get_quotas(),
'selected_scans' => $self->_selected_scans(),
'num_boards' => $self->_num_boards(),
'scans_iters_pdls' => $self->_calc_scans_iters_pdls(),
'trace_cb' => \&_arbitrator_trace_cb,
'optimize_for' => $self->_optimize_for(),
'stats_factors' => $self->_stats_factors(),
}
)
);
}
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
use File::Path qw(mkpath);
use AI::Pathfinding::OptimizeMultiple::Scan ();
use PDL (qw( pdl ));
use PDL::IO::FastRaw (qw( readfraw writefraw ));
has start_board => ( isa => 'Int', is => 'ro', required => 1 );
has num_boards => ( isa => 'Int', is => 'ro', required => 1 );
has selected_scans => (
isa => 'ArrayRef',
is => 'ro',
required => 1,
default => sub {
my ($self) = @_;
return $self->_calc_selected_scan_list();
},
lazy => 1,
);
has _scan_ids_to_indexes => (
isa => 'HashRef[Int]',
is => 'ro',
lazy => 1,
default => sub {
my ($self) = @_;
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
{
my $self = shift;
my $filename = shift;
my $text = _slurp($filename);
return [ split( /[\n\r]+/, $text ) ];
}
# Number of selected scans.
sub _num_sel_scans
{
my $self = shift;
return scalar( @{ $self->selected_scans() } );
}
sub _gen_initial_scans_tensor
{
my $self = shift;
my $extra_dims = shift || [];
return zeroes( $self->num_boards(), $self->_num_sel_scans, @$extra_dims );
}
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
my $NUM_NUMBERS_IN_HEADER = 3;
my $HEADER_START_BOARD_IDX = 0;
my $HEADER_NUM_BOARDS = 1;
my $HEADER_ITERATIONS_LIMIT = 2;
sub _get_scans_data_helper
{
my $self = shift;
my $selected_scans = $self->selected_scans();
my $start_board = $self->start_board();
my $scans_data = {};
my $scans_lens_data = {};
my $data_dir = ".data-proc";
my $lens_dir = ".data-len-proc";
mkpath( [ $data_dir, $lens_dir ] );
foreach my $scan (@$selected_scans)
{
{
my $dest_path = $data_dir . "/" . $scan->id();
{
if (
$self->_should_update(
$scan->data_file_path(), $dest_path
)
)
{
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
}
sub _suitable_scans_list
{
my $self = shift;
return [ grep { $self->_is_scan_suitable($_) }
@{ $self->_get_all_scans_list_from_file() } ];
}
sub _calc_selected_scan_list
{
my $self = shift;
return _filter_scans_based_on_black_list_ids(
$self->_suitable_scans_list(),
$self->_black_list_ids_list(),
);
}
sub _get_next_id_file_path
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
}
close($from_cmd);
close($fcs_out);
close($fc_pro_out);
}
sub get_scan_ids_aref
{
my $self = shift;
return [ map { $_->id() } @{ $self->selected_scans } ];
}
sub lookup_scan_idx_based_on_id
{
my ( $self, $scan_id ) = @_;
my $idx = $self->_scan_ids_to_indexes->{$scan_id};
if ( !defined($idx) )
{
die "Index '$idx' does not exist!";
lib/AI/Pathfinding/OptimizeMultiple/DataInputObj.pm view on Meta::CPAN
Returns the hash ref mapping scan IDs/names to iteration PDLs.
=head2 my $hash_ref = $self->get_scans_lens_iters_pdls()
Returns the hash ref mapping scan IDs/names to iteration+lengths PDLs.
=head2 $self->num_boards()
The number of boards.
=head2 $self->selected_scans()
An accessor for the selected scans.
=head2 $self->start_board()
The index of the board to start from.
=head2 $self->time_scan()
Times a new scan.
=head2 $self->get_scan_ids_aref()
lib/AI/Pathfinding/OptimizeMultiple/IterState.pm view on Meta::CPAN
# in $state->update_total_iters().
my $idx_slice = $state->idx_slice();
$idx_slice .=
( ( $r > 0 ) * ( $r - $state->_quota() ) ) + ( ( $r < 0 ) * ($r) );
}
sub _mark_as_used
{
my $state = shift;
$state->_main()->_selected_scans()->[ $state->_scan_idx() ]->mark_as_used();
return;
}
sub _add_chosen
{
my $state = shift;
push @{ $state->_main()->chosen_scans() }, $state->get_chosen_struct();
lib/AI/Pathfinding/OptimizeMultiple/IterState.pm view on Meta::CPAN
return;
}
sub _trace_wrapper
{
my $state = shift;
$state->_main()->_trace(
{
'iters_quota' => $state->_quota(),
'selected_scan_idx' => $state->_scan_idx(),
'total_boards_solved' => $state->_main()->_total_boards_solved(),
}
);
return;
}
sub register_params
{
my $state = shift;
t/optimize-multiple-full-test.t view on Meta::CPAN
# TEST:$c=0;
sub test_based_on_data
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
my ( $scans_aref, $quotas_aref, $want_results, $stats_factors, $blurb ) =
@_;
my $results_aref = [];
my $selected_scans = [
map {
my $id = $_->{name};
AI::Pathfinding::OptimizeMultiple::Scan->new(
id => $id,
cmd_line => "-l $id",
)
} @{$scans_aref},
];
t/optimize-multiple-full-test.t view on Meta::CPAN
Carp::confess("num is not 1.");
}
my $obj = AI::Pathfinding::OptimizeMultiple->new(
{
scans => [ map { +{ name => $_->{name} } } @$scans_aref, ],
num_boards => $nums[0],
scans_iters_pdls =>
{ map { $_->{name} => pdl( $_->{data} ), } @$scans_aref, },
quotas => $quotas_aref,
selected_scans => $selected_scans,
optimize_for => "speed",
( $stats_factors ? ( stats_factors => $stats_factors ) : () ),
}
);
$obj->calc_meta_scan();
my @have = (
map {
+{