Skip to content

Commit 7971d49

Browse files
djelovinaDenis JelovinaVladimir Dimic
committed
520 dense cholesky integration (#72)
run like this: make test_alp_cholesky_ndebug_alp_reference && tests/unit/alp_cholesky_ndebug_alp_reference -fname datasets/spd5.mtx or make test_alp_cholesky_ndebug_alp_reference && tests/unit/alp_cholesky_ndebug_alp_reference -n 100 The first version reads dense symmetric real matrix in Matrix Market Array format, the second version generated a random SPD matrix internally. Once input matrix is present the code calculates Cholesky decomposition and checks the result. * views fix * test cholesky * First numerically correct version * Add missing structure type traits * Use utils print functions * Add preliminary checks for cholesky result * Fix a bug in print_matrix * Fix band upper limits as the end is not included TODO: Check other structures * file reader enabled currently works on general input matrices: make test_alp_cholesky_ndebug_alp_reference && tests/unit/alp_cholesky_ndebug_alp_reference -fname ../datasets/spd5_convertotodense.mtx But it should also work for symmetric input matrices make test_alp_cholesky_ndebug_alp_reference && tests/unit/alp_cholesky_ndebug_alp_reference -fname ../datasets/spd5_convertotodense_symmetric.mtx * clean prints and DEBUG * Unit test with check or the solution by calculating the Frobenius norm of H - L L^t where H is the input matrix and L is Cholesky solution H is expcted to be (currently real) symmetric matrix in Matrix Market Array format The code is currently generating Upper instead of lower triangular matrix, which is solved by using the transpose view. * remove temporary parser in implement it in a separate branch * review and internal matrix generation * remove temp matrix files * spaces Co-authored-by: Denis Jelovina <denis.jelovina@huawei.com> Co-authored-by: Vladimir Dimic <vladimir.dimic@huawei.com>
1 parent 5925496 commit 7971d49

File tree

7 files changed

+319
-74
lines changed

7 files changed

+319
-74
lines changed

include/alp/algorithms/cholesky.hpp

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@
1616

1717
#include <cmath>
1818
#include <iostream>
19+
#include <iomanip>
1920

2021
#include <alp.hpp>
2122

23+
#include "../../../tests/utils/print_alp_containers.hpp"
24+
25+
#define TEMP_DISABLE
26+
2227
namespace alp {
2328

2429
namespace algorithms {
@@ -42,9 +47,9 @@ namespace alp {
4247
typename Ring = Semiring< operators::add< D >, operators::mul< D >, identities::zero, identities::one >,
4348
typename Minus = operators::subtract< D >,
4449
typename Divide = operators::divide< D > >
45-
RC cholesky_lowtr(
46-
Matrix< D, structures::LowerTriangular, Dense > &L,
47-
const Matrix< D, structures::SymmetricPositiveDefinite, Dense > &H,
50+
RC cholesky_uptr(
51+
Matrix< D, structures::UpperTriangular, Dense > &L,
52+
const Matrix< D, structures::Symmetric, Dense > &H,
4853
const Ring & ring = Ring(),
4954
const Minus & minus = Minus(),
5055
const Divide & divide = Divide() ) {
@@ -55,54 +60,116 @@ namespace alp {
5560
const size_t n = nrows( H );
5661

5762
// Out of place specification of the operation
58-
Matrix< D, structures::SymmetricPositiveDefinite, Dense > LL( n, n );
63+
Matrix< D, structures::Symmetric, Dense > LL( n, n );
5964
rc = set( LL, H );
6065

61-
for( size_t k = 0; k < n ; ++k ) {
66+
if( rc != SUCCESS ) {
67+
std::cerr << " set( LL, H ) failed\n";
68+
return rc;
69+
}
70+
#ifdef DEBUG
71+
print_matrix( " -- LL -- " , LL );
72+
#endif
6273

63-
const size_t m = n - k - 1;
74+
for( size_t k = 0; k < n ; ++k ) {
75+
#ifdef DEBUG
76+
std::cout << "============ Iteration " << k << " ============" << std::endl;
77+
#endif
6478

65-
auto v = get_view( LL , utils::range( k, n) , k );
79+
auto a = get_view( LL, k, utils::range( k, n ) );
80+
#ifdef DEBUG
81+
print_vector( " -- a -- " , a );
82+
#endif
6683

6784
// L[ k, k ] = alpha = sqrt( LL[ k, k ] )
6885
Scalar< D > alpha;
6986
rc = eWiseLambda(
70-
[ &v, &alpha, &ring ]( const size_t i ) {
71-
if ( i == 0 ) {
72-
v[ i ] = alpha = std::sqrt( v[ i ] );
73-
}
74-
},
75-
v );
76-
87+
[ &alpha, &ring ]( const size_t i, D &val ) {
88+
if ( i == 0 ) {
89+
#ifdef TEMP_DISABLE
90+
internal::setInitialized( alpha, true );
91+
*alpha = std::sqrt( val );
92+
#else
93+
(void)set( alpha, std::sqrt( val ) );
94+
#endif
95+
val = *alpha;
96+
}
97+
},
98+
a
99+
);
100+
101+
#ifdef DEBUG
102+
std::cout << "alpha " << *alpha << std::endl;
103+
if( rc != SUCCESS ) {
104+
std::cerr << " eWiseLambda( lambda, view ) (0) failed\n";
105+
return rc;
106+
}
107+
#endif
108+
109+
auto v = get_view( LL, k, utils::range( k + 1, n ) );
110+
#ifdef DEBUG
111+
print_vector( " -- v -- " , v );
112+
#endif
77113
// LL[ k + 1: , k ] = LL[ k + 1: , k ] / alpha
78114
rc = eWiseLambda(
79-
[ &v, &alpha, &divide ]( const size_t i ) {
80-
if ( i > 0 ) {
81-
foldl( v[ i ], alpha, divide );
82-
}
83-
},
84-
v );
85-
115+
[ &alpha, &divide ]( const size_t i, D &val ) {
116+
(void)i;
117+
internal::foldl( val, *alpha, divide );
118+
},
119+
v
120+
);
121+
122+
#ifdef DEBUG
123+
if( rc != SUCCESS ) {
124+
std::cerr << " eWiseLambda( lambda, view ) (1) failed\n";
125+
return rc;
126+
}
127+
#endif
86128

87129
// LL[ k+1: , k+1: ] -= v*v^T
88130
auto LLprim = get_view( LL, utils::range( k + 1, n ), utils::range( k + 1, n ) );
89131

90-
vvt = outer( v, ring.getMultiplicativeOperator() );
91-
rc = foldl( LLprim, vvt, minus );
92-
132+
auto vvt = outer( v, ring.getMultiplicativeOperator() );
133+
#ifdef DEBUG
134+
print_vector( " -- v -- " , v );
135+
print_matrix( " vvt ", vvt );
136+
#endif
137+
138+
rc = alp::eWiseLambda(
139+
[ &vvt, &minus, &divide ]( const size_t i, const size_t j, D &val ) {
140+
internal::foldl(
141+
val,
142+
internal::access( vvt, internal::getStorageIndex( vvt, i, j ) ),
143+
minus
144+
);
145+
},
146+
LLprim
147+
);
148+
#ifdef DEBUG
149+
if( rc != SUCCESS ) {
150+
std::cerr << " eWiseLambda( lambda, view ) (2) failed\n";
151+
return rc;
152+
}
153+
#endif
93154
}
94155

95156
// Finally collect output into L matrix and return
96157
for( size_t k = 0; k < n ; ++k ) {
97158

98159
// L[ k: , k ] = LL[ k: , k ]
99-
auto vL = get_view( L , utils::range( k, n) , k );
100-
auto vLL = get_view( LL , utils::range( k, n) , k );
160+
auto vL = get_view( L, k, utils::range( k, n ) );
161+
auto vLL = get_view( LL, k, utils::range( k, n ) );
101162

102163
rc = set( vL, vLL );
103-
164+
#ifdef DEBUG
165+
if( rc != SUCCESS ) {
166+
std::cerr << " set( view, view ) failed\n";
167+
return rc;
168+
}
169+
#endif
104170
}
105171

172+
assert( rc == SUCCESS );
106173
return rc;
107174
}
108175

include/alp/structures.hpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,13 @@ namespace alp {
289289
using inferred_structures = std::tuple< General >;
290290
};
291291

292+
struct Square: BaseStructure {
293+
294+
typedef std::tuple< OpenInterval > band_intervals;
295+
296+
using inferred_structures = tuple_cat< std::tuple< Square >, General::inferred_structures >::type;
297+
};
298+
292299
/**
293300
* @brief Static and runtime check to determine if a matrix view of structure TargetStructure
294301
* and index mapping functions (IMFs) \a imf_r and \a imf_c can be defined over \a SourceStructure.
@@ -297,7 +304,7 @@ namespace alp {
297304
* @tparam TargetStructure The underlying structure of the target view.
298305
* @param imf_r The IMF applied to the rows of the source matrix.
299306
* @param imf_c The IMF applied to the columns of the source matrix.
300-
307+
301308
* @return \a false if the function can determined that the new view may alter underlying assumptions
302309
* associated with the source structure \a SourceStructure; \a true otherwise.
303310
*/
@@ -337,13 +344,6 @@ namespace alp {
337344
};
338345
};
339346

340-
struct Square: BaseStructure {
341-
342-
typedef std::tuple< OpenInterval > band_intervals;
343-
344-
using inferred_structures = tuple_cat< std::tuple< Square >, General::inferred_structures >::type;
345-
};
346-
347347

348348
template<>
349349
struct isInstantiable< General, Square > {
@@ -425,6 +425,22 @@ namespace alp {
425425
using inferred_structures = tuple_cat< std::tuple< Symmetric >, Square::inferred_structures >::type;
426426
};
427427

428+
template<>
429+
struct isInstantiable< General, Symmetric > {
430+
template< typename ImfR, typename ImfC >
431+
static bool check( const ImfR &imf_r, const ImfC &imf_c ) {
432+
return ( ( imf_r.n == imf_c.n ) && ( imf_r.s == imf_c.s ) && ( imf_r.b == imf_c.b ) );
433+
};
434+
};
435+
436+
template<>
437+
struct isInstantiable< Symmetric, Symmetric > {
438+
template< typename ImfR, typename ImfC >
439+
static bool check( const ImfR &imf_r, const ImfC &imf_c ) {
440+
return imf_r.isSame(imf_c);
441+
};
442+
};
443+
428444
struct SymmetricPositiveDefinite: BaseStructure {
429445

430446
typedef std::tuple< OpenInterval > band_intervals;
@@ -444,14 +460,14 @@ namespace alp {
444460

445461
struct LowerTrapezoidal: BaseStructure {
446462

447-
typedef std::tuple< LeftOpenInterval< 0 > > band_intervals;
463+
typedef std::tuple< LeftOpenInterval< 1 > > band_intervals;
448464

449465
using inferred_structures = tuple_cat< std::tuple< LowerTrapezoidal >, Trapezoidal::inferred_structures >::type;
450466
};
451467

452468
struct LowerTriangular: BaseStructure {
453469

454-
typedef std::tuple< LeftOpenInterval< 0 > > band_intervals;
470+
typedef std::tuple< LeftOpenInterval< 1 > > band_intervals;
455471

456472
using inferred_structures = tuple_cat< std::tuple< LowerTriangular >, Triangular::inferred_structures, LowerTrapezoidal::inferred_structures >::type;
457473
};

include/alp/utils/parser/MatrixFileReaderBase.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,16 @@ namespace alp {
263263
return properties._n;
264264
}
265265

266+
/** Check if matrix is symmetric. */
267+
bool isSymmetric() const noexcept {
268+
return properties._symmetry == MatrixFileProperties::MMsymmetries::SYMMETRIC;
269+
}
270+
271+
/** Check if matrix is symmetric. */
272+
bool isGeneral() const noexcept {
273+
return properties._symmetry == MatrixFileProperties::MMsymmetries::GENERAL;
274+
}
275+
266276
/**
267277
* If known, returns the number of nonzeroes contained in the matrix file.
268278
*

tests/unit/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ add_grb_executables( add15m add15m.cpp
3838
# BACKENDS alp_reference
3939
#)
4040

41+
add_grb_executables( alp_cholesky alp_cholesky.cpp
42+
BACKENDS alp_reference
43+
)
44+
4145
add_grb_executables( alp_views alp_views.cpp
4246
BACKENDS alp_reference
4347
)

0 commit comments

Comments
 (0)