package Math::Bacovia::Log;
use 5.014;
use warnings;
use Class::Multimethods qw();
use parent qw(Math::Bacovia);
our $VERSION = $Math::Bacovia::VERSION;
sub new {
my ($class, $value) = @_;
Math::Bacovia::_check_type(\$value);
bless {value => $value}, $class;
}
sub get {
$_[0]->{value};
}
#
## Operations
#
Class::Multimethods::multimethod add => (__PACKAGE__, __PACKAGE__) => sub {
__PACKAGE__->new($_[0]->{value} * $_[1]->{value});
};
Class::Multimethods::multimethod sub => (__PACKAGE__, __PACKAGE__) => sub {
__PACKAGE__->new($_[0]->{value} / $_[1]->{value});
};
sub neg {
my ($x) = @_;
$x->{_neg} //= __PACKAGE__->new($x->{value}->inv);
}
#
## Equality
#
Class::Multimethods::multimethod eq => (__PACKAGE__, __PACKAGE__) => sub {
my ($x, $y) = @_;
(ref($x->{value}) eq ref($y->{value}))
&& ($x->{value}->eq($y->{value}));
};
Class::Multimethods::multimethod eq => (__PACKAGE__, '*') => sub {
!1;
};
#
## Transformations
#
sub numeric {
my ($x) = @_;
CORE::log($x->{value}->numeric);
}
sub pretty {
my ($x) = @_;
$x->{_pretty} //= "log(" . $x->{value}->pretty() . ")";
}
sub stringify {
my ($x) = @_;
$x->{_str} //= "Log(" . $x->{value}->stringify() . ")";
}
#
## Alternatives
#
sub alternatives {
my ($self, %opt) = @_;
$self->{_alt} //= do {
my @alt;
foreach my $o ($self->{value}->alternatives(%opt)) {
push @alt, __PACKAGE__->new($o);
if (ref($o) eq 'Math::Bacovia::Exp') {
push @alt, $o->{value};
}
if ($opt{full}) {
# Identity: log(a * b) = log(a) + log(b)
if (ref($o) eq 'Math::Bacovia::Product') {
push @alt, 'Math::Bacovia::Sum'->new(map { __PACKAGE__->new($_) } @{$o->{values}});
}
# Identity: log(a / b) = log(a) - log(b)
if (ref($o) eq 'Math::Bacovia::Fraction') {
push @alt, 'Math::Bacovia::Difference'->new(__PACKAGE__->new($o->{num}), __PACKAGE__->new($o->{den}));
}
# Identity: log(a^b) = log(a) * b
#~ if (ref($o) eq 'Math::Bacovia::Power') {
#~ push @alt, __PACKAGE__->new($o->{base}) * $o->{power};
#~ }
}
}
[List::UtilsBy::uniq_by { $_->stringify } @alt];
};
@{$self->{_alt}};
}
1;