Algorithm-Classifier-IsolationForest
view release on metacpan or search on metacpan
benchmarking/bench-axis-predict-accel.pl view on Meta::CPAN
#!/usr/bin/perl
# benchmarking/bench-axis-predict-accel.pl
#
# Benchmarks axis-mode (classic IF) scoring/prediction under each
# acceleration backend:
# pure_perl -- use_c => 0 (pure Perl tree walk)
# c_serial -- use_c => 1, use_openmp => 0 (C tree walk, single thread)
# c_openmp -- use_c => 1, use_openmp => 1 (C tree walk, OpenMP parallel)
#
# This is where the accel differences are largest: the C backend replaces
# the Perl tree walk with a tight C loop, and OpenMP distributes query
# points across cores.
#
# Sections:
# 1. Scoring method comparison -- all 5 methods under each backend
# 2. Query set size scaling -- where OpenMP parallelism shines
# 3. n_trees scaling -- more trees = more work per point
# 4. Feature count (wide) -- 2, 5, 10, 20, 50
# 5. Feature count (2-10) -- fine-grained sweep
#
# Models are pre-trained before any timing begins.
#
# Run with:
# perl -Ilib benchmarking/bench-axis-predict-accel.pl
use strict;
use warnings;
use lib '../lib';
use FindBin;
use lib "$FindBin::Bin";
use BenchAccel qw(wall_cmpthese);
use Algorithm::Classifier::IsolationForest;
use constant PI => 3.14159265358979;
sub gaussian {
my ( $mu, $sigma ) = @_;
return $mu + $sigma * sqrt( -2 * log( rand() || 1e-12 ) ) * cos( 2 * PI * rand() );
}
sub make_data {
my ( $n, $nf ) = @_;
my @rows = map {
[ map { gaussian( 0, 1 ) } 1 .. $nf ]
} 1 .. $n;
for ( 1 .. int( $n * 0.05 ) ) {
my $r = 5 + rand() * 3;
push @rows, [ map { $r * ( rand() > 0.5 ? 1 : -1 ) } 1 .. $nf ];
}
return \@rows;
} ## end sub make_data
my $HAS_C = $Algorithm::Classifier::IsolationForest::HAS_C;
my $HAS_OPENMP = $Algorithm::Classifier::IsolationForest::HAS_OPENMP;
# Build one model per accel config. They share the same seed and training
# data so tree structure is identical -- only the scoring path differs.
sub build_models {
my (%opts) = @_;
my $data = delete $opts{_data};
my %m;
$m{pure_perl} = Algorithm::Classifier::IsolationForest->new( %opts, use_c => 0, )->fit($data);
if ($HAS_C) {
$m{c_serial} = Algorithm::Classifier::IsolationForest->new(
%opts,
use_c => 1,
use_openmp => 0,
)->fit($data);
}
if ( $HAS_C && $HAS_OPENMP ) {
$m{c_openmp} = Algorithm::Classifier::IsolationForest->new(
%opts,
use_c => 1,
use_openmp => 1,
)->fit($data);
}
return \%m;
} ## end sub build_models
print "=" x 70, "\n";
print " axis-mode scoring/predict accel benchmarks\n";
print " Algorithm::Classifier::IsolationForest\n";
print "=" x 70, "\n";
printf "Backend availability: HAS_C=%d HAS_OPENMP=%d HAS_SIMD=%d\n",
$HAS_C, $HAS_OPENMP,
$Algorithm::Classifier::IsolationForest::HAS_SIMD;
print "(rates shown as calls/second wall-clock; higher is faster)\n";
# -----------------------------------------------------------------------
# 1. Scoring method comparison (n_trees=100, 1000 query points)
( run in 0.507 second using v1.01-cache-2.11-cpan-6aa56a78535 )