Bio-Metabolic

 view release on metacpan or  search on metacpan

lib/Bio/Metabolic/MatrixOps.pm  view on Meta::CPAN

Returns the kernel of matrix $m, i.e. the matrix with linearly independent
column vectors $c satisfying the equation $m x $c = 0.

=cut

sub PDL::Matrix::kernel {
    my $matrix = shift->copy;

    my ( $rem, $perm, $rank ) = $matrix->row_echelon_int();

    my ( $cols, $rows ) = $rem->dims();

    my $vec;
    my @veclist = ();

    my ( $cnt, $r );
    for ( $cnt = $rank ; $cnt < $cols ; $cnt++ ) {

        #    print "Solution number ".eval($cnt-$rank+1).":\n";
        $vec = zeroes($cols);
        set $vec, $cnt, 1;

        for ( $r = $rank - 1 ; $r >= 0 ; $r-- ) {

            #      print "Calculating row $r:\n";
            my ($row) = $rem->slice("($r),:");
            my $sum = inner( $row, $vec );

            # ensure only integers remain
            my ( $gcd, $redsum, $redpivot ) =
              euclid( $sum, $rem->at( $r, $r ) );
            $vec *= $redpivot;
            set $vec, $r, -( $sum * $redpivot / $rem->at( $r, $r ) );

            #      print "$vec\n";
        }

        push( @veclist, $vec );
    }

    #  print "kernel: Rank=$rank,Columns=$cols,vecs:@veclist\n";
    #  my $retmat = cat(@veclist)->xchg(0,1);
    #  $retmat->permrows($perm);
    #  return $retmat;
    return null unless @veclist;
    my $retmat = bless cat(@veclist)->xchg( 0, 1 ), ref($matrix);
    return $retmat->permrows($perm);
}

=head2 method invert # probably obsolete!!!! Check with PDL::Matrix / PDL::MatrixOps

$inv = $m->invert;
Returns the inverse of $m, undef if $m is not invertible.

=cut

sub PDL::Matrix::invert {
    my $matrix = shift->copy;

    #  print "ref(matrix) is ".ref($matrix)."\n";
    #  my ($pkg,$file,$line)=caller();

    my @dims = $matrix->dims;

    if ( $dims[0] != $dims[1] ) {
        croak("Inverse for non-square matrix not defined!\n");
        return undef;
    }

    my $n = $dims[0];    # n x n matrix

    # $inverse = 1
    #  print "matrix $matrix";
    #  print "invert called from package $pkg, file $file, line $line (n=$n)\n";
    #  my $inverse = ref($matrix)->new($n,$n);
    my $inverse = mzeroes( $n, $n );

    #  (my $tmp = $inverse->diagonal(0,1)) .= 1;   # some strange error!!!!
    #  for (my $del=0;$del<$n;$del++) {set($inverse,$del,$del,1)};
    $inverse->diagonal( 0, 1 ) .= 1;

    for ( my $colnr = 0 ; $colnr < $n ; $colnr++ ) {

        # find pivot element
        my $colnz = which( $matrix->slice(":,($colnr)")->sever != 0 );
        my $ppiv  = which( $colnz >= $colnr );
        if ( $ppiv->nelem == 0 ) {
            print "Matrix not invertible\n";
            return undef;
        }
        my $pivotrow = $colnz->at( $ppiv->at(0) );

        if ( $pivotrow != $colnr ) {
            $matrix->xrow( $colnr,  $pivotrow );
            $inverse->xrow( $colnr, $pivotrow );
        }

        my $akk = $matrix->at( $colnr, $colnr );    # this is a_{kk}
        for ( my $rownr = 0 ; $rownr < $n ; $rownr++ ) {
            if ( $rownr != $colnr ) {

                #	my $q = - $matrix->at($colnr,$rownr) / $akk;
                my $q = -$matrix->at( $rownr, $colnr ) / $akk;
                $matrix->addrows( $rownr,  $colnr, $q );
                $inverse->addrows( $rownr, $colnr, $q );
            }
        }

        #    print "Matrix now (column $colnr) : $matrix\n";
        #    print "Inverse now (column $colnr) : $inverse\n";

    }

    #  my $diag = $matrix->diagonal(0,1);
    #  if (!(which($diag==0)->isempty)) {
    #    print "Matrix non inversible!\n";
    #    return undef;
    #  }

    for ( my $d = 0 ; $d < $n ; $d++ ) {
        if ( $matrix->at( $d, $d ) == 0 ) {



( run in 2.307 seconds using v1.01-cache-2.11-cpan-0d23b851a93 )