my
$one
= fract(1, 1);
my
$neg_one
= fract(1, -1);
has
'+tableau'
=> (
isa
=> ArrayRef [ ArrayRef [ InstanceOf [
'Math::Cephes::Fraction'
] ] ],
coerce
=>
sub
{
&make_fractions
(
$_
[0]) },
);
has
'+display_tableau'
=> (
isa
=> ArrayRef [ ArrayRef [Str] ],
coerce
=>
sub
{
&display_fractions
(
$_
[0]) },
);
sub
_build_objective_function_value {
my
$self
=
shift
;
return
$self
->tableau->[
$self
->number_of_rows ]
->[
$self
->number_of_columns ]->rmul(
$neg_one
)->as_string;
}
sub
pivot {
my
$self
=
shift
;
my
$pivot_row_number
=
shift
;
my
$pivot_column_number
=
shift
;
my
$scale
=
$one
->rdiv(
$self
->tableau->[
$pivot_row_number
]->[
$pivot_column_number
]);
for
my
$j
(0 ..
$self
->number_of_columns) {
$self
->tableau->[
$pivot_row_number
]->[
$j
] =
$self
->tableau->[
$pivot_row_number
]->[
$j
]->rmul(
$scale
);
}
$self
->tableau->[
$pivot_row_number
]->[
$pivot_column_number
] =
$scale
;
for
my
$i
(0 ..
$self
->number_of_rows) {
if
(
$i
!=
$pivot_row_number
) {
my
$neg_a_ic
=
$self
->tableau->[
$i
]->[
$pivot_column_number
]->rmul(
$neg_one
);
for
my
$j
(0 ..
$self
->number_of_columns) {
$self
->tableau->[
$i
]->[
$j
] =
$self
->tableau->[
$i
]->[
$j
]->radd(
$neg_a_ic
->rmul(
$self
->tableau->[
$pivot_row_number
]->[
$j
]));
}
$self
->tableau->[
$i
]->[
$pivot_column_number
] =
$neg_a_ic
->rmul(
$scale
);
}
}
return
;
}
after
'pivot'
=>
sub
{
my
$self
=
shift
;
$self
->number_of_pivots_made(
$self
->number_of_pivots_made + 1);
return
;
};
sub
determine_simplex_pivot_columns {
my
$self
=
shift
;
my
@simplex_pivot_column_numbers
;
for
my
$col_num
(0 ..
$self
->number_of_columns - 1) {
my
$bottom_row_fraction
=
$self
->tableau->[
$self
->number_of_rows ]->[
$col_num
];
my
$bottom_row_numeric
=
$bottom_row_fraction
->{n} /
$bottom_row_fraction
->{d};
if
(
$bottom_row_numeric
> 0) {
push
(
@simplex_pivot_column_numbers
,
$col_num
);
}
}
return
(
@simplex_pivot_column_numbers
);
}
sub
determine_positive_ratios {
my
$self
=
shift
;
my
$pivot_column_number
=
shift
;
my
@positive_ratios
;
my
@positive_ratio_row_numbers
;
for
my
$row_num
(0 ..
$self
->number_of_rows - 1) {
my
$bottom_row_fraction
=
$self
->tableau->[
$row_num
]->[
$pivot_column_number
];
my
$bottom_row_numeric
=
$bottom_row_fraction
->{n} /
$bottom_row_fraction
->{d};
if
(
$bottom_row_numeric
> 0) {
push
(
@positive_ratios
,
(
$self
->tableau->[
$row_num
]->[
$self
->number_of_columns ]
->{n} *
$self
->tableau->[
$row_num
]->[
$pivot_column_number
]->{d}
) / (
$self
->tableau->[
$row_num
]->[
$pivot_column_number
]->{n} *
$self
->tableau->[
$row_num
]->[
$self
->number_of_columns ]
->{d}
)
);
push
@positive_ratio_row_numbers
,
$row_num
;
}
}
return
(\
@positive_ratios
, \
@positive_ratio_row_numbers
);
}
sub
is_optimal {
my
$self
=
shift
;
for
my
$j
(0 ..
$self
->number_of_columns - 1) {
my
$basement_row_fraction
=
$self
->tableau->[
$self
->number_of_rows ]->[
$j
];
my
$basement_row_numeric
=
$basement_row_fraction
->{n} /
$basement_row_fraction
->{d};
if
(
$basement_row_numeric
> 0) {
return
0;
}
}
return
1;
}
sub
current_solution {
my
$self
=
shift
;
my
@y
= @{
$self
->y_variables };
my
@u
= @{
$self
->u_variables };
my
%primal_solution
;
for
my
$i
(0 ..
$#y
) {
my
$rational
=
$self
->tableau->[
$i
]->[
$self
->number_of_columns ];
$primal_solution
{
$y
[
$i
]->{generic} } =
$rational
->as_string;
}
my
%dual_solution
;
for
my
$j
(0 ..
$#u
) {
my
$rational
=
$self
->tableau->[
$self
->number_of_rows ]->[
$j
]->rmul(
$neg_one
);
$dual_solution
{
$u
[
$j
]->{generic} } =
$rational
->as_string;
}
return
(\
%primal_solution
, \
%dual_solution
);
}
sub
make_fractions {
my
$tableau
=
shift
;
for
my
$i
(0 ..
scalar
@{
$tableau
} - 1) {
for
my
$j
(0 ..
scalar
@{
$tableau
->[0] } - 1) {
my
$x
= Math::BigRat->new(
$tableau
->[
$i
]->[
$j
]);
$tableau
->[
$i
]->[
$j
] = fract(
$x
->numerator,
$x
->denominator);
}
}
return
$tableau
;
}
sub
display_fractions {
my
$fraction_tableau
=
shift
;
my
$display_tableau
;
for
my
$i
(0 ..
scalar
@{
$fraction_tableau
} - 1) {
for
my
$j
(0 ..
scalar
@{
$fraction_tableau
->[0] } - 1) {
$display_tableau
->[
$i
]->[
$j
] =
$fraction_tableau
->[
$i
]->[
$j
]->as_string;
}
}
return
$display_tableau
;
}
1;