Algorithm-Simplex

 view release on metacpan or  search on metacpan

lib/Algorithm/Simplex/Float.pm  view on Meta::CPAN


            my $neg_a_ic =
              $self->tableau->[$i]->[$pivot_column_number] * ($neg_one);
            for my $j (0 .. $self->number_of_columns) {
                $self->tableau->[$i]->[$j] =
                  $self->tableau->[$i]->[$j] +
                  ($neg_a_ic * ($self->tableau->[$pivot_row_number]->[$j]));
            }
            $self->tableau->[$i]->[$pivot_column_number] = $neg_a_ic * ($scale);
        }
    }

    return;
}

# Count pivots made
after 'pivot' => sub {
    my $self = shift;

    # TODO: Confirm whether clear is needed or not. Appears not in testing.
    # $self->clear_display_tableau;
    $self->number_of_pivots_made($self->number_of_pivots_made + 1);
    return;
};

=head2 is_optimal

Check the basement row to see if any positive entries exist.  Existence of
a positive entry means the solution is sub-optimal and optimal otherwise.
This is how we decide when to stop the algorithm.

Use EPSILON instead of zero because we're dealing with floats (imperfect numbers).

=cut

sub is_optimal {
    my $self = shift;

    for my $j (0 .. $self->number_of_columns - 1) {
        if ($self->tableau->[ $self->number_of_rows ]->[$j] > $self->EPSILON) {
            return 0;
        }
    }
    return 1;
}

=head2 determine_simplex_pivot_columns

Find the columns that are candiates for pivoting in.  This is based on 
their basement row value being greater than zero.

=cut

sub determine_simplex_pivot_columns {
    my $self = shift;

    my @simplex_pivot_column_numbers;

# Assumes the existence of at least one pivot (use optimality check to insure this)
# According to Nering and Tucker (1993) page 26
# "selected a column with a positive entry in the basement row."
# NOTE: My intuition indicates a pivot could still take place but no gains would be made
# when the cost is zero.  This would not lead us to optimality, but if we were
# already in an optimal state if may (should) lead to another optimal state.
# This would only apply then in the optimal case, i.e. all entries non-positive.
    for my $col_num (0 .. $self->number_of_columns - 1) {
        if ($self->tableau->[ $self->number_of_rows ]->[$col_num] >
            $self->EPSILON)
        {
            push(@simplex_pivot_column_numbers, $col_num);
        }
    }
    return (@simplex_pivot_column_numbers);
}

=head2 determine_positive_ratios

Once a a pivot column has been chosen then we choose a pivot row based on 
the smallest postive ration.  This function is a helper to achieve that.

=cut

sub determine_positive_ratios {
    my $self                = shift;
    my $pivot_column_number = shift;

# Build Ratios and Choose row(s) that yields min for the bland simplex column as a candidate pivot point.
# To be a Simplex pivot we must not consider negative entries
    my @positive_ratios;
    my @positive_ratio_row_numbers;

    #print "Column: $possible_pivot_column\n";
    for my $row_num (0 .. $self->number_of_rows - 1) {
        if ($self->tableau->[$row_num]->[$pivot_column_number] > $self->EPSILON)
        {
            push(@positive_ratios,
                $self->tableau->[$row_num]->[ $self->number_of_columns ] /
                  $self->tableau->[$row_num]->[$pivot_column_number]);

            # Track the rows that give ratios
            push @positive_ratio_row_numbers, $row_num;
        }
    }

    return (\@positive_ratios, \@positive_ratio_row_numbers);
}

=head2 current_solution

Return both the primal (max) and dual (min) solutions for the tableau.

=cut

sub current_solution {
    my $self = shift;

    # Report the Current Solution as primal dependents and dual dependents.
    my @y = @{ $self->y_variables };
    my @u = @{ $self->u_variables };

    # Dependent Primal Variables



( run in 1.018 second using v1.01-cache-2.11-cpan-5b529ec07f3 )