- cholmod_solve, cholmode_l_solveは結構大変
cholmod_dense * cholmod_solve (int sys, cholmod_factor *L, cholmod_dense *B, cholmod_common *Common)
-
- solveする式のパターンを決めるint sys (たとえばAx =B を解くならsys=0)、AをFactorizationした結果のL、それにBを与え、最期に、cholmod的に扱うために与える *Commonを引数として、cholmodeでの密行列(密ベクトル)が返る
- factorizationして、それをfactorizatio結果に特化したクラス(cholmod_factor)に入れなおして…
- と、大変
- この大変さをspinxformライブラリでは、ラッパーで簡単に扱えるようにしている
- もちろん、cholmod, suitesparseのすべてのクラスをラッピングするのは大変なので、ごく一部だけだが
- ラッピングされているのは
- 密行列(DENSE):cholmod_denseをラッピング
- 疎行列(SPARSE):cholmod_sparse
- Factorizationの結果(FACTOR):cholmod_factor
- 行列(UPPER):cholmod_upper。これはSPARSEを継承している。基本は行列の形があって、値が全部ゼロの完全に疎な行列。それに、非ゼロセルだけ値を持たせやすい、実(疎)行列
- cholmodが持つ、cholmod扱いするためのオブジェクト(COMMON):cholmod_common
- このラッパーの特徴は
- ラッピングしているcholmodのクラスを *hogeと呼び出せる(*が、そのような機能を持つオペレータ)
- 行列のサイズ情報を取り出したり変更したりしやすい
#include "cholmod.h"
#include "CMWrapperY.h"
#include <iostream>
using namespace std;
int main()
{
int n = 3;
cm::Common cc;
cm::Upper A(cc,n,n);
cm::Sparse S(cc,3,4);
cout << "S size:" << S.size(1) << "\n" << endl;
A(0,0) = 2.0;
A(0,1) = -1.0;
A(0,2) = 0.0;
A(1,0) = -1.0;
A(1,1) = 3.0;
A(1,2) = -1.0;
A(2,0) = 0.0;
A(2,1) = -1.0;
A(2,2) = 2.0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cout << A(i,j) << "\n" << endl;
}
}
cm::Factor B(cc);
B.build(A);
cm::Dense x(cc,n,1);
cm::Dense b(cc,n,1);
b(0,0) = 1.0;
b(1,0) = 2.0;
b(2,0) = 3.0;
x = cholmod_l_solve(CHOLMOD_A, *B, *b, cc);
for(int i=0;i<n;i++){
cout << "i:" << i << " " << x(i,0) << "\n" << endl;
cout << "i:" << i << " " << x(i,1) << "\n" << endl;
}
return 0;
}
-
- これを可能にするCMWrapperY.h,CMWrapperY.cppが
#ifndef SPINYFORM_CMWRAPPER_H
#define SPINYFORM_CMWRAPPER_H
#include <cholmod.h>
#include <map>
namespace cm
{
class Common
{
public:
Common( void );
~Common( void );
operator cholmod_common*( void );
protected:
cholmod_common common;
};
class Dense
{
public:
Dense( Common& common, int m = 0, int n = 0, int xtype = CHOLMOD_REAL );
Dense( const Dense& A );
~Dense( void );
cholmod_dense* operator*( void );
const Dense& operator=( const Dense& A );
const Dense& operator=( cholmod_dense* A );
int size( int dim ) const;
int length( void ) const;
void zero( double rVal = 0., double iVal = 0. );
double norm( void );
void horzcat( const Dense& A, const Dense& B );
void vertcat( const Dense& A, const Dense& B );
double& operator()( int row, int col );
double operator()( int row, int col ) const;
double& r( int row, int col );
double r( int row, int col ) const;
double& i( int row, int col );
double i( int row, int col ) const;
double& operator()( int index );
double operator()( int index ) const;
double& r( int index );
double r( int index ) const;
double& i( int index );
double i( int index ) const;
protected:
void initializeFromCopy( void );
Common& common;
int m, n;
int xtype;
cholmod_dense* data;
double* rData;
double* iData;
};
class Sparse
{
public:
Sparse( Common& common, int m = 0, int n = 0, int xtype = CHOLMOD_REAL );
~Sparse( void );
void resize( int m, int n );
cholmod_sparse* operator*( void );
int size( int dim ) const;
int length( void ) const;
void zero( double rVal = 0., double iVal = 0. );
void transpose( void );
void horzcat( const Sparse& A, const Sparse& B );
void vertcat( const Sparse& A, const Sparse& B );
double& operator()( int row, int col );
double operator()( int row, int col ) const;
double& r( int row, int col );
double r( int row, int col ) const;
double& i( int row, int col );
double i( int row, int col ) const;
typedef std::pair<int,int> EntryIndex;
typedef std::pair<double,double> EntryValue;
typedef std::map<EntryIndex,EntryValue> EntryMap;
typedef EntryMap::iterator iterator;
typedef EntryMap::const_iterator const_iterator;
iterator begin( void );
const_iterator begin( void ) const;
iterator end( void );
const_iterator end( void ) const;
protected:
Common& common;
int m, n;
int xtype, stype;
cholmod_sparse* A;
EntryMap data;
double& retrieveEntry( int row, int col, int c );
double retrieveEntry( int row, int col, int c ) const;
};
class Upper : public Sparse
{
public:
Upper( Common& common, int m = 0, int n = 0, int xtype = CHOLMOD_REAL );
};
class Factor
{
public:
Factor( Common& common );
~Factor( void );
void build( Upper& A );
cholmod_factor* operator*( void );
protected:
Common& common;
cholmod_factor *L;
};
}
#endif
#include "CMWrapperY.h"
#include <algorithm>
#include <cassert>
#include <cmath>
using namespace std;
namespace cm
{
Common :: Common( void )
{
cholmod_l_start( &common );
}
Common :: ~Common( void )
{
cholmod_l_finish( &common );
}
Common :: operator cholmod_common*( void )
{
return &common;
}
Sparse :: Sparse( Common& _common, int _m, int _n, int _xtype )
: common( _common ),
m( _m ),
n( _n ),
xtype( _xtype ),
stype( 0 ),
A( NULL )
{}
Upper :: Upper( Common& _common, int _m, int _n, int _xtype )
: Sparse( _common, _m, _n, _xtype )
{
stype = 1;
}
Sparse :: ~Sparse( void )
{
if( A )
{
cholmod_l_free_sparse( &A, common );
}
}
void Sparse :: resize( int _m, int _n )
{
m = _m;
n = _n;
data.clear();
}
int Sparse :: size( int dim ) const
{
if( dim == 1 ) return m;
if( dim == 2 ) return n;
return 0;
}
int Sparse :: length( void ) const
{
return max( m, n );
}
void Sparse :: zero( double rVal, double iVal )
{
EntryValue val( rVal, iVal );
for( EntryMap::iterator i = data.begin(); i != data.end(); i++ )
{
i->second = val;
}
}
void Sparse :: transpose( void )
{
EntryMap transposed;
for( const_iterator e = data.begin(); e != data.end(); e++ )
{
int i = e->first.first;
int j = e->first.second;
transposed[ EntryIndex( j, i ) ] = e->second;
}
data = transposed;
swap( m, n );
}
void Sparse :: horzcat( const Sparse& A, const Sparse& B )
{
assert( A.m == B.m );
assert( A.xtype == B.xtype );
data.clear();
m = A.m;
n = A.n + B.n;
xtype = A.xtype;
for( const_iterator e = A.begin(); e != A.end(); e++ )
{
int i = e->first.second;
int j = e->first.first;
data[ EntryIndex( j, i ) ] = e->second;
}
for( const_iterator e = B.begin(); e != B.end(); e++ )
{
int i = e->first.second;
int j = e->first.first;
data[ EntryIndex( j+A.n, i ) ] = e->second;
}
}
void Sparse :: vertcat( const Sparse& A, const Sparse& B )
{
assert( A.n == B.n );
assert( A.xtype == B.xtype );
data.clear();
m = A.m + B.m;
n = A.n;
xtype = A.xtype;
for( const_iterator e = A.begin(); e != A.end(); e++ )
{
int i = e->first.second;
int j = e->first.first;
data[ EntryIndex( j, i ) ] = e->second;
}
for( const_iterator e = B.begin(); e != B.end(); e++ )
{
int i = e->first.second;
int j = e->first.first;
data[ EntryIndex( j, i+A.m ) ] = e->second;
}
}
cholmod_sparse* Sparse :: operator*( void )
{
if( A )
{
cholmod_l_free_sparse( &A, common );
A = NULL;
}
int nzmax = data.size();
int sorted = true;
int packed = true;
A = cholmod_l_allocate_sparse( m, n, nzmax, sorted, packed, stype, xtype, common );
double* pr = (double*) A->x;
double* pi = (double*) A->z;
UF_long* ir = (UF_long*) A->i;
UF_long* jc = (UF_long*) A->p;
int i = 0;
int j = -1;
for( EntryMap::const_iterator e = data.begin(); e != data.end(); e++ )
{
int c = e->first.first;
if( c != j )
{
for( int k = j+1; k <= c; k++ )
{
jc[k] = i;
}
j = c;
}
ir[i] = e->first.second;
pr[i] = e->second.first;
if( xtype == CHOLMOD_ZOMPLEX )
{
pi[i] = e->second.second;
}
i++;
}
for( int k = j+1; k <= n; k++ )
{
jc[k] = i;
}
return A;
}
double& Sparse :: operator()( int row, int col ) { return retrieveEntry( row, col, CHOLMOD_REAL ); }
double Sparse :: operator()( int row, int col ) const { return retrieveEntry( row, col, CHOLMOD_REAL ); }
double& Sparse :: r( int row, int col ) { return retrieveEntry( row, col, CHOLMOD_REAL ); }
double Sparse :: r( int row, int col ) const { return retrieveEntry( row, col, CHOLMOD_REAL ); }
double& Sparse :: i( int row, int col ) { return retrieveEntry( row, col, CHOLMOD_ZOMPLEX ); }
double Sparse :: i( int row, int col ) const { return retrieveEntry( row, col, CHOLMOD_ZOMPLEX ); }
Sparse::iterator Sparse :: begin( void )
{
return data.begin();
}
Sparse::const_iterator Sparse :: begin( void ) const
{
return data.begin();
}
Sparse::iterator Sparse :: end( void )
{
return data.end();
}
Sparse::const_iterator Sparse :: end( void ) const
{
return data.end();
}
double& Sparse :: retrieveEntry( int row, int col, int c )
{
EntryIndex index( col, row );
EntryMap::const_iterator entry = data.find( index );
if( entry == data.end())
{
data[ index ] = EntryValue( 0., 0. );
}
if( c == CHOLMOD_REAL ) return data[ index ].first;
else return data[ index ].second;
}
double Sparse :: retrieveEntry( int row, int col, int c ) const
{
EntryIndex index( col, row );
EntryMap::const_iterator entry = data.find( index );
if( entry == data.end())
{
return 0;
}
if( c == CHOLMOD_REAL ) return entry->second.first;
else return entry->second.second;
}
Dense :: Dense( Common& _common, int _m, int _n, int _xtype )
: common( _common ),
m( _m ),
n( _n ),
xtype( _xtype ),
data( NULL ),
rData( NULL ),
iData( NULL )
{
int d = m;
data = cholmod_l_allocate_dense( m, n, d, xtype, common );
rData = (double*) data->x;
if( xtype == CHOLMOD_ZOMPLEX )
{
iData = (double*) data->z;
}
}
Dense :: Dense( const Dense& A )
: common( A.common ),
data( NULL ),
rData( NULL ),
iData( NULL )
{
*this = A;
}
Dense :: ~Dense( void )
{
if( data ) cholmod_l_free_dense( &data, common );
}
cholmod_dense* Dense :: operator*( void )
{
return data;
}
void Dense :: initializeFromCopy( void )
{
assert( data->dtype == CHOLMOD_DOUBLE );
xtype = data->xtype;
m = data->nrow;
n = data->ncol;
rData = (double*) data->x;
if( data->xtype == CHOLMOD_ZOMPLEX )
{
iData = (double*) data->z;
}
}
const Dense& Dense :: operator=( const Dense& A )
{
if( data ) { cholmod_l_free_dense( &data, common ); data = NULL; }
data = cholmod_l_copy_dense( A.data, common );
initializeFromCopy();
return *this;
}
const Dense& Dense :: operator=( cholmod_dense* A )
{
if( data ) { cholmod_l_free_dense( &data, common ); data = NULL; }
data = A;
initializeFromCopy();
return *this;
}
int Dense :: size( int dim ) const
{
if( dim == 1 ) return m;
if( dim == 2 ) return n;
return 0;
}
int Dense :: length( void ) const
{
return max( m, n );
}
void Dense :: zero( double rVal, double iVal )
{
if( rData )
for( int i = 0; i < m*n; i++ )
{
rData[i] = rVal;
}
if( iData )
for( int i = 0; i < m*n; i++ )
{
iData[i] = iVal;
}
}
double Dense :: norm( void )
{
return cholmod_l_norm_dense( **this, 0, common );
}
void Dense :: horzcat( const Dense& A, const Dense& B )
{
assert( A.m == B.m );
assert( A.xtype == B.xtype );
m = A.m;
n = A.n + B.n;
xtype = A.xtype;
if( data ) { cholmod_l_free_dense( &data, common ); data = NULL; }
data = cholmod_l_allocate_dense( m, n, m, xtype, common );
rData = (double*) data->x;
if( xtype == CHOLMOD_ZOMPLEX )
{
iData = (double*) data->z;
}
for( int i = 0; i < A.m; i++ )
for( int j = 0; j < A.n; j++ )
{
rData[i+m*j] = A.rData[i+A.m*j];
if( xtype == CHOLMOD_ZOMPLEX )
{
iData[i+m*j] = A.iData[i+A.m*j];
}
}
for( int i = 0; i < B.m; i++ )
for( int j = 0; j < B.n; j++ )
{
rData[i+m*(j+A.n)] = B.rData[i+B.m*j];
if( xtype == CHOLMOD_ZOMPLEX )
{
iData[i+m*(j+A.n)] = B.iData[i+B.m*j];
}
}
}
void Dense :: vertcat( const Dense& A, const Dense& B )
{
assert( A.n == B.n );
assert( A.xtype == B.xtype );
m = A.m + B.m;
n = A.n;
xtype = A.xtype;
if( data ) { cholmod_l_free_dense( &data, common ); data = NULL; }
data = cholmod_l_allocate_dense( m, n, m, xtype, common );
rData = (double*) data->x;
if( xtype == CHOLMOD_ZOMPLEX )
{
iData = (double*) data->z;
}
for( int i = 0; i < A.m; i++ )
for( int j = 0; j < A.n; j++ )
{
rData[i+m*j] = A.rData[i+A.m*j];
if( xtype == CHOLMOD_ZOMPLEX )
{
iData[i+m*j] = A.iData[i+A.m*j];
}
}
for( int i = 0; i < B.m; i++ )
for( int j = 0; j < B.n; j++ )
{
rData[(i+A.m)+m*j] = B.rData[i+B.m*j];
if( xtype == CHOLMOD_ZOMPLEX )
{
iData[(i+A.m)+m*j] = B.iData[i+B.m*j];
}
}
}
double& Dense :: operator()( int row, int col ) { return rData[ row + m*col ]; }
double Dense :: operator()( int row, int col ) const { return rData[ row + m*col ]; }
double& Dense :: r( int row, int col ) { return rData[ row + m*col ]; }
double Dense :: r( int row, int col ) const { return rData[ row + m*col ]; }
double& Dense :: i( int row, int col ) { return iData[ row + m*col ]; }
double Dense :: i( int row, int col ) const { return iData[ row + m*col ]; }
double& Dense :: operator()( int index ) { return rData[ index ]; }
double Dense :: operator()( int index ) const { return rData[ index ]; }
double& Dense :: r( int index ) { return rData[ index ]; }
double Dense :: r( int index ) const { return rData[ index ]; }
double& Dense :: i( int index ) { return iData[ index ]; }
double Dense :: i( int index ) const { return iData[ index ]; }
Factor :: Factor( Common& _common )
: common( _common ),
L( NULL )
{}
Factor :: ~Factor( void )
{
if( L )
{
cholmod_l_free_factor( &L, common );
}
}
void Factor :: build( Upper& A )
{
if( L )
{
cholmod_l_free_factor( &L, common );
L = NULL;
}
L = cholmod_l_analyze( *A, common );
cholmod_l_factorize( *A, L, common );
}
cholmod_factor* Factor :: operator*( void )
{
return L;
}
}
A <- matrix(c(2,-1,0,-1,3,-1,0,-1,2),byrow=TRUE,3,3)
A. <- t(A)
b <- c(1,2,3)
library(Matrix)
x <- Matrix::solve(A,b,sys="A")
x
A %*% x
> A <- matrix(c(2,-1,0,-1,3,-1,0,-1,2),byrow=TRUE,3,3)
> A. <- t(A)
> b <- c(1,2,3)
> library(Matrix)
> x <- Matrix::solve(A,b,sys="A")
> x
[1] 1.5 2.0 2.5
> A %*% x
[,1]
[1,] 1
[2,] 2
[3,] 3