Skip to content

Instantly share code, notes, and snippets.

@yati-sagade
Created December 21, 2015 09:59
Show Gist options
  • Select an option

  • Save yati-sagade/7ab5169ec482dc2bb59d to your computer and use it in GitHub Desktop.

Select an option

Save yati-sagade/7ab5169ec482dc2bb59d to your computer and use it in GitHub Desktop.
# Given an expression, computes its "complexity".
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
use Perlito5::Compiler;
use Perlito5::Perl5::Emitter;
use Perlito5::Perl5::PrettyPrinter;
use Data::Dumper;
use Perlito5::AST;
use Perlito5::Dumper;
$Perlito5::PKG_NAME = 'main';
$Perlito5::PROTO = {};
sub traverse_breadth_first {
my ($ast, $callback) = @_;
my @queue = ($ast);
while (@queue) {
my $node = shift @queue;
if (exists $node->{arguments}) {
push @queue, $_ for @{ $node->{arguments} };
}
$callback->($node);
}
}
sub lg {
my $x = shift // die 'undef value in lg';
log($x) / log(2.0);
}
sub symbols {
my $ast = shift;
my @symbols;
traverse_breadth_first($ast, sub {
my ($node) = @_;
if (ref $node eq 'Perlito5::AST::Apply') {
push @symbols, $node->{code}
} else {
push @symbols, ref $node;
}
});
return @symbols;
}
sub entropy {
my (@symbols) = @_;
my %dist;
my $inc = 1.0 / (scalar @symbols);
for (@symbols) {
$dist{$_} //= 0.0;
$dist{$_} += $inc;
}
my $ret = 0.0;
for (values %dist) {
$ret += $_ * lg($_);
}
return -$ret;
}
sub get_ast {
my $source = shift;
my $statements = Perlito5::Grammar::exp_stmts($source, 0);
my $ast = Perlito5::Match::flat($statements)->[0];
}
sub compare_expressions {
my (@strings) = @_;
my @asts = map { get_ast($_) } @strings;
my @entropies = map { entropy(symbols($_)) } @asts;
my %rev_map;
for (0..$#entropies) {
my ($entropy, $string) = ($entropies[$_], $strings[$_]);
$rev_map{$entropy} //= [];
push @{ $rev_map{$entropy} }, $string;
}
my @ordered = sort keys %rev_map;
say "Expressions ordered by complexity:";
for (1..@ordered) {
my $e = join "\n\t ", @{ $rev_map{$ordered[$_-1]} };
say "\t$_: " . $e;
}
}
@ARGV >= 2 || die 'Need at least two args';
compare_expressions(@ARGV);
@yati-sagade
Copy link
Author

Sample run:

➜  ~  perl expr_complexity.pl '!($x != $y)' '$x == $y'
Expressions ordered by complexity:
    1: $x == $y
    2: !($x != $y)
➜  ~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment