Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tsoc
openmm
Commits
6fd7f3bb
Commit
6fd7f3bb
authored
May 21, 2009
by
Peter Eastman
Browse files
Working on new constraint algorithm
parent
f23db9f1
Changes
37
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
2055 additions
and
145 deletions
+2055
-145
libraries/jama/include/tnt_i_refvec.h
libraries/jama/include/tnt_i_refvec.h
+0
-0
libraries/jama/include/tnt_math_utils.h
libraries/jama/include/tnt_math_utils.h
+0
-0
libraries/jama/include/tnt_sparse_matrix_csr.h
libraries/jama/include/tnt_sparse_matrix_csr.h
+0
-0
libraries/jama/include/tnt_stopwatch.h
libraries/jama/include/tnt_stopwatch.h
+0
-0
libraries/jama/include/tnt_subscript.h
libraries/jama/include/tnt_subscript.h
+0
-0
libraries/jama/include/tnt_vec.h
libraries/jama/include/tnt_vec.h
+0
-0
libraries/jama/include/tnt_version.h
libraries/jama/include/tnt_version.h
+0
-0
libraries/quern/README
libraries/quern/README
+17
-0
libraries/quern/include/quern.h
libraries/quern/include/quern.h
+233
-0
libraries/quern/include/quern_list.h
libraries/quern/include/quern_list.h
+230
-0
libraries/quern/src/quern.cpp
libraries/quern/src/quern.cpp
+93
-0
libraries/quern/src/quern_factorization.cpp
libraries/quern/src/quern_factorization.cpp
+890
-0
libraries/quern/src/quern_order.cpp
libraries/quern/src/quern_order.cpp
+163
-0
libraries/quern/src/quern_solver.cpp
libraries/quern/src/quern_solver.cpp
+116
-0
platforms/reference/src/ReferenceKernels.cpp
platforms/reference/src/ReferenceKernels.cpp
+29
-9
platforms/reference/src/SimTKReference/ReferenceRigidShakeAlgorithm.cpp
...rence/src/SimTKReference/ReferenceRigidShakeAlgorithm.cpp
+267
-133
platforms/reference/src/SimTKReference/ReferenceRigidShakeAlgorithm.h
...ference/src/SimTKReference/ReferenceRigidShakeAlgorithm.h
+17
-3
No files found.
jama/include/tnt_i_refvec.h
→
libraries/
jama/include/tnt_i_refvec.h
View file @
6fd7f3bb
File moved
jama/include/tnt_math_utils.h
→
libraries/
jama/include/tnt_math_utils.h
View file @
6fd7f3bb
File moved
jama/include/tnt_sparse_matrix_csr.h
→
libraries/
jama/include/tnt_sparse_matrix_csr.h
View file @
6fd7f3bb
File moved
jama/include/tnt_stopwatch.h
→
libraries/
jama/include/tnt_stopwatch.h
View file @
6fd7f3bb
File moved
jama/include/tnt_subscript.h
→
libraries/
jama/include/tnt_subscript.h
View file @
6fd7f3bb
File moved
jama/include/tnt_vec.h
→
libraries/
jama/include/tnt_vec.h
View file @
6fd7f3bb
File moved
jama/include/tnt_version.h
→
libraries/
jama/include/tnt_version.h
View file @
6fd7f3bb
File moved
libraries/quern/README
0 → 100644
View file @
6fd7f3bb
Quern 0.9 (beta)
Public domain code for sparse up-looking Givens QR, including incomplete
drop tolerance version for preconditioning iterative solvers.
Edit Makefile to fit your set up (in particular, MATLAB-specific stuff).
Currently it's set up for debugging; change the flags to get optimized
versions of the code.
In addition to the library libquern.a (with header quern.h), there are
two mex files (quern_internal_mex and quern_cgnr_mex) as well as a
stand-alone executable test_mat for running tests on matrices stored
in .mat files.
- Robert Bridson
UBC Computer Science
February 4, 2009
libraries/quern/include/quern.h
0 → 100644
View file @
6fd7f3bb
/*
* Quern: a sparse QR library.
* This code is in the public domain.
* - Robert Bridson
*/
#ifndef QUERN_H
#define QUERN_H
#ifdef __cplusplus
extern
"C"
{
#endif
// Function return values: nonzero indicates an error
#define QUERN_OK 0
#define QUERN_INPUT_ERROR 1
#define QUERN_OUT_OF_MEMORY 2
// Takes a compressed sparse column format matrix and outputs it in compressed
// sparse row format (suitable for the QR factorization routines).
// Requires A1_row_start to have room for num_columns+1 entries,
// A1_column_index to have room for all nonzeros,
// and A1_value to have room for all nonzeros.
int
QUERN_convert_column_format_to_row_format
(
int
num_rows
,
int
num_columns
,
const
int
*
A0_column_start
,
const
int
*
A0_row_index
,
const
double
*
A0_value
,
int
*
A1_row_start
,
int
*
A1_column_index
,
double
*
A1_value
);
// Takes a compressed sparse row format m*n matrix and finds a reversed
// breadth-first search column ordering, suitable for incomplete QR
// preconditioning.
// Requires column_order to have room for n entries.
int
QUERN_get_rbfs_column_ordering
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
int
*
column_order
);
// Takes a length n column ordering and a compressed sparse row format m*n
// matrix, then reorders each row accordingly.
int
QUERN_reorder_columns
(
int
m
,
int
n
,
const
int
*
column_order
,
const
int
*
A_row_start
,
int
*
A_column_index
,
double
*
A_value
);
// Takes a compressed sparse row format m*n matrix and finds a row ordering
// which minimizes the lower profile---in particular, if A's rows can be
// permuted to make it upper triangular, row_order will do the trick.
// This is recommended as a cheap pre-process before QR, at least if nothing
// is known about the current structure, to improve performance.
// Requires row_order to have room for m integers.
int
QUERN_get_profile_row_ordering
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
int
*
row_order
);
// Reorders a given input vector x into an output vector y of length m.
int
QUERN_reorder_vector
(
int
m
,
const
int
*
order
,
const
double
*
x
,
double
*
y
);
// Applies the inverse order to a given input vector x, saving in an output
// vector y of length m.
int
QUERN_inverse_order_vector
(
int
m
,
const
int
*
order
,
const
double
*
x
,
double
*
y
);
// Takes a compressed sparse row format m*n matrix (m>=n) and outputs the upper
// triangular R factor from QR, also in compressed sparse row format. If
// row_order is non-null, it should contain the order in which rows of A should be
// taken; if it is null, the natural ordering is used. Memory for R is
// allocated internally; use QUERN_free_result to free.
int
QUERN_compute_qr_without_q
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
int
*
row_order
,
int
**
ptr_R_row_start
,
int
**
ptr_R_column_index
,
double
**
ptr_R_value
);
// Takes a compressed sparse row format m*n matrix (m>=n) and outputs the QR
// factors. The storage for Q encodes a sequence of Givens rotations and row
// swaps; it is not directly usable as a standard sparse matrix. R, however,
// is stored in standard compressed sparse row format. If row_order is non-null
// it should contain the order in which rows of A should be taken; if it is
// null, the natural ordering is used. Memory for Q and R is allocated
// internally; use QUERN_free_result to free.
int
QUERN_compute_qr
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
int
*
row_order
,
int
**
ptr_Q_row_start
,
int
**
ptr_Q_column_index
,
double
**
ptr_Q_value
,
int
**
ptr_R_row_start
,
int
**
ptr_R_column_index
,
double
**
ptr_R_value
);
// Takes a compressed sparse row format m*n matrix (m>=n) and outputs the upper
// triangular R factor from QR, with small entries dropped, also in compressed
// sparse row format. If row_order is non-null, it should contain the order in
// which rows of A should be taken; if it is null, the natural ordering is used.
// Memory for R is allocated internally; use QUERN_free_result to free.
int
QUERN_compute_incomplete_qr_without_q
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
int
*
row_order
,
double
drop_tolerance
,
int
**
ptr_R_row_start
,
int
**
ptr_R_column_index
,
double
**
ptr_R_value
);
// Takes a compressed sparse row format m*n matrix (m>=n) and outputs incomplete
// QR factors. The storage for Q encodes a sequence of Givens rotations and row
// swaps; it is not directly usable as a standard sparse matrix. R, however,
// is stored in standard compressed sparse row format. If row_order is non-null
// it should contain the order in which rows of A should be taken; if it is
// null, the natural ordering is used. Memory for Q and R is allocated
// internally; use QUERN_free_result to free.
int
QUERN_compute_incomplete_qr
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
int
*
row_order
,
double
drop_tolerance
,
int
**
ptr_Q_row_start
,
int
**
ptr_Q_column_index
,
double
**
ptr_Q_value
,
int
**
ptr_R_row_start
,
int
**
ptr_R_column_index
,
double
**
ptr_R_value
);
// Free the memory allocated during QR factorization (for either Q or R).
// After calling this, do not try to access the factor again!
void
QUERN_free_result
(
int
*
row_start
,
int
*
column_index
,
double
*
value
);
// Compute the product of an m*n CSR matrix with n-vector input in
// m-vector result.
int
QUERN_multiply
(
int
m
,
int
n
,
const
int
*
row_start
,
const
int
*
column_index
,
const
double
*
value
,
const
double
*
input
,
double
*
result
);
// Compute the product of an m*n CSR matrix transposes with m-vector input in
// n-vector result.
int
QUERN_multiply_transpose
(
int
m
,
int
n
,
const
int
*
row_start
,
const
int
*
column_index
,
const
double
*
value
,
const
double
*
input
,
double
*
result
);
// Compute the product Q*x in-place (Q from QR factorization).
// Note: if the input is naturally a length n vector, you should pad it with
// zeros to make it length m.
// If a row reordering of A was involved, you probably want to
// call QUERN_inverse_order_vector afterwards.
int
QUERN_multiply_with_q
(
int
m
,
const
int
*
Q_row_start
,
const
int
*
Q_column_index
,
const
double
*
Q_value
,
double
*
x
);
// Compute the product Q^T*x in-place (Q from QR factorization).
// If a row reordering of A was involved, you probably want to
// call QUERN_reorder_vector first.
int
QUERN_multiply_with_q_transpose
(
int
m
,
const
int
*
Q_row_start
,
const
int
*
Q_column_index
,
const
double
*
Q_value
,
double
*
x
);
// Compute result=R^{-1}*rhs (R from QR factorization).
// The vector result may actually be aliased to rhs, for an in-place solve.
int
QUERN_solve_with_r
(
int
n
,
const
int
*
R_row_start
,
const
int
*
R_column_index
,
const
double
*
R_value
,
const
double
*
rhs
,
double
*
result
);
// Compute R^{-T}*x in-place (R from QR factorization).
int
QUERN_solve_with_r_transpose_in_place
(
int
n
,
const
int
*
R_row_start
,
const
int
*
R_column_index
,
const
double
*
R_value
,
double
*
x
);
// CGNR solver for A^T*A*x=rhs, starting with zero initial guess,
// with R as preconditioner.
int
QUERN_solve_with_CGNR
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
double
*
rhs
,
const
int
*
R_row_start
,
const
int
*
R_column_index
,
const
double
*
R_value
,
int
max_iterations
,
double
absolute_convergence_tolerance
,
double
*
x
,
int
*
return_solved
,
int
*
return_iterations
,
double
*
return_residual_norm
);
#ifdef __cplusplus
}
#endif
#endif
libraries/quern/include/quern_list.h
0 → 100644
View file @
6fd7f3bb
#ifndef QUERN_LIST_H
#define QUERN_LIST_H
#include <algorithm>
#include <cstdlib>
// This is a light-weight singly linked list with half-decent
// allocation, suitable only for plain-old-data, and designed
// to make it easy to use robustly from plain C (e.g. no
// exceptions, basic memory management with malloc/free and
// returned error codes).
namespace
Quern
{
template
<
typename
T
>
struct
ListEntry
{
T
data
;
ListEntry
<
T
>*
next
;
ListEntry
(
void
)
{}
ListEntry
(
const
T
&
data_
,
ListEntry
<
T
>*
next_
=
0
)
:
data
(
data_
),
next
(
next_
)
{}
};
const
int
puddle_size
=
1020
;
template
<
typename
T
>
struct
Puddle
{
int
end
;
Puddle
*
next
;
ListEntry
<
T
>
array
[
puddle_size
];
};
template
<
typename
T
>
struct
Pool
{
Puddle
<
T
>*
puddle_head
;
ListEntry
<
T
>*
free_head
;
Pool
(
void
)
:
puddle_head
(
0
),
free_head
(
0
)
{}
~
Pool
(
void
)
{
Puddle
<
T
>*
p
=
puddle_head
;
while
(
p
){
Puddle
<
T
>*
p_next
=
p
->
next
;
std
::
free
(
p
);
p
=
p_next
;
}
puddle_head
=
0
;
free_head
=
0
;
}
ListEntry
<
T
>*
allocate
(
void
)
{
// if we just have something free at hand, use it
if
(
free_head
){
ListEntry
<
T
>*
p
=
free_head
;
free_head
=
free_head
->
next
;
return
p
;
}
// otherwise, if we know we need another puddle in the pool, try for it
if
(
!
puddle_head
||
puddle_head
->
end
==
puddle_size
){
Puddle
<
T
>*
new_puddle
=
(
Puddle
<
T
>*
)
std
::
malloc
(
sizeof
(
Puddle
<
T
>
));
if
(
!
new_puddle
)
return
0
;
new_puddle
->
end
=
0
;
new_puddle
->
next
=
puddle_head
;
puddle_head
=
new_puddle
;
}
return
&
puddle_head
->
array
[
puddle_head
->
end
++
];
}
void
release
(
ListEntry
<
T
>*
entry
)
{
entry
->
next
=
free_head
;
free_head
=
entry
;
}
};
template
<
typename
T
>
struct
ListIterator
{
ListEntry
<
T
>**
handle
;
// pointer to a "next" or "head" pointer in the list
ListIterator
(
ListEntry
<
T
>**
handle_
=
0
)
:
handle
(
handle_
)
{}
bool
still_going
(
void
)
const
{
assert
(
handle
);
return
*
handle
!=
0
;
}
void
operator
++
(
void
)
{
assert
(
handle
);
assert
(
*
handle
);
handle
=&
((
*
handle
)
->
next
);
}
T
&
operator
*
(
void
)
{
assert
(
handle
);
assert
(
*
handle
);
return
(
*
handle
)
->
data
;
}
T
*
operator
->
(
void
)
{
assert
(
handle
);
assert
(
*
handle
);
return
&
(
*
handle
)
->
data
;
}
const
T
*
operator
->
(
void
)
const
{
assert
(
handle
);
assert
(
*
handle
);
return
&
(
*
handle
)
->
data
;
}
const
T
&
operator
*
(
void
)
const
{
assert
(
handle
);
assert
(
*
handle
);
return
(
*
handle
)
->
data
;
}
};
template
<
typename
T
>
struct
List
{
Pool
<
T
>*
pool
;
ListEntry
<
T
>*
head
;
int
length
;
List
(
void
)
{}
void
init
(
Pool
<
T
>*
pool_
)
{
pool
=
pool_
;
head
=
0
;
length
=
0
;
}
ListIterator
<
T
>
begin
(
void
)
{
return
ListIterator
<
T
>
(
&
head
);
}
bool
empty
(
void
)
{
return
head
==
0
;
}
// p ends up referring to the next element
void
erase
(
ListIterator
<
T
>&
p
)
{
assert
(
p
.
handle
);
assert
(
*
p
.
handle
);
ListEntry
<
T
>*
q
=*
p
.
handle
;
*
p
.
handle
=
q
->
next
;
pool
->
release
(
q
);
--
length
;
}
T
&
front
(
void
)
{
assert
(
head
);
return
head
->
data
;
}
const
T
&
front
(
void
)
const
{
assert
(
head
);
return
head
->
data
;
}
// put the new element before the one p initially refers to;
// if successful, p ends up referring to the new element
bool
insert
(
ListIterator
<
T
>&
p
,
const
T
&
data
)
{
ListEntry
<
T
>*
q
=
pool
->
allocate
();
if
(
!
q
)
return
false
;
q
->
next
=*
p
.
handle
;
q
->
data
=
data
;
*
p
.
handle
=
q
;
++
length
;
return
true
;
}
void
pop_front
(
void
)
{
assert
(
head
);
ListEntry
<
T
>*
p
=
head
;
head
=
p
->
next
;
pool
->
release
(
p
);
--
length
;
}
bool
push_front
(
const
T
&
entry
)
{
ListEntry
<
T
>*
p
=
pool
->
allocate
();
if
(
!
p
)
return
false
;
p
->
data
=
entry
;
p
->
next
=
head
;
head
=
p
;
++
length
;
return
true
;
}
int
size
(
void
)
{
return
length
;
}
void
swap
(
List
<
T
>&
other
)
{
assert
(
pool
==
other
.
pool
);
std
::
swap
(
head
,
other
.
head
);
std
::
swap
(
length
,
other
.
length
);
}
};
}
// end namespace
#endif
libraries/quern/src/quern.cpp
0 → 100644
View file @
6fd7f3bb
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "quern.h"
int
QUERN_convert_column_format_to_row_format
(
int
num_rows
,
int
num_columns
,
const
int
*
A0_column_start
,
const
int
*
A0_row_index
,
const
double
*
A0_value
,
int
*
A1_row_start
,
int
*
A1_column_index
,
double
*
A1_value
)
{
// check input
if
(
num_rows
<=
0
||
num_columns
<=
0
)
return
QUERN_INPUT_ERROR
;
if
(
!
A0_column_start
||
!
A0_row_index
||
!
A0_value
)
return
QUERN_INPUT_ERROR
;
if
(
!
A1_row_start
||
!
A1_column_index
||
!
A1_value
)
return
QUERN_INPUT_ERROR
;
// figure out number of entries in each row
std
::
memset
(
A1_row_start
,
0
,
(
num_rows
+
1
)
*
sizeof
(
int
));
for
(
int
i
=
0
;
i
<
num_columns
;
++
i
){
if
(
A0_column_start
[
i
]
>
A0_column_start
[
i
+
1
])
return
QUERN_INPUT_ERROR
;
for
(
int
j
=
A0_column_start
[
i
];
j
<
A0_column_start
[
i
+
1
];
++
j
){
if
(
A0_row_index
[
j
]
<
0
||
A0_row_index
[
j
]
>=
num_rows
)
return
QUERN_INPUT_ERROR
;
++
A1_row_start
[
A0_row_index
[
j
]
+
1
];
}
}
// cumulative sum to get row_start
for
(
int
i
=
0
;
i
<
num_rows
;
++
i
)
A1_row_start
[
i
+
1
]
+=
A1_row_start
[
i
];
// use a temporary copy of row_start for keeping track of where we add
int
*
row_pointer
=
(
int
*
)
std
::
malloc
(
num_rows
*
sizeof
(
int
));
if
(
!
row_pointer
)
return
QUERN_OUT_OF_MEMORY
;
std
::
memcpy
(
row_pointer
,
A1_row_start
,
num_rows
*
sizeof
(
int
));
// then fill in the entries
for
(
int
i
=
0
;
i
<
num_columns
;
++
i
){
for
(
int
j
=
A0_column_start
[
i
];
j
<
A0_column_start
[
i
+
1
];
++
j
){
int
r
=
A0_row_index
[
j
];
A1_column_index
[
row_pointer
[
r
]]
=
i
;
A1_value
[
row_pointer
[
r
]]
=
A0_value
[
j
];
++
row_pointer
[
r
];
}
}
std
::
free
(
row_pointer
);
return
QUERN_OK
;
}
int
QUERN_multiply
(
int
m
,
int
n
,
const
int
*
row_start
,
const
int
*
column_index
,
const
double
*
value
,
const
double
*
input
,
double
*
result
)
{
if
(
m
<=
0
||
n
<=
0
||
!
row_start
||
!
column_index
||
!
value
||
!
input
||
!
result
)
return
QUERN_INPUT_ERROR
;
int
i
,
j
;
double
x
;
for
(
i
=
0
;
i
<
m
;
++
i
){
x
=
0
;
for
(
j
=
row_start
[
i
];
j
<
row_start
[
i
+
1
];
++
j
)
x
+=
value
[
j
]
*
input
[
column_index
[
j
]];
result
[
i
]
=
x
;
}
return
QUERN_OK
;
}
int
QUERN_multiply_transpose
(
int
m
,
int
n
,
const
int
*
row_start
,
const
int
*
column_index
,
const
double
*
value
,
const
double
*
input
,
double
*
result
)
{
if
(
m
<=
0
||
n
<=
0
||
!
row_start
||
!
column_index
||
!
value
||
!
input
||
!
result
)
return
QUERN_INPUT_ERROR
;
int
i
,
j
;
double
x
;
std
::
memset
(
result
,
0
,
n
*
sizeof
(
double
));
for
(
i
=
0
;
i
<
m
;
++
i
){
x
=
input
[
i
];
for
(
j
=
row_start
[
i
];
j
<
row_start
[
i
+
1
];
++
j
)
result
[
column_index
[
j
]]
+=
value
[
j
]
*
x
;
}
return
QUERN_OK
;
}
libraries/quern/src/quern_factorization.cpp
0 → 100644
View file @
6fd7f3bb
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "quern.h"
#include "quern_list.h"
struct
SparseEntry
{
int
index
;
double
value
;
SparseEntry
(
void
)
{}
SparseEntry
(
int
index_
,
double
value_
)
:
index
(
index_
),
value
(
value_
)
{}
};
typedef
Quern
::
List
<
SparseEntry
>
SparseVector
;
static
bool
copy_row
(
int
nnz
,
const
int
*
index
,
const
double
*
value
,
SparseVector
&
x
)
{
for
(
int
i
=
nnz
-
1
;
i
>=
0
;
--
i
)
if
(
value
[
i
]){
if
(
!
x
.
push_front
(
SparseEntry
(
index
[
i
],
value
[
i
])))
return
false
;
}
return
true
;
}
// compute c>=0 and s, with c^2+s^2=1, so that s*a+c*b=0
static
void
givens
(
double
a
,
double
b
,
double
&
c
,
double
&
s
)
{
if
(
b
==
0
){
c
=
1
;
s
=
0
;
}
else
{
if
(
std
::
fabs
(
b
)
>
std
::
fabs
(
a
)){
double
tau
=-
a
/
b
;
s
=
1
/
std
::
sqrt
(
1
+
tau
*
tau
);
c
=
s
*
tau
;
if
(
c
<
0
){
c
=-
c
;
s
=-
s
;
}
}
else
{
double
tau
=-
b
/
a
;
c
=
1
/
std
::
sqrt
(
1
+
tau
*
tau
);
s
=
c
*
tau
;
}
}
}
// given c and s (c>=0, c^2+s^2=1) encode them in a single double
static
double
encode
(
double
c
,
double
s
)
{
if
(
std
::
fabs
(
s
)
<
c
)
return
s
;
// will be at most sqrt(0.5)=0.707... in magnitude
else
return
copysign
(
1
/
c
,
s
);
// will be least sqrt(2)=1.414... in magnitude
}
// given output from encode, reconstruct c and s (c>=0, c^2+s^2=1)
static
void
decode
(
double
tau
,
double
&
c
,
double
&
s
)
{
if
(
std
::
fabs
(
tau
)
<
1
){
s
=
tau
;
c
=
std
::
sqrt
(
1
-
s
*
s
);
}
else
{
c
=
1
/
tau
;
s
=
std
::
sqrt
(
1
-
c
*
c
);
if
(
c
<
0
){
c
=-
c
;
s
=-
s
;
}
}
}
static
bool
apply_givens
(
SparseVector
&
x
,
SparseVector
&
y
,
int
diagonal
,
double
&
c
,
double
&
s
)
{
assert
(
!
x
.
empty
()
&&
x
.
front
().
index
==
diagonal
&&
x
.
front
().
value
);
assert
(
!
y
.
empty
()
&&
y
.
front
().
index
==
diagonal
&&
y
.
front
().
value
);
// find the rotation we need
double
a
=
x
.
front
().
value
,
b
=
y
.
front
().
value
;
givens
(
a
,
b
,
c
,
s
);
assert
(
c
&&
s
);
// rotate the start of each list
x
.
front
().
value
=
c
*
a
-
s
*
b
;
y
.
pop_front
();
// then update the rest (x_new = c*x-s*y and y_new = s*x+c*y)
Quern
::
ListIterator
<
SparseEntry
>
p
=
x
.
begin
(),
q
=
y
.
begin
();
++
p
;
// skip the first value we already took care of
while
(
p
.
still_going
()
&&
q
.
still_going
()){
if
(
p
->
index
==
q
->
index
){
double
xnew
=
c
*
p
->
value
-
s
*
q
->
value
,
ynew
=
s
*
p
->
value
+
c
*
q
->
value
;
if
(
xnew
){
p
->
value
=
xnew
;
++
p
;
}
else
x
.
erase
(
p
);
if
(
ynew
){
q
->
value
=
ynew
;
++
q
;
}
else
y
.
erase
(
q
);
}
else
if
(
p
->
index
<
q
->
index
){
int
k
=
p
->
index
;
double
xnew
=
c
*
p
->
value
,
ynew
=
s
*
p
->
value
;
p
->
value
=
xnew
;
++
p
;
if
(
!
y
.
insert
(
q
,
SparseEntry
(
k
,
ynew
)))
return
false
;
++
q
;
}
else
{
int
k
=
q
->
index
;
double
xnew
=-
s
*
q
->
value
,
ynew
=
c
*
q
->
value
;
if
(
!
x
.
insert
(
p
,
SparseEntry
(
k
,
xnew
)))
return
false
;
++
p
;
q
->
value
=
ynew
;
++
q
;
}
}
if
(
p
.
still_going
()){
do
{
int
k
=
p
->
index
;
double
xnew
=
c
*
p
->
value
,
ynew
=
s
*
p
->
value
;
p
->
value
=
xnew
;
++
p
;
if
(
!
y
.
insert
(
q
,
SparseEntry
(
k
,
ynew
)))
return
false
;
++
q
;
}
while
(
p
.
still_going
());
}
else
if
(
q
.
still_going
()){
do
{
int
k
=
q
->
index
;
double
xnew
=-
s
*
q
->
value
,
ynew
=
c
*
q
->
value
;
if
(
!
x
.
insert
(
p
,
SparseEntry
(
k
,
xnew
)))
return
false
;
++
p
;
q
->
value
=
ynew
;
++
q
;
}
while
(
q
.
still_going
());
}
return
true
;
}
int
QUERN_compute_qr_without_q
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
int
*
row_order
,
int
**
ptr_R_row_start
,
int
**
ptr_R_column_index
,
double
**
ptr_R_value
)
{
if
(
m
<=
0
||
n
<=
0
||
m
<
n
||
!
A_row_start
||
!
A_column_index
||
!
A_value
||
!
ptr_R_row_start
||
!
ptr_R_column_index
||
!
ptr_R_value
)
return
QUERN_INPUT_ERROR
;
// set up lists for dynamically building R
Quern
::
Pool
<
SparseEntry
>
pool
;
SparseVector
*
R
=
(
SparseVector
*
)
std
::
malloc
(
m
*
sizeof
(
SparseVector
));
if
(
!
R
)
return
QUERN_OUT_OF_MEMORY
;
for
(
int
i
=
0
;
i
<
m
;
++
i
)
R
[
i
].
init
(
&
pool
);
// do the Givens QR
SparseVector
row
;
row
.
init
(
&
pool
);
double
c
,
s
;
for
(
int
a
=
0
;
a
<
m
;
++
a
){
int
i
=
(
row_order
?
row_order
[
a
]
:
a
);
if
(
!
copy_row
(
A_row_start
[
i
+
1
]
-
A_row_start
[
i
],
A_column_index
+
A_row_start
[
i
],
A_value
+
A_row_start
[
i
],
row
)){
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
while
(
!
row
.
empty
()
&&
row
.
front
().
index
<
a
&&
row
.
front
().
index
<
n
){
int
j
=
row
.
front
().
index
;
if
(
R
[
j
].
empty
()
||
R
[
j
].
front
().
index
>
j
){
// swap?
R
[
j
].
swap
(
row
);
}
else
{
// use Givens
if
(
!
apply_givens
(
R
[
j
],
row
,
j
,
c
,
s
)){
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
}
}
if
(
a
<
n
){
R
[
a
].
swap
(
row
);
assert
(
R
[
a
].
empty
()
||
R
[
a
].
front
().
index
>=
a
);
}
}
// transfer R's lists to static CSR form
int
*
R_row_start
=
(
int
*
)
std
::
malloc
((
n
+
1
)
*
sizeof
(
int
));
if
(
!
R_row_start
){
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
R_row_start
[
0
]
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
)
R_row_start
[
i
+
1
]
=
R_row_start
[
i
]
+
R
[
i
].
size
();
int
Rnnz
=
R_row_start
[
n
];
int
*
R_column_index
=
(
int
*
)
std
::
malloc
(
Rnnz
*
sizeof
(
int
));
if
(
!
R_column_index
){
std
::
free
(
R
);
std
::
free
(
R_row_start
);
return
QUERN_OUT_OF_MEMORY
;
}
double
*
R_value
=
(
double
*
)
std
::
malloc
(
Rnnz
*
sizeof
(
double
));
if
(
!
R_value
){
std
::
free
(
R
);
std
::
free
(
R_row_start
);
std
::
free
(
R_column_index
);
return
QUERN_OUT_OF_MEMORY
;
}
int
j
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
){
Quern
::
ListIterator
<
SparseEntry
>
p
;
for
(
p
=
R
[
i
].
begin
();
p
.
still_going
();
++
p
){
R_column_index
[
j
]
=
p
->
index
;
R_value
[
j
]
=
p
->
value
;
++
j
;
}
}
std
::
free
(
R
);
*
ptr_R_row_start
=
R_row_start
;
*
ptr_R_column_index
=
R_column_index
;
*
ptr_R_value
=
R_value
;
return
QUERN_OK
;
}
int
QUERN_compute_qr
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
int
*
row_order
,
int
**
ptr_Q_row_start
,
int
**
ptr_Q_column_index
,
double
**
ptr_Q_value
,
int
**
ptr_R_row_start
,
int
**
ptr_R_column_index
,
double
**
ptr_R_value
)
{
if
(
m
<=
0
||
n
<=
0
||
m
<
n
||
!
A_row_start
||
!
A_column_index
||
!
A_value
||
!
ptr_Q_row_start
||
!
ptr_Q_column_index
||
!
ptr_Q_value
||
!
ptr_R_row_start
||
!
ptr_R_column_index
||
!
ptr_R_value
)
return
QUERN_INPUT_ERROR
;
// set up lists for dynamically building Q and R
Quern
::
Pool
<
SparseEntry
>
pool
;
SparseVector
*
Q
=
(
SparseVector
*
)
std
::
malloc
(
m
*
sizeof
(
SparseVector
));
if
(
!
Q
)
return
QUERN_OUT_OF_MEMORY
;
SparseVector
*
R
=
(
SparseVector
*
)
std
::
malloc
(
m
*
sizeof
(
SparseVector
));
if
(
!
R
){
std
::
free
(
Q
);
return
QUERN_OUT_OF_MEMORY
;
}
for
(
int
i
=
0
;
i
<
m
;
++
i
){
Q
[
i
].
init
(
&
pool
);
R
[
i
].
init
(
&
pool
);
}
// do the Givens QR
SparseVector
row
;
row
.
init
(
&
pool
);
double
c
,
s
;
for
(
int
a
=
0
;
a
<
m
;
++
a
){
int
i
=
(
row_order
?
row_order
[
a
]
:
a
);
if
(
!
copy_row
(
A_row_start
[
i
+
1
]
-
A_row_start
[
i
],
A_column_index
+
A_row_start
[
i
],
A_value
+
A_row_start
[
i
],
row
)){
std
::
free
(
Q
);
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
Quern
::
ListIterator
<
SparseEntry
>
q
=
Q
[
a
].
begin
();
while
(
!
row
.
empty
()
&&
row
.
front
().
index
<
a
&&
row
.
front
().
index
<
n
){
int
j
=
row
.
front
().
index
;
if
(
R
[
j
].
empty
()
||
R
[
j
].
front
().
index
>
j
){
// swap?
R
[
j
].
swap
(
row
);
Q
[
a
].
insert
(
q
,
SparseEntry
(
j
,
1
));
++
q
;
}
else
{
// use Givens
if
(
!
apply_givens
(
R
[
j
],
row
,
j
,
c
,
s
)){
std
::
free
(
Q
);
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
Q
[
a
].
insert
(
q
,
SparseEntry
(
j
,
encode
(
c
,
s
)));
++
q
;
}
}
if
(
a
<
n
){
R
[
a
].
swap
(
row
);
assert
(
R
[
a
].
empty
()
||
R
[
a
].
front
().
index
>=
a
);
}
}
// transfer Q's lists to static CSR form
int
*
Q_row_start
=
(
int
*
)
std
::
malloc
((
m
+
1
)
*
sizeof
(
int
));
if
(
!
Q_row_start
){
std
::
free
(
Q
);
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
Q_row_start
[
0
]
=
0
;
for
(
int
i
=
0
;
i
<
m
;
++
i
)
Q_row_start
[
i
+
1
]
=
Q_row_start
[
i
]
+
Q
[
i
].
size
();
int
Qnnz
=
Q_row_start
[
m
];
int
*
Q_column_index
=
(
int
*
)
std
::
malloc
(
Qnnz
*
sizeof
(
int
));
if
(
!
Q_column_index
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
return
QUERN_OUT_OF_MEMORY
;
}
double
*
Q_value
=
(
double
*
)
std
::
malloc
(
Qnnz
*
sizeof
(
double
));
if
(
!
Q_value
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
std
::
free
(
Q_column_index
);
return
QUERN_OUT_OF_MEMORY
;
}
int
j
=
0
;
for
(
int
i
=
0
;
i
<
m
;
++
i
){
Quern
::
ListIterator
<
SparseEntry
>
q
;
for
(
q
=
Q
[
i
].
begin
();
q
.
still_going
();
++
q
){
Q_column_index
[
j
]
=
q
->
index
;
Q_value
[
j
]
=
q
->
value
;
++
j
;
}
}
std
::
free
(
Q
);
// transfer R's lists to static CSR form
int
*
R_row_start
=
(
int
*
)
std
::
malloc
((
n
+
1
)
*
sizeof
(
int
));
if
(
!
R_row_start
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
std
::
free
(
Q_column_index
);
std
::
free
(
Q_value
);
return
QUERN_OUT_OF_MEMORY
;
}
R_row_start
[
0
]
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
)
R_row_start
[
i
+
1
]
=
R_row_start
[
i
]
+
R
[
i
].
size
();
int
Rnnz
=
R_row_start
[
n
];
int
*
R_column_index
=
(
int
*
)
std
::
malloc
(
Rnnz
*
sizeof
(
int
));
if
(
!
R_column_index
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
std
::
free
(
Q_column_index
);
std
::
free
(
Q_value
);
std
::
free
(
R_row_start
);
return
QUERN_OUT_OF_MEMORY
;
}
double
*
R_value
=
(
double
*
)
std
::
malloc
(
Rnnz
*
sizeof
(
double
));
if
(
!
R_value
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
std
::
free
(
Q_column_index
);
std
::
free
(
Q_value
);
std
::
free
(
R_row_start
);
std
::
free
(
R_column_index
);
return
QUERN_OUT_OF_MEMORY
;
}
j
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
){
Quern
::
ListIterator
<
SparseEntry
>
p
;
for
(
p
=
R
[
i
].
begin
();
p
.
still_going
();
++
p
){
R_column_index
[
j
]
=
p
->
index
;
R_value
[
j
]
=
p
->
value
;
++
j
;
}
}
std
::
free
(
R
);
*
ptr_Q_row_start
=
Q_row_start
;
*
ptr_Q_column_index
=
Q_column_index
;
*
ptr_Q_value
=
Q_value
;
*
ptr_R_row_start
=
R_row_start
;
*
ptr_R_column_index
=
R_column_index
;
*
ptr_R_value
=
R_value
;
return
QUERN_OK
;
}
static
void
determine_column_thresholds
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
double
drop_tolerance
,
double
*
drop
)
{
std
::
memset
(
drop
,
0
,
n
*
sizeof
(
double
));
for
(
int
i
=
0
;
i
<
m
;
++
i
){
for
(
int
j
=
A_row_start
[
i
];
j
<
A_row_start
[
i
+
1
];
++
j
)
drop
[
A_column_index
[
j
]]
+=
A_value
[
j
]
*
A_value
[
j
];
}
for
(
int
i
=
0
;
i
<
n
;
++
i
){
drop
[
i
]
=
std
::
sqrt
(
drop
[
i
])
*
drop_tolerance
;
}
}
static
bool
apply_givens
(
SparseVector
&
x
,
SparseVector
&
y
,
int
diagonal
,
const
double
*
drop
,
double
&
c
,
double
&
s
)
{
assert
(
!
x
.
empty
()
&&
x
.
front
().
index
==
diagonal
&&
x
.
front
().
value
);
assert
(
!
y
.
empty
()
&&
y
.
front
().
index
==
diagonal
&&
y
.
front
().
value
);
// find the rotation we need
double
a
=
x
.
front
().
value
,
b
=
y
.
front
().
value
;
givens
(
a
,
b
,
c
,
s
);
assert
(
c
&&
s
);
// rotate the start of each list
x
.
front
().
value
=
c
*
a
-
s
*
b
;
y
.
pop_front
();
// then update the rest (x_new = c*x-s*y and y_new = s*x+c*y)
Quern
::
ListIterator
<
SparseEntry
>
p
=
x
.
begin
(),
q
=
y
.
begin
();
++
p
;
// skip the first value we already took care of
while
(
p
.
still_going
()
&&
q
.
still_going
()){
if
(
p
->
index
==
q
->
index
){
int
k
=
p
->
index
;
double
xnew
=
c
*
p
->
value
-
s
*
q
->
value
,
ynew
=
s
*
p
->
value
+
c
*
q
->
value
;
if
(
std
::
fabs
(
xnew
)
>
drop
[
k
]){
p
->
value
=
xnew
;
++
p
;
}
else
x
.
erase
(
p
);
if
(
std
::
fabs
(
ynew
)
>
drop
[
k
]){
q
->
value
=
ynew
;
++
q
;
}
else
y
.
erase
(
q
);
}
else
if
(
p
->
index
<
q
->
index
){
int
k
=
p
->
index
;
double
xnew
=
c
*
p
->
value
,
ynew
=
s
*
p
->
value
;
if
(
std
::
fabs
(
xnew
)
>
drop
[
k
]){
p
->
value
=
xnew
;
++
p
;
}
else
x
.
erase
(
p
);
if
(
std
::
fabs
(
ynew
)
>
drop
[
k
]){
if
(
!
y
.
insert
(
q
,
SparseEntry
(
k
,
ynew
)))
return
false
;
++
q
;
}
}
else
{
int
k
=
q
->
index
;
double
xnew
=-
s
*
q
->
value
,
ynew
=
c
*
q
->
value
;
if
(
std
::
fabs
(
xnew
)
>
drop
[
k
]){
if
(
!
x
.
insert
(
p
,
SparseEntry
(
k
,
xnew
)))
return
false
;
++
p
;
}
if
(
std
::
fabs
(
ynew
)
>
drop
[
k
]){
q
->
value
=
ynew
;
++
q
;
}
else
y
.
erase
(
q
);
}
}
if
(
p
.
still_going
()){
do
{
int
k
=
p
->
index
;
double
xnew
=
c
*
p
->
value
,
ynew
=
s
*
p
->
value
;
if
(
std
::
fabs
(
xnew
)
>
drop
[
k
]){
p
->
value
=
xnew
;
++
p
;
}
else
x
.
erase
(
p
);
if
(
std
::
fabs
(
ynew
)
>
drop
[
k
]){
if
(
!
y
.
insert
(
q
,
SparseEntry
(
k
,
ynew
)))
return
false
;
++
q
;
}
}
while
(
p
.
still_going
());
}
else
if
(
q
.
still_going
()){
do
{
int
k
=
q
->
index
;
double
xnew
=-
s
*
q
->
value
,
ynew
=
c
*
q
->
value
;
if
(
std
::
fabs
(
xnew
)
>
drop
[
k
]){
if
(
!
x
.
insert
(
p
,
SparseEntry
(
k
,
xnew
)))
return
false
;
++
p
;
}
if
(
std
::
fabs
(
ynew
)
>
drop
[
k
]){
q
->
value
=
ynew
;
++
q
;
}
else
y
.
erase
(
q
);
}
while
(
q
.
still_going
());
}
return
true
;
}
int
QUERN_compute_incomplete_qr_without_q
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
int
*
row_order
,
double
drop_tolerance
,
int
**
ptr_R_row_start
,
int
**
ptr_R_column_index
,
double
**
ptr_R_value
)
{
if
(
m
<=
0
||
n
<=
0
||
m
<
n
||
!
A_row_start
||
!
A_column_index
||
!
A_value
||
!
ptr_R_row_start
||
!
ptr_R_column_index
||
!
ptr_R_value
)
return
QUERN_INPUT_ERROR
;
// find per-column drop tolerance
double
*
drop
=
(
double
*
)
std
::
malloc
(
n
*
sizeof
(
double
));
if
(
!
drop
)
return
QUERN_OUT_OF_MEMORY
;
determine_column_thresholds
(
m
,
n
,
A_row_start
,
A_column_index
,
A_value
,
drop_tolerance
,
drop
);
// set up lists for dynamically building R
Quern
::
Pool
<
SparseEntry
>
pool
;
SparseVector
*
R
=
(
SparseVector
*
)
std
::
malloc
(
m
*
sizeof
(
SparseVector
));
if
(
!
R
){
std
::
free
(
drop
);
return
QUERN_OUT_OF_MEMORY
;
}
for
(
int
i
=
0
;
i
<
m
;
++
i
)
R
[
i
].
init
(
&
pool
);
// do the Givens QR
SparseVector
row
;
row
.
init
(
&
pool
);
double
c
,
s
;
for
(
int
a
=
0
;
a
<
m
;
++
a
){
int
i
=
(
row_order
?
row_order
[
a
]
:
a
);
if
(
!
copy_row
(
A_row_start
[
i
+
1
]
-
A_row_start
[
i
],
A_column_index
+
A_row_start
[
i
],
A_value
+
A_row_start
[
i
],
row
)){
std
::
free
(
drop
);
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
while
(
!
row
.
empty
()
&&
row
.
front
().
index
<
a
&&
row
.
front
().
index
<
n
){
int
j
=
row
.
front
().
index
;
if
(
R
[
j
].
empty
()
||
R
[
j
].
front
().
index
>
j
){
// swap?
R
[
j
].
swap
(
row
);
}
else
{
// use Givens
if
(
!
apply_givens
(
R
[
j
],
row
,
j
,
drop
,
c
,
s
)){
std
::
free
(
drop
);
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
}
}
if
(
a
<
n
){
R
[
a
].
swap
(
row
);
assert
(
R
[
a
].
empty
()
||
R
[
a
].
front
().
index
>=
a
);
}
}
// don't need this any more
std
::
free
(
drop
);
// transfer R's lists to static CSR form
int
*
R_row_start
=
(
int
*
)
std
::
malloc
((
n
+
1
)
*
sizeof
(
int
));
if
(
!
R_row_start
){
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
R_row_start
[
0
]
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
)
R_row_start
[
i
+
1
]
=
R_row_start
[
i
]
+
R
[
i
].
size
();
int
Rnnz
=
R_row_start
[
n
];
int
*
R_column_index
=
(
int
*
)
std
::
malloc
(
Rnnz
*
sizeof
(
int
));
if
(
!
R_column_index
){
std
::
free
(
R
);
std
::
free
(
R_row_start
);
return
QUERN_OUT_OF_MEMORY
;
}
double
*
R_value
=
(
double
*
)
std
::
malloc
(
Rnnz
*
sizeof
(
double
));
if
(
!
R_value
){
std
::
free
(
R
);
std
::
free
(
R_row_start
);
std
::
free
(
R_column_index
);
return
QUERN_OUT_OF_MEMORY
;
}
int
j
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
){
Quern
::
ListIterator
<
SparseEntry
>
p
;
for
(
p
=
R
[
i
].
begin
();
p
.
still_going
();
++
p
){
R_column_index
[
j
]
=
p
->
index
;
R_value
[
j
]
=
p
->
value
;
++
j
;
}
}
std
::
free
(
R
);
*
ptr_R_row_start
=
R_row_start
;
*
ptr_R_column_index
=
R_column_index
;
*
ptr_R_value
=
R_value
;
return
QUERN_OK
;
}
int
QUERN_compute_incomplete_qr
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
int
*
row_order
,
double
drop_tolerance
,
int
**
ptr_Q_row_start
,
int
**
ptr_Q_column_index
,
double
**
ptr_Q_value
,
int
**
ptr_R_row_start
,
int
**
ptr_R_column_index
,
double
**
ptr_R_value
)
{
if
(
m
<=
0
||
n
<=
0
||
m
<
n
||
!
A_row_start
||
!
A_column_index
||
!
A_value
||
!
ptr_Q_row_start
||
!
ptr_Q_column_index
||
!
ptr_Q_value
||
!
ptr_R_row_start
||
!
ptr_R_column_index
||
!
ptr_R_value
)
return
QUERN_INPUT_ERROR
;
// find per-column drop tolerance
double
*
drop
=
(
double
*
)
std
::
malloc
(
n
*
sizeof
(
double
));
if
(
!
drop
)
return
QUERN_OUT_OF_MEMORY
;
determine_column_thresholds
(
m
,
n
,
A_row_start
,
A_column_index
,
A_value
,
drop_tolerance
,
drop
);
// set up lists for dynamically building Q and R
Quern
::
Pool
<
SparseEntry
>
pool
;
SparseVector
*
Q
=
(
SparseVector
*
)
std
::
malloc
(
m
*
sizeof
(
SparseVector
));
if
(
!
Q
){
std
::
free
(
drop
);
return
QUERN_OUT_OF_MEMORY
;
}
SparseVector
*
R
=
(
SparseVector
*
)
std
::
malloc
(
m
*
sizeof
(
SparseVector
));
if
(
!
R
){
std
::
free
(
drop
);
std
::
free
(
Q
);
return
QUERN_OUT_OF_MEMORY
;
}
for
(
int
i
=
0
;
i
<
m
;
++
i
){
Q
[
i
].
init
(
&
pool
);
R
[
i
].
init
(
&
pool
);
}
// do the Givens QR
SparseVector
row
;
row
.
init
(
&
pool
);
double
c
,
s
;
for
(
int
a
=
0
;
a
<
m
;
++
a
){
int
i
=
(
row_order
?
row_order
[
a
]
:
a
);
if
(
!
copy_row
(
A_row_start
[
i
+
1
]
-
A_row_start
[
i
],
A_column_index
+
A_row_start
[
i
],
A_value
+
A_row_start
[
i
],
row
)){
std
::
free
(
drop
);
std
::
free
(
Q
);
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
Quern
::
ListIterator
<
SparseEntry
>
q
=
Q
[
a
].
begin
();
while
(
!
row
.
empty
()
&&
row
.
front
().
index
<
a
&&
row
.
front
().
index
<
n
){
int
j
=
row
.
front
().
index
;
if
(
R
[
j
].
empty
()
||
R
[
j
].
front
().
index
>
j
){
// swap?
R
[
j
].
swap
(
row
);
Q
[
a
].
insert
(
q
,
SparseEntry
(
j
,
1
));
++
q
;
}
else
{
// use Givens
if
(
!
apply_givens
(
R
[
j
],
row
,
j
,
drop
,
c
,
s
)){
std
::
free
(
drop
);
std
::
free
(
Q
);
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
Q
[
a
].
insert
(
q
,
SparseEntry
(
j
,
encode
(
c
,
s
)));
++
q
;
}
}
if
(
a
<
n
){
R
[
a
].
swap
(
row
);
assert
(
R
[
a
].
empty
()
||
R
[
a
].
front
().
index
>=
a
);
}
}
// don't need this any more
std
::
free
(
drop
);
// transfer Q's lists to static CSR form
int
*
Q_row_start
=
(
int
*
)
std
::
malloc
((
m
+
1
)
*
sizeof
(
int
));
if
(
!
Q_row_start
){
std
::
free
(
Q
);
std
::
free
(
R
);
return
QUERN_OUT_OF_MEMORY
;
}
Q_row_start
[
0
]
=
0
;
for
(
int
i
=
0
;
i
<
m
;
++
i
)
Q_row_start
[
i
+
1
]
=
Q_row_start
[
i
]
+
Q
[
i
].
size
();
int
Qnnz
=
Q_row_start
[
m
];
int
*
Q_column_index
=
(
int
*
)
std
::
malloc
(
Qnnz
*
sizeof
(
int
));
if
(
!
Q_column_index
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
return
QUERN_OUT_OF_MEMORY
;
}
double
*
Q_value
=
(
double
*
)
std
::
malloc
(
Qnnz
*
sizeof
(
double
));
if
(
!
Q_value
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
std
::
free
(
Q_column_index
);
return
QUERN_OUT_OF_MEMORY
;
}
int
j
=
0
;
for
(
int
i
=
0
;
i
<
m
;
++
i
){
Quern
::
ListIterator
<
SparseEntry
>
q
;
for
(
q
=
Q
[
i
].
begin
();
q
.
still_going
();
++
q
){
Q_column_index
[
j
]
=
q
->
index
;
Q_value
[
j
]
=
q
->
value
;
++
j
;
}
}
std
::
free
(
Q
);
// transfer R's lists to static CSR form
int
*
R_row_start
=
(
int
*
)
std
::
malloc
((
n
+
1
)
*
sizeof
(
int
));
if
(
!
R_row_start
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
std
::
free
(
Q_column_index
);
std
::
free
(
Q_value
);
return
QUERN_OUT_OF_MEMORY
;
}
R_row_start
[
0
]
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
)
R_row_start
[
i
+
1
]
=
R_row_start
[
i
]
+
R
[
i
].
size
();
int
Rnnz
=
R_row_start
[
n
];
int
*
R_column_index
=
(
int
*
)
std
::
malloc
(
Rnnz
*
sizeof
(
int
));
if
(
!
R_column_index
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
std
::
free
(
Q_column_index
);
std
::
free
(
Q_value
);
std
::
free
(
R_row_start
);
return
QUERN_OUT_OF_MEMORY
;
}
double
*
R_value
=
(
double
*
)
std
::
malloc
(
Rnnz
*
sizeof
(
double
));
if
(
!
R_value
){
std
::
free
(
Q
);
std
::
free
(
R
);
std
::
free
(
Q_row_start
);
std
::
free
(
Q_column_index
);
std
::
free
(
Q_value
);
std
::
free
(
R_row_start
);
std
::
free
(
R_column_index
);
return
QUERN_OUT_OF_MEMORY
;
}
j
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
){
Quern
::
ListIterator
<
SparseEntry
>
p
;
for
(
p
=
R
[
i
].
begin
();
p
.
still_going
();
++
p
){
R_column_index
[
j
]
=
p
->
index
;
R_value
[
j
]
=
p
->
value
;
++
j
;
}
}
std
::
free
(
R
);
*
ptr_Q_row_start
=
Q_row_start
;
*
ptr_Q_column_index
=
Q_column_index
;
*
ptr_Q_value
=
Q_value
;
*
ptr_R_row_start
=
R_row_start
;
*
ptr_R_column_index
=
R_column_index
;
*
ptr_R_value
=
R_value
;
return
QUERN_OK
;
}
void
QUERN_free_result
(
int
*
row_start
,
int
*
column_index
,
double
*
value
)
{
std
::
free
(
row_start
);
std
::
free
(
column_index
);
std
::
free
(
value
);
}
int
QUERN_multiply_with_q
(
int
m
,
const
int
*
Q_row_start
,
const
int
*
Q_column_index
,
const
double
*
Q_value
,
double
*
x
)
{
if
(
m
<=
0
||
!
Q_row_start
||
!
Q_column_index
||
!
Q_value
)
return
QUERN_INPUT_ERROR
;
int
i
,
j
,
k
;
double
c
,
s
;
for
(
i
=
m
-
1
;
i
>=
0
;
--
i
){
for
(
j
=
Q_row_start
[
i
+
1
]
-
1
;
j
>=
Q_row_start
[
i
];
--
j
){
k
=
Q_column_index
[
j
];
if
(
Q_value
[
j
]
==
1.
){
// swap?
std
::
swap
(
x
[
i
],
x
[
k
]);
}
else
{
decode
(
Q_value
[
j
],
c
,
s
);
double
newxk
=
c
*
x
[
k
]
+
s
*
x
[
i
];
x
[
i
]
=-
s
*
x
[
k
]
+
c
*
x
[
i
];
x
[
k
]
=
newxk
;
}
}
}
return
QUERN_OK
;
}
int
QUERN_multiply_with_q_transpose
(
int
m
,
const
int
*
Q_row_start
,
const
int
*
Q_column_index
,
const
double
*
Q_value
,
double
*
x
)
{
if
(
m
<=
0
||
!
Q_row_start
||
!
Q_column_index
||
!
Q_value
)
return
QUERN_INPUT_ERROR
;
int
i
,
j
,
k
;
double
c
,
s
;
for
(
i
=
0
;
i
<
m
;
++
i
){
for
(
j
=
Q_row_start
[
i
];
j
<
Q_row_start
[
i
+
1
];
++
j
){
k
=
Q_column_index
[
j
];
if
(
Q_value
[
j
]
==
1
){
// swap?
std
::
swap
(
x
[
i
],
x
[
k
]);
}
else
{
decode
(
Q_value
[
j
],
c
,
s
);
double
newxk
=
c
*
x
[
k
]
-
s
*
x
[
i
];
x
[
i
]
=
s
*
x
[
k
]
+
c
*
x
[
i
];
x
[
k
]
=
newxk
;
}
}
}
return
QUERN_OK
;
}
int
QUERN_solve_with_r
(
int
n
,
const
int
*
R_row_start
,
const
int
*
R_column_index
,
const
double
*
R_value
,
const
double
*
rhs
,
double
*
result
)
{
// check input
if
(
n
<=
0
||
!
R_row_start
||
!
R_column_index
||
!
R_value
||
!
rhs
||
!
result
)
return
QUERN_INPUT_ERROR
;
// do the solve
double
x
,
rii
;
int
i
,
j
;
for
(
i
=
n
-
1
;
i
>=
0
;
--
i
){
x
=
rhs
[
i
];
rii
=
0
;
j
=
R_row_start
[
i
];
if
(
j
<
R_row_start
[
i
+
1
]
&&
R_column_index
[
j
]
==
i
){
rii
=
R_value
[
j
];
++
j
;
}
if
(
rii
){
for
(;
j
<
R_row_start
[
i
+
1
];
++
j
){
assert
(
R_column_index
[
j
]
>
i
&&
R_column_index
[
j
]
<
n
);
x
-=
R_value
[
j
]
*
result
[
R_column_index
[
j
]];
}
result
[
i
]
=
x
/
rii
;
}
else
result
[
i
]
=
0
;
}
return
QUERN_OK
;
}
int
QUERN_solve_with_r_transpose_in_place
(
int
n
,
const
int
*
R_row_start
,
const
int
*
R_column_index
,
const
double
*
R_value
,
double
*
x
)
{
// check input
if
(
n
<=
0
||
!
R_row_start
||
!
R_column_index
||
!
R_value
||
!
x
)
return
QUERN_INPUT_ERROR
;
// do the solve
double
rii
;
int
i
,
j
;
for
(
i
=
0
;
i
<
n
;
++
i
){
rii
=
0
;
j
=
R_row_start
[
i
];
if
(
j
<
R_row_start
[
i
+
1
]
&&
R_column_index
[
j
]
==
i
){
rii
=
R_value
[
j
];
++
j
;
}
if
(
rii
){
x
[
i
]
/=
rii
;
for
(;
j
<
R_row_start
[
i
+
1
];
++
j
){
assert
(
R_column_index
[
j
]
>
i
&&
R_column_index
[
j
]
<
n
);
x
[
R_column_index
[
j
]]
-=
R_value
[
j
]
*
x
[
i
];
}
}
else
x
[
i
]
=
0
;
}
return
QUERN_OK
;
}
libraries/quern/src/quern_order.cpp
0 → 100644
View file @
6fd7f3bb
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include "quern.h"
int
QUERN_get_rbfs_column_ordering
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
int
*
column_order
)
{
if
(
m
<=
0
||
n
<=
0
||
!
A_row_start
||
!
A_column_index
||
!
column_order
)
return
QUERN_INPUT_ERROR
;
// get some memory to work in
int
*
work
=
(
int
*
)
std
::
malloc
((
n
+
1
+
A_row_start
[
m
]
+
n
+
n
)
*
sizeof
(
int
));
if
(
!
work
)
return
QUERN_OUT_OF_MEMORY
;
// figure out number of entries in each column
int
*
column_start
=
work
;
std
::
memset
(
column_start
,
0
,
(
n
+
1
)
*
sizeof
(
int
));
for
(
int
i
=
0
;
i
<
m
;
++
i
){
for
(
int
j
=
A_row_start
[
i
];
j
<
A_row_start
[
i
+
1
];
++
j
)
++
column_start
[
A_column_index
[
j
]
+
1
];
}
// cumulative sum to get column_start
for
(
int
i
=
0
;
i
<
n
;
++
i
)
column_start
[
i
+
1
]
+=
column_start
[
i
];
assert
(
column_start
[
n
]
==
A_row_start
[
m
]);
// list the columns now
int
*
row_index
=
column_start
+
(
n
+
1
);
int
*
column_pointer
=
row_index
+
column_start
[
n
];
std
::
memcpy
(
column_pointer
,
column_start
,
n
*
sizeof
(
int
));
for
(
int
i
=
0
;
i
<
m
;
++
i
){
for
(
int
j
=
A_row_start
[
i
];
j
<
A_row_start
[
i
+
1
];
++
j
){
int
c
=
A_column_index
[
j
];
row_index
[
column_pointer
[
c
]
++
]
=
i
;
}
}
// set up marker for BFS
char
*
column_marker
=
(
char
*
)(
column_pointer
+
n
);
std
::
memset
(
column_marker
,
0
,
n
);
// and do as many BFS as we need to hit all connected components
int
p
=
n
;
for
(
int
root
=
0
;
root
<
n
;
++
root
)
if
(
!
column_marker
[
root
]){
column_order
[
--
p
]
=
root
;
column_marker
[
root
]
=
1
;
for
(
int
i
=
p
;
i
>=
p
;
--
i
){
int
j
=
column_order
[
i
];
// add unmarked neighbour columns of j to ordering
for
(
int
k
=
column_start
[
j
];
k
<
column_start
[
j
+
1
];
++
k
){
int
r
=
row_index
[
k
];
for
(
int
a
=
A_row_start
[
r
];
a
<
A_row_start
[
r
+
1
];
++
a
){
int
nbr
=
A_column_index
[
a
];
if
(
!
column_marker
[
nbr
]){
column_order
[
--
p
]
=
nbr
;
column_marker
[
nbr
]
=
1
;
}
}
}
}
}
assert
(
p
==
0
);
std
::
free
(
work
);
return
QUERN_OK
;
}
int
QUERN_reorder_columns
(
int
m
,
int
n
,
const
int
*
column_order
,
const
int
*
A_row_start
,
int
*
A_column_index
,
double
*
A_value
)
{
if
(
m
<=
0
||
n
<=
0
||
!
column_order
||
!
A_row_start
||
!
A_column_index
||
!
A_value
)
return
QUERN_INPUT_ERROR
;
// Since we don't expect to have lots of empty columns, it would
// probably be superior to do this as two transposes --- but we'll
// worry about that optimization later.
// get some temporary storage for permuting and sorting
std
::
pair
<
int
,
double
>*
row
=
(
std
::
pair
<
int
,
double
>*
)
std
::
malloc
(
n
*
sizeof
(
std
::
pair
<
int
,
double
>
));
if
(
!
row
)
return
QUERN_OUT_OF_MEMORY
;
// and invert the permutation
int
*
inv
=
(
int
*
)
std
::
malloc
(
n
*
sizeof
(
int
));
if
(
!
inv
){
std
::
free
(
row
);
return
QUERN_OUT_OF_MEMORY
;
}
for
(
int
i
=
0
;
i
<
n
;
++
i
)
inv
[
column_order
[
i
]]
=
i
;
// do it row by row
int
k
;
for
(
int
i
=
0
;
i
<
m
;
++
i
){
k
=
0
;
for
(
int
j
=
A_row_start
[
i
];
j
<
A_row_start
[
i
+
1
];
++
j
)
row
[
k
++
]
=
std
::
make_pair
(
inv
[
A_column_index
[
j
]],
A_value
[
j
]);
std
::
sort
(
row
,
row
+
k
);
// at some point should replace with radix-sort
k
=
0
;
for
(
int
j
=
A_row_start
[
i
];
j
<
A_row_start
[
i
+
1
];
++
j
){
A_column_index
[
j
]
=
row
[
k
].
first
;
A_value
[
j
]
=
row
[
k
].
second
;
++
k
;
}
}
std
::
free
(
row
);
std
::
free
(
inv
);
return
QUERN_OK
;
}
int
QUERN_get_profile_row_ordering
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
int
*
row_order
)
{
if
(
m
<=
0
||
n
<=
0
||
!
A_row_start
||
!
A_column_index
||
!
row_order
)
return
QUERN_INPUT_ERROR
;
// first count how many rows start at column i for each i=0, .., n-1
int
*
count
=
(
int
*
)
std
::
calloc
(
n
+
1
,
sizeof
(
int
));
if
(
!
count
)
return
QUERN_OUT_OF_MEMORY
;
for
(
int
i
=
0
;
i
<
m
;
++
i
)
if
(
A_row_start
[
i
]
<
A_row_start
[
i
+
1
])
++
count
[
A_column_index
[
A_row_start
[
i
]]
+
1
];
// then do a cumulative sum to find target locations of the rows
for
(
int
j
=
2
;
j
<
n
+
1
;
++
j
)
count
[
j
]
+=
count
[
j
-
1
];
// and now write out the row ordering with a second pass
for
(
int
i
=
0
;
i
<
m
;
++
i
){
if
(
A_row_start
[
i
]
<
A_row_start
[
i
+
1
])
row_order
[
count
[
A_column_index
[
A_row_start
[
i
]]]
++
]
=
i
;
else
row_order
[
count
[
n
]
++
]
=
i
;
}
std
::
free
(
count
);
return
QUERN_OK
;
}
// Reorders a given input vector x into an output vector y of length m.
int
QUERN_reorder_vector
(
int
m
,
const
int
*
order
,
const
double
*
x
,
double
*
y
)
{
if
(
m
<=
0
||
!
order
||
!
x
||
!
y
)
return
QUERN_INPUT_ERROR
;
for
(
int
i
=
0
;
i
<
m
;
++
i
)
y
[
i
]
=
x
[
order
[
i
]];
return
QUERN_OK
;
}
// Applies the inverse order to a given input vector x, saving in an output
// vector y of length m.
int
QUERN_inverse_order_vector
(
int
m
,
const
int
*
order
,
const
double
*
x
,
double
*
y
)
{
if
(
m
<=
0
||
!
order
||
!
x
||
!
y
)
return
QUERN_INPUT_ERROR
;
for
(
int
i
=
0
;
i
<
m
;
++
i
)
y
[
order
[
i
]]
=
x
[
i
];
return
QUERN_OK
;
}
libraries/quern/src/quern_solver.cpp
0 → 100644
View file @
6fd7f3bb
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "quern.h"
// TO-DO: use BLAS versions of these smaller kernels, if available
double
two_norm
(
int
n
,
const
double
*
x
)
{
double
r
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
)
r
+=
x
[
i
]
*
x
[
i
];
return
std
::
sqrt
(
r
);
}
double
two_norm_squared
(
int
n
,
const
double
*
x
)
{
double
r
=
0
;
for
(
int
i
=
0
;
i
<
n
;
++
i
)
r
+=
x
[
i
]
*
x
[
i
];
return
r
;
}
// x=x+alpha*y
void
add_scaled
(
int
n
,
double
*
x
,
double
alpha
,
const
double
*
y
)
{
for
(
int
i
=
0
;
i
<
n
;
++
i
)
x
[
i
]
+=
alpha
*
y
[
i
];
}
// x=beta*x+y
void
scale_and_add
(
int
n
,
double
beta
,
double
*
x
,
const
double
*
y
)
{
for
(
int
i
=
0
;
i
<
n
;
++
i
)
x
[
i
]
=
beta
*
x
[
i
]
+
y
[
i
];
}
int
QUERN_solve_with_CGNR
(
int
m
,
int
n
,
const
int
*
A_row_start
,
const
int
*
A_column_index
,
const
double
*
A_value
,
const
double
*
rhs
,
const
int
*
R_row_start
,
const
int
*
R_column_index
,
const
double
*
R_value
,
int
max_iterations
,
double
absolute_convergence_tolerance
,
double
*
x
,
int
*
return_solved
,
int
*
return_iterations
,
double
*
return_residual_norm
)
{
if
(
m
<=
0
||
n
<=
0
||
!
A_row_start
||
!
A_column_index
||
!
A_value
||
!
rhs
||
!
R_row_start
||
!
R_column_index
||
!
R_value
||
!
x
||
!
return_solved
||
!
return_iterations
||
!
return_residual_norm
)
return
QUERN_INPUT_ERROR
;
// default values
*
return_solved
=
0
;
*
return_iterations
=
0
;
*
return_residual_norm
=
two_norm
(
n
,
rhs
);
if
(
*
return_residual_norm
<=
absolute_convergence_tolerance
){
*
return_solved
=
1
;
return
QUERN_OK
;
}
// allocate some room to work in
double
*
working_vectors
=
(
double
*
)
std
::
malloc
((
3
*
n
+
m
)
*
sizeof
(
double
));
if
(
!
working_vectors
)
return
QUERN_OUT_OF_MEMORY
;
double
*
r
=
working_vectors
;
double
*
s
=
r
+
n
;
double
*
z
=
s
+
n
;
double
*
u
=
z
+
n
;
// set up CGNR
int
check
;
std
::
memset
(
x
,
0
,
n
*
sizeof
(
double
));
std
::
memcpy
(
r
,
rhs
,
n
*
sizeof
(
double
));
std
::
memcpy
(
u
,
rhs
,
n
*
sizeof
(
double
));
check
=
QUERN_solve_with_r_transpose_in_place
(
n
,
R_row_start
,
R_column_index
,
R_value
,
u
);
if
(
check
){
std
::
free
(
working_vectors
);
return
check
;
}
check
=
QUERN_solve_with_r
(
n
,
R_row_start
,
R_column_index
,
R_value
,
u
,
z
);
if
(
check
){
std
::
free
(
working_vectors
);
return
check
;
}
std
::
memcpy
(
s
,
z
,
n
*
sizeof
(
double
));
double
rho
=
two_norm_squared
(
n
,
u
);
// the main loop
for
(;;){
if
(
rho
==
0
){
std
::
free
(
working_vectors
);
return
QUERN_INPUT_ERROR
;
}
check
=
QUERN_multiply
(
m
,
n
,
A_row_start
,
A_column_index
,
A_value
,
s
,
u
);
if
(
check
){
std
::
free
(
working_vectors
);
return
check
;
}
check
=
QUERN_multiply_transpose
(
m
,
n
,
A_row_start
,
A_column_index
,
A_value
,
u
,
z
);
if
(
check
){
std
::
free
(
working_vectors
);
return
check
;
}
double
denom
=
two_norm_squared
(
m
,
u
);
if
(
denom
==
0
){
std
::
free
(
working_vectors
);
return
QUERN_INPUT_ERROR
;
}
double
alpha
=
rho
/
denom
;
add_scaled
(
n
,
x
,
alpha
,
s
);
add_scaled
(
n
,
r
,
-
alpha
,
z
);
++*
return_iterations
;
*
return_residual_norm
=
two_norm
(
n
,
r
);
if
(
*
return_residual_norm
<=
absolute_convergence_tolerance
){
*
return_solved
=
1
;
break
;
}
if
(
*
return_iterations
>
max_iterations
)
break
;
std
::
memcpy
(
u
,
r
,
n
*
sizeof
(
double
));
check
=
QUERN_solve_with_r_transpose_in_place
(
n
,
R_row_start
,
R_column_index
,
R_value
,
u
);
if
(
check
){
std
::
free
(
working_vectors
);
return
check
;
}
check
=
QUERN_solve_with_r
(
n
,
R_row_start
,
R_column_index
,
R_value
,
u
,
z
);
if
(
check
){
std
::
free
(
working_vectors
);
return
check
;
}
double
rho_new
=
two_norm_squared
(
n
,
u
);
double
beta
=
rho_new
/
rho
;
scale_and_add
(
n
,
beta
,
s
,
z
);
rho
=
rho_new
;
}
std
::
free
(
working_vectors
);
return
QUERN_OK
;
}
platforms/reference/src/ReferenceKernels.cpp
View file @
6fd7f3bb
...
...
@@ -58,21 +58,21 @@
using
namespace
OpenMM
;
using
namespace
std
;
int
**
allocateIntArray
(
int
length
,
int
width
)
{
static
int
**
allocateIntArray
(
int
length
,
int
width
)
{
int
**
array
=
new
int
*
[
length
];
for
(
int
i
=
0
;
i
<
length
;
++
i
)
array
[
i
]
=
new
int
[
width
];
return
array
;
}
RealOpenMM
**
allocateRealArray
(
int
length
,
int
width
)
{
static
RealOpenMM
**
allocateRealArray
(
int
length
,
int
width
)
{
RealOpenMM
**
array
=
new
RealOpenMM
*
[
length
];
for
(
int
i
=
0
;
i
<
length
;
++
i
)
array
[
i
]
=
new
RealOpenMM
[
width
];
return
array
;
}
int
**
copyToArray
(
const
vector
<
vector
<
int
>
>
vec
)
{
static
int
**
copyToArray
(
const
vector
<
vector
<
int
>
>
vec
)
{
if
(
vec
.
size
()
==
0
)
return
new
int
*
[
0
];
int
**
array
=
allocateIntArray
(
vec
.
size
(),
vec
[
0
].
size
());
...
...
@@ -82,7 +82,7 @@ int** copyToArray(const vector<vector<int> > vec) {
return
array
;
}
RealOpenMM
**
copyToArray
(
const
vector
<
vector
<
double
>
>
vec
)
{
static
RealOpenMM
**
copyToArray
(
const
vector
<
vector
<
double
>
>
vec
)
{
if
(
vec
.
size
()
==
0
)
return
new
RealOpenMM
*
[
0
];
RealOpenMM
**
array
=
allocateRealArray
(
vec
.
size
(),
vec
[
0
].
size
());
...
...
@@ -92,7 +92,7 @@ RealOpenMM** copyToArray(const vector<vector<double> > vec) {
return
array
;
}
void
disposeIntArray
(
int
**
array
,
int
size
)
{
static
void
disposeIntArray
(
int
**
array
,
int
size
)
{
if
(
array
)
{
for
(
int
i
=
0
;
i
<
size
;
++
i
)
delete
[]
array
[
i
];
...
...
@@ -100,7 +100,7 @@ void disposeIntArray(int** array, int size) {
}
}
void
disposeRealArray
(
RealOpenMM
**
array
,
int
size
)
{
static
void
disposeRealArray
(
RealOpenMM
**
array
,
int
size
)
{
if
(
array
)
{
for
(
int
i
=
0
;
i
<
size
;
++
i
)
delete
[]
array
[
i
];
...
...
@@ -108,6 +108,20 @@ void disposeRealArray(RealOpenMM** array, int size) {
}
}
static
void
findAnglesForShake
(
const
System
&
system
,
vector
<
ReferenceRigidShakeAlgorithm
::
AngleInfo
>&
angles
)
{
for
(
int
i
=
0
;
i
<
system
.
getNumForces
();
i
++
)
{
const
HarmonicAngleForce
*
force
=
dynamic_cast
<
const
HarmonicAngleForce
*>
(
&
system
.
getForce
(
i
));
if
(
force
!=
NULL
)
{
for
(
int
j
=
0
;
j
<
force
->
getNumAngles
();
j
++
)
{
int
atom1
,
atom2
,
atom3
;
double
angle
,
k
;
force
->
getAngleParameters
(
j
,
atom1
,
atom2
,
atom3
,
angle
,
k
);
angles
.
push_back
(
ReferenceRigidShakeAlgorithm
::
AngleInfo
(
atom1
,
atom2
,
atom3
,
angle
));
}
}
}
}
void
ReferenceInitializeForcesKernel
::
initialize
(
const
System
&
system
)
{
}
...
...
@@ -609,7 +623,9 @@ void ReferenceIntegrateVerletStepKernel::execute(OpenMMContextImpl& context, con
delete
constraints
;
}
dynamics
=
new
ReferenceVerletDynamics
(
context
.
getSystem
().
getNumParticles
(),
static_cast
<
RealOpenMM
>
(
stepSize
)
);
constraints
=
new
ReferenceRigidShakeAlgorithm
(
context
.
getSystem
().
getNumParticles
(),
numConstraints
,
constraintIndices
,
constraintDistances
,
masses
,
(
RealOpenMM
)
integrator
.
getConstraintTolerance
());
vector
<
ReferenceRigidShakeAlgorithm
::
AngleInfo
>
angles
;
findAnglesForShake
(
context
.
getSystem
(),
angles
);
constraints
=
new
ReferenceRigidShakeAlgorithm
(
context
.
getSystem
().
getNumParticles
(),
numConstraints
,
constraintIndices
,
constraintDistances
,
masses
,
angles
,
(
RealOpenMM
)
integrator
.
getConstraintTolerance
());
dynamics
->
setReferenceConstraintAlgorithm
(
constraints
);
prevStepSize
=
stepSize
;
}
...
...
@@ -668,7 +684,9 @@ void ReferenceIntegrateLangevinStepKernel::execute(OpenMMContextImpl& context, c
static_cast
<
RealOpenMM
>
(
stepSize
),
static_cast
<
RealOpenMM
>
(
tau
),
static_cast
<
RealOpenMM
>
(
temperature
)
);
constraints
=
new
ReferenceRigidShakeAlgorithm
(
context
.
getSystem
().
getNumParticles
(),
numConstraints
,
constraintIndices
,
constraintDistances
,
masses
,
(
RealOpenMM
)
integrator
.
getConstraintTolerance
());
vector
<
ReferenceRigidShakeAlgorithm
::
AngleInfo
>
angles
;
findAnglesForShake
(
context
.
getSystem
(),
angles
);
constraints
=
new
ReferenceRigidShakeAlgorithm
(
context
.
getSystem
().
getNumParticles
(),
numConstraints
,
constraintIndices
,
constraintDistances
,
masses
,
angles
,
(
RealOpenMM
)
integrator
.
getConstraintTolerance
());
dynamics
->
setReferenceConstraintAlgorithm
(
constraints
);
prevTemp
=
temperature
;
prevFriction
=
friction
;
...
...
@@ -728,7 +746,9 @@ void ReferenceIntegrateBrownianStepKernel::execute(OpenMMContextImpl& context, c
static_cast
<
RealOpenMM
>
(
stepSize
),
static_cast
<
RealOpenMM
>
(
friction
),
static_cast
<
RealOpenMM
>
(
temperature
)
);
constraints
=
new
ReferenceRigidShakeAlgorithm
(
context
.
getSystem
().
getNumParticles
(),
numConstraints
,
constraintIndices
,
constraintDistances
,
masses
,
(
RealOpenMM
)
integrator
.
getConstraintTolerance
());
vector
<
ReferenceRigidShakeAlgorithm
::
AngleInfo
>
angles
;
findAnglesForShake
(
context
.
getSystem
(),
angles
);
constraints
=
new
ReferenceRigidShakeAlgorithm
(
context
.
getSystem
().
getNumParticles
(),
numConstraints
,
constraintIndices
,
constraintDistances
,
masses
,
angles
,
(
RealOpenMM
)
integrator
.
getConstraintTolerance
());
dynamics
->
setReferenceConstraintAlgorithm
(
constraints
);
prevTemp
=
temperature
;
prevFriction
=
friction
;
...
...
platforms/reference/src/SimTKReference/ReferenceRigidShakeAlgorithm.cpp
View file @
6fd7f3bb
...
...
@@ -31,10 +31,12 @@
#include "ReferenceRigidShakeAlgorithm.h"
#include "ReferenceDynamics.h"
#include "jama_svd.h"
#include "quern.h"
#include "openmm/Vec3.h"
#include <map>
using
std
::
map
;
using
std
::
pair
;
using
std
::
vector
;
using
std
::
set
;
using
OpenMM
::
Vec3
;
...
...
@@ -58,6 +60,7 @@ ReferenceRigidShakeAlgorithm::ReferenceRigidShakeAlgorithm( int numberOfAtoms,
int
**
atomIndices
,
RealOpenMM
*
distance
,
RealOpenMM
*
masses
,
vector
<
AngleInfo
>&
angles
,
RealOpenMM
tolerance
){
// ---------------------------------------------------------------------------------------
...
...
@@ -92,156 +95,274 @@ ReferenceRigidShakeAlgorithm::ReferenceRigidShakeAlgorithm( int numberOfAtoms,
_distanceTolerance
=
SimTKOpenMMUtilities
::
allocateOneDRealOpenMMArray
(
numberOfConstraints
,
NULL
,
1
,
zero
,
"distanceTolerance"
);
_reducedMasses
=
SimTKOpenMMUtilities
::
allocateOneDRealOpenMMArray
(
numberOfConstraints
,
NULL
,
1
,
zero
,
"reducedMasses"
);
}
// Identify rigid clusters.
vector
<
map
<
int
,
int
>
>
atomConstraints
(
numberOfAtoms
);
for
(
int
i
=
0
;
i
<
numberOfConstraints
;
i
++
)
{
atomConstraints
[
atomIndices
[
i
][
0
]][
atomIndices
[
i
][
1
]]
=
i
;
atomConstraints
[
atomIndices
[
i
][
1
]][
atomIndices
[
i
][
0
]]
=
i
;
}
for
(
int
i
=
0
;
i
<
numberOfAtoms
;
i
++
)
{
if
(
atomConstraints
[
i
].
size
()
<
2
)
continue
;
// Begin by looking for a triangle this atom is part of.
set
<
int
>
atoms
;
atoms
.
insert
(
i
);
for
(
map
<
int
,
int
>::
const_iterator
atom1
=
atomConstraints
[
i
].
begin
();
atom1
!=
atomConstraints
[
i
].
end
()
&&
atoms
.
size
()
==
1
;
++
atom1
)
{
for
(
map
<
int
,
int
>::
const_iterator
atom2
=
atomConstraints
[
atom1
->
first
].
begin
();
atom2
!=
atomConstraints
[
atom1
->
first
].
end
();
++
atom2
)
{
if
(
atomConstraints
[
i
].
count
(
atom2
->
first
)
!=
0
)
{
atoms
.
insert
(
atom1
->
first
);
atoms
.
insert
(
atom2
->
first
);
break
;
}
}
}
if
(
atoms
.
size
()
==
1
)
continue
;
// We have three atoms that are part of a cluster, so look for other atoms we can add.
bool
done
=
false
;
while
(
!
done
)
{
done
=
true
;
for
(
set
<
int
>::
const_iterator
atom1
=
atoms
.
begin
();
atom1
!=
atoms
.
end
();
++
atom1
)
{
for
(
map
<
int
,
int
>::
const_iterator
atom2
=
atomConstraints
[
*
atom1
].
begin
();
atom2
!=
atomConstraints
[
*
atom1
].
end
();
++
atom2
)
{
if
(
atoms
.
find
(
atom2
->
first
)
!=
atoms
.
end
())
continue
;
// This atom is already in the cluster.
// See if this atom is linked to three other atoms in the cluster.
int
linkCount
=
0
;
for
(
map
<
int
,
int
>::
const_iterator
atom3
=
atomConstraints
[
atom2
->
first
].
begin
();
atom3
!=
atomConstraints
[
atom2
->
first
].
end
();
++
atom3
)
if
(
atoms
.
find
(
atom3
->
first
)
!=
atoms
.
end
())
linkCount
++
;
if
(
linkCount
>
2
)
{
atoms
.
insert
(
atom2
->
first
);
done
=
false
;
}
if
(
numberOfConstraints
>
0
)
{
// Compute the constraint coupling matrix
vector
<
vector
<
int
>
>
atomAngles
(
numberOfAtoms
);
for
(
int
i
=
0
;
i
<
(
int
)
angles
.
size
();
i
++
)
atomAngles
[
angles
[
i
].
atom2
].
push_back
(
i
);
vector
<
vector
<
pair
<
int
,
double
>
>
>
matrix
(
numberOfConstraints
);
for
(
int
j
=
0
;
j
<
numberOfConstraints
;
j
++
)
{
for
(
int
k
=
0
;
k
<
numberOfConstraints
;
k
++
)
{
if
(
j
==
k
)
{
matrix
[
j
].
push_back
(
pair
<
int
,
double
>
(
j
,
1.0
));
continue
;
}
}
}
// Record the cluster.
vector
<
int
>
constraints
;
for
(
set
<
int
>::
const_iterator
atom1
=
atoms
.
begin
();
atom1
!=
atoms
.
end
();
++
atom1
)
{
for
(
map
<
int
,
int
>::
const_iterator
atom2
=
atomConstraints
[
*
atom1
].
begin
();
atom2
!=
atomConstraints
[
*
atom1
].
end
();
++
atom2
)
{
if
(
*
atom1
<
atom2
->
first
&&
atoms
.
find
(
atom2
->
first
)
!=
atoms
.
end
())
constraints
.
push_back
(
atom2
->
second
);
}
}
_rigidClusters
.
push_back
(
constraints
);
for
(
set
<
int
>::
const_iterator
atom1
=
atoms
.
begin
();
atom1
!=
atoms
.
end
();
++
atom1
)
{
for
(
map
<
int
,
int
>::
const_iterator
atom2
=
atomConstraints
[
*
atom1
].
begin
();
atom2
!=
atomConstraints
[
*
atom1
].
end
();
++
atom2
)
atomConstraints
[
atom2
->
first
].
erase
(
*
atom1
);
atomConstraints
[
*
atom1
].
clear
();
}
// Compute the constraint coupling matrix for this cluster.
const
vector
<
int
>&
cluster
=
_rigidClusters
[
i
];
unsigned
int
size
=
cluster
.
size
();
Array2D
<
double
>
matrix
(
size
,
size
);
for
(
int
j
=
0
;
j
<
(
int
)
size
;
j
++
)
{
for
(
int
k
=
0
;
k
<
(
int
)
size
;
k
++
)
{
double
scale
;
int
atomj0
=
_atomIndices
[
cluster
[
j
]
][
0
];
int
atomj1
=
_atomIndices
[
cluster
[
j
]
][
1
];
int
atomk0
=
_atomIndices
[
cluster
[
k
]
][
0
];
int
atomk1
=
_atomIndices
[
cluster
[
k
]
][
1
];
int
atomj0
=
_atomIndices
[
j
][
0
];
int
atomj1
=
_atomIndices
[
j
][
1
];
int
atomk0
=
_atomIndices
[
k
][
0
];
int
atomk1
=
_atomIndices
[
k
][
1
];
RealOpenMM
invMass0
=
one
/
masses
[
atomj0
];
RealOpenMM
invMass1
=
one
/
masses
[
atomj1
];
int
atoma
,
atomb
;
int
atoma
,
atomb
,
atomc
;
if
(
atomj0
==
atomk0
)
{
atoma
=
atomj1
;
atomb
=
atomk1
;
atomb
=
atomj0
;
atomc
=
atomk1
;
scale
=
invMass0
/
(
invMass0
+
invMass1
);
}
else
if
(
atomj1
==
atomk1
)
{
atoma
=
atomj0
;
atomb
=
atomk0
;
atomb
=
atomj1
;
atomc
=
atomk0
;
scale
=
invMass1
/
(
invMass0
+
invMass1
);
}
else
if
(
atomj0
==
atomk1
)
{
atoma
=
atomj1
;
atomb
=
atomk0
;
atomb
=
atomj0
;
atomc
=
atomk0
;
scale
=
invMass0
/
(
invMass0
+
invMass1
);
}
else
if
(
atomj1
==
atomk0
)
{
atoma
=
atomj0
;
atomb
=
atomk1
;
atomb
=
atomj1
;
atomc
=
atomk1
;
scale
=
invMass1
/
(
invMass0
+
invMass1
);
}
else
{
matrix
[
j
][
k
]
=
0.0
;
else
continue
;
// These constraints are not connected.
}
//
Find the
third constraint forming a triangle with these two.
//
Look for a
third constraint forming a triangle with these two.
for
(
int
m
=
0
;
m
<
size
;
m
++
)
{
int
other
=
cluster
[
m
];
if
((
_atomIndices
[
other
][
0
]
==
atoma
&&
_atomIndices
[
other
][
1
]
==
atom
b
)
||
(
_atomIndices
[
other
][
0
]
==
atom
b
&&
_atomIndices
[
other
][
1
]
==
atoma
))
{
double
d1
=
_distance
[
cluster
[
j
]
];
double
d2
=
_distance
[
cluster
[
k
]
];
bool
foundConstraint
=
false
;
for
(
int
other
=
0
;
other
<
numberOfConstraints
;
other
++
)
{
if
((
_atomIndices
[
other
][
0
]
==
atoma
&&
_atomIndices
[
other
][
1
]
==
atom
c
)
||
(
_atomIndices
[
other
][
0
]
==
atom
c
&&
_atomIndices
[
other
][
1
]
==
atoma
))
{
double
d1
=
_distance
[
j
];
double
d2
=
_distance
[
k
];
double
d3
=
_distance
[
other
];
matrix
[
j
][
k
]
=
scale
*
(
d1
*
d1
+
d2
*
d2
-
d3
*
d3
)
/
(
2.0
*
d1
*
d2
);
matrix
[
j
].
push_back
(
pair
<
int
,
double
>
(
k
,
scale
*
(
d1
*
d1
+
d2
*
d2
-
d3
*
d3
)
/
(
2.0
*
d1
*
d2
)));
foundConstraint
=
true
;
break
;
}
}
if
(
!
foundConstraint
)
{
// We didn't find one, so look for an angle force field term.
const
vector
<
int
>&
angleCandidates
=
atomAngles
[
atomb
];
for
(
vector
<
int
>::
const_iterator
iter
=
angleCandidates
.
begin
();
iter
!=
angleCandidates
.
end
();
iter
++
)
{
const
AngleInfo
&
angle
=
angles
[
*
iter
];
if
((
angle
.
atom1
==
atoma
&&
angle
.
atom3
==
atomc
)
||
(
angle
.
atom3
==
atoma
&&
angle
.
atom1
==
atomc
))
{
matrix
[
j
].
push_back
(
pair
<
int
,
double
>
(
k
,
scale
*
cos
(
angle
.
angle
)));
break
;
}
}
}
}
matrix
[
j
][
j
]
=
1.0
;
}
// Invert it using SVD.
Array2D
<
double
>
u
,
v
;
Array1D
<
double
>
w
;
SVD
<
double
>
svd
(
matrix
);
svd
.
getU
(
u
);
svd
.
getV
(
v
);
svd
.
getSingularValues
(
w
);
double
singularValueCutoff
=
0.01
*
w
[
0
];
for
(
int
j
=
0
;
j
<
(
int
)
size
;
j
++
)
w
[
j
]
=
(
w
[
j
]
<
singularValueCutoff
?
0.0
:
1.0
/
w
[
j
]);
for
(
int
j
=
0
;
j
<
(
int
)
size
;
j
++
)
{
for
(
int
k
=
0
;
k
<
(
int
)
size
;
k
++
)
{
matrix
[
j
][
k
]
=
0.0
;
for
(
int
m
=
0
;
m
<
(
int
)
size
;
m
++
)
matrix
[
j
][
k
]
+=
v
[
j
][
m
]
*
w
[
m
]
*
u
[
k
][
m
];
// Invert it using QR.
vector
<
int
>
matrixRowStart
;
vector
<
int
>
matrixColIndex
;
vector
<
double
>
matrixValue
;
for
(
int
i
=
0
;
i
<
numberOfConstraints
;
i
++
)
{
matrixRowStart
.
push_back
(
matrixValue
.
size
());
for
(
int
j
=
0
;
j
<
(
int
)
matrix
[
i
].
size
();
j
++
)
{
pair
<
int
,
double
>
element
=
matrix
[
i
][
j
];
matrixColIndex
.
push_back
(
element
.
first
);
matrixValue
.
push_back
(
element
.
second
);
}
}
matrixRowStart
.
push_back
(
matrixValue
.
size
());
int
*
qRowStart
,
*
qColIndex
,
*
rRowStart
,
*
rColIndex
;
double
*
qValue
,
*
rValue
;
QUERN_compute_qr
(
numberOfConstraints
,
numberOfConstraints
,
&
matrixRowStart
[
0
],
&
matrixColIndex
[
0
],
&
matrixValue
[
0
],
NULL
,
&
qRowStart
,
&
qColIndex
,
&
qValue
,
&
rRowStart
,
&
rColIndex
,
&
rValue
);
vector
<
double
>
rhs
(
numberOfConstraints
);
_matrix
.
resize
(
numberOfConstraints
);
for
(
int
i
=
0
;
i
<
numberOfConstraints
;
i
++
)
{
// Extract column i of the inverse matrix.
for
(
int
j
=
0
;
j
<
numberOfConstraints
;
j
++
)
rhs
[
j
]
=
(
i
==
j
?
1.0
:
0.0
);
QUERN_multiply_with_q_transpose
(
numberOfConstraints
,
qRowStart
,
qColIndex
,
qValue
,
&
rhs
[
0
]);
QUERN_solve_with_r
(
numberOfConstraints
,
rRowStart
,
rColIndex
,
rValue
,
&
rhs
[
0
],
&
rhs
[
0
]);
for
(
int
j
=
0
;
j
<
numberOfConstraints
;
j
++
)
{
double
value
=
rhs
[
j
]
*
_distance
[
i
]
/
_distance
[
j
];
if
(
abs
(
value
)
>
0.01
)
_matrix
[
j
].
push_back
(
pair
<
int
,
RealOpenMM
>
(
i
,
(
RealOpenMM
)
value
));
}
}
QUERN_free_result
(
qRowStart
,
qColIndex
,
qValue
);
QUERN_free_result
(
rRowStart
,
rColIndex
,
rValue
);
}
// Record the inverted matrix.
_matrices
.
push_back
(
SimTKOpenMMUtilities
::
allocateTwoDRealOpenMMArray
(
constraints
.
size
(),
constraints
.
size
(),
NULL
,
false
,
0.0
,
""
));
for
(
int
j
=
0
;
j
<
(
int
)
size
;
j
++
)
for
(
int
k
=
0
;
k
<
(
int
)
size
;
k
++
)
_matrices
[
i
][
j
][
k
]
=
(
RealOpenMM
)
matrix
[
j
][
k
]
*
_distance
[
cluster
[
k
]]
/
_distance
[
cluster
[
j
]];
}
// // Identify rigid clusters.
//
// vector<map<int, int> > atomConstraints(numberOfAtoms);
// for (int i = 0; i < numberOfConstraints; i++) {
// atomConstraints[atomIndices[i][0]][atomIndices[i][1]] = i;
// atomConstraints[atomIndices[i][1]][atomIndices[i][0]] = i;
// }
// for (int i = 0; i < numberOfAtoms; i++) {
// if (atomConstraints[i].size() < 2)
// continue;
//
// // Begin by looking for a triangle this atom is part of.
//
// set<int> atoms;
// atoms.insert(i);
// for (map<int, int>::const_iterator atom1 = atomConstraints[i].begin(); atom1 != atomConstraints[i].end() && atoms.size() == 1; ++atom1) {
// for (map<int, int>::const_iterator atom2 = atomConstraints[atom1->first].begin(); atom2 != atomConstraints[atom1->first].end(); ++atom2) {
// if (atomConstraints[i].count(atom2->first) != 0) {
// atoms.insert(atom1->first);
// atoms.insert(atom2->first);
// break;
// }
// }
// }
// if (atoms.size() == 1)
// continue;
//
// // We have three atoms that are part of a cluster, so look for other atoms we can add.
//
// bool done = false;
// while (!done) {
// done = true;
// for (set<int>::const_iterator atom1 = atoms.begin(); atom1 != atoms.end(); ++atom1) {
// for (map<int, int>::const_iterator atom2 = atomConstraints[*atom1].begin(); atom2 != atomConstraints[*atom1].end(); ++atom2) {
// if (atoms.find(atom2->first) != atoms.end())
// continue; // This atom is already in the cluster.
//
// // See if this atom is linked to three other atoms in the cluster.
//
// int linkCount = 0;
// for (map<int, int>::const_iterator atom3 = atomConstraints[atom2->first].begin(); atom3 != atomConstraints[atom2->first].end(); ++atom3)
// if (atoms.find(atom3->first) != atoms.end())
// linkCount++;
// if (linkCount > 2) {
// atoms.insert(atom2->first);
// done = false;
// }
// }
// }
// }
//
// // Record the cluster.
//
// vector<int> constraints;
// for (set<int>::const_iterator atom1 = atoms.begin(); atom1 != atoms.end(); ++atom1) {
// for (map<int, int>::const_iterator atom2 = atomConstraints[*atom1].begin(); atom2 != atomConstraints[*atom1].end(); ++atom2) {
// if (*atom1 < atom2->first && atoms.find(atom2->first) != atoms.end())
// constraints.push_back(atom2->second);
// }
// }
// _rigidClusters.push_back(constraints);
// for (set<int>::const_iterator atom1 = atoms.begin(); atom1 != atoms.end(); ++atom1) {
// for (map<int, int>::const_iterator atom2 = atomConstraints[*atom1].begin(); atom2 != atomConstraints[*atom1].end(); ++atom2)
// atomConstraints[atom2->first].erase(*atom1);
// atomConstraints[*atom1].clear();
// }
//
// // Compute the constraint coupling matrix for this cluster.
//
// const vector<int>& cluster = _rigidClusters[i];
// unsigned int size = cluster.size();
// Array2D<double> matrix(size, size);
// for (int j = 0; j < (int)size; j++) {
// for (int k = 0; k < (int)size; k++) {
// double scale;
// int atomj0 = _atomIndices[cluster[j]][0];
// int atomj1 = _atomIndices[cluster[j]][1];
// int atomk0 = _atomIndices[cluster[k]][0];
// int atomk1 = _atomIndices[cluster[k]][1];
// RealOpenMM invMass0 = one/masses[atomj0];
// RealOpenMM invMass1 = one/masses[atomj1];
// int atoma, atomb;
// if (atomj0 == atomk0) {
// atoma = atomj1;
// atomb = atomk1;
// scale = invMass0/(invMass0+invMass1);
// }
// else if (atomj1 == atomk1) {
// atoma = atomj0;
// atomb = atomk0;
// scale = invMass1/(invMass0+invMass1);
// }
// else if (atomj0 == atomk1) {
// atoma = atomj1;
// atomb = atomk0;
// scale = invMass0/(invMass0+invMass1);
// }
// else if (atomj1 == atomk0) {
// atoma = atomj0;
// atomb = atomk1;
// scale = invMass1/(invMass0+invMass1);
// }
// else {
// matrix[j][k] = 0.0;
// continue; // These constraints are not connected.
// }
//
// // Find the third constraint forming a triangle with these two.
//
// for (int m = 0; m < size; m++) {
// int other = cluster[m];
// if ((_atomIndices[other][0] == atoma && _atomIndices[other][1] == atomb) || (_atomIndices[other][0] == atomb && _atomIndices[other][1] == atoma)) {
// double d1 = _distance[cluster[j]];
// double d2 = _distance[cluster[k]];
// double d3 = _distance[other];
// matrix[j][k] = scale*(d1*d1+d2*d2-d3*d3)/(2.0*d1*d2);
// break;
// }
// }
// }
// matrix[j][j] = 1.0;
// }
//
// // Invert it using SVD.
//
// Array2D<double> u, v;
// Array1D<double> w;
// SVD<double> svd(matrix);
// svd.getU(u);
// svd.getV(v);
// svd.getSingularValues(w);
// double singularValueCutoff = 0.01*w[0];
// for (int j = 0; j < (int)size; j++)
// w[j] = (w[j] < singularValueCutoff ? 0.0 : 1.0/w[j]);
// for (int j = 0; j < (int)size; j++) {
// for (int k = 0; k < (int)size; k++) {
// matrix[j][k] = 0.0;
// for (int m = 0; m < (int)size; m++)
// matrix[j][k] += v[j][m]*w[m]*u[k][m];
// }
// }
//
// // Record the inverted matrix.
//
// _matrices.push_back(SimTKOpenMMUtilities::allocateTwoDRealOpenMMArray(constraints.size(), constraints.size(), NULL, false, 0.0, ""));
// for (int j = 0; j < (int)size; j++)
// for (int k = 0; k < (int)size; k++)
// _matrices[i][j][k] = (RealOpenMM)matrix[j][k]*_distance[cluster[k]]/_distance[cluster[j]];
// }
}
/**---------------------------------------------------------------------------------------
...
...
@@ -265,8 +386,8 @@ ReferenceRigidShakeAlgorithm::~ReferenceRigidShakeAlgorithm( ){
SimTKOpenMMUtilities
::
freeOneDRealOpenMMArray
(
_distanceTolerance
,
"distanceTolerance"
);
SimTKOpenMMUtilities
::
freeOneDRealOpenMMArray
(
_reducedMasses
,
"reducedMasses"
);
}
for
(
unsigned
int
i
=
0
;
i
<
_matrices
.
size
();
i
++
)
SimTKOpenMMUtilities
::
freeTwoDRealOpenMMArray
(
_matrices
[
i
],
""
);
//
for (unsigned int i = 0; i < _matrices.size(); i++)
//
SimTKOpenMMUtilities::freeTwoDRealOpenMMArray(_matrices[i], "");
}
/**---------------------------------------------------------------------------------------
...
...
@@ -451,7 +572,7 @@ int ReferenceRigidShakeAlgorithm::apply( int numberOfAtoms, RealOpenMM** atomCoo
int
iterations
=
0
;
int
numberConverged
=
0
;
vector
<
RealOpenMM
>
constraintForce
(
_numberOfConstraints
);
vector
<
RealOpenMM
>
tempForce
(
10
);
vector
<
RealOpenMM
>
tempForce
(
_numberOfConstraints
);
while
(
!
done
&&
iterations
++
<
getMaximumNumberOfIterations
()
){
numberConverged
=
0
;
for
(
int
ii
=
0
;
ii
<
_numberOfConstraints
;
ii
++
){
...
...
@@ -482,22 +603,35 @@ int ReferenceRigidShakeAlgorithm::apply( int numberOfAtoms, RealOpenMM** atomCoo
if
(
numberConverged
==
_numberOfConstraints
){
done
=
true
;
}
for
(
unsigned
int
i
=
0
;
i
<
_rigidClusters
.
size
();
i
++
)
{
const
vector
<
int
>&
cluster
=
_rigidClusters
[
i
];
RealOpenMM
**
matrix
=
_matrices
[
i
];
unsigned
int
size
=
cluster
.
size
();
if
(
size
>
tempForce
.
size
())
tempForce
.
resize
(
size
);
for
(
unsigned
int
j
=
0
;
j
<
size
;
j
++
)
{
tempForce
[
j
]
=
zero
;
for
(
unsigned
int
k
=
0
;
k
<
size
;
k
++
)
tempForce
[
j
]
+=
matrix
[
j
][
k
]
*
constraintForce
[
cluster
[
k
]];
}
for
(
unsigned
int
j
=
0
;
j
<
size
;
j
++
)
constraintForce
[
cluster
[
j
]]
=
tempForce
[
j
];
if
(
_matrix
.
size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
_numberOfConstraints
;
i
++
)
{
RealOpenMM
sum
=
0.0
;
for
(
int
j
=
0
;
j
<
(
int
)
_matrix
[
i
].
size
();
j
++
)
{
pair
<
int
,
RealOpenMM
>
element
=
_matrix
[
i
][
j
];
sum
+=
element
.
second
*
constraintForce
[
element
.
first
];
}
tempForce
[
i
]
=
sum
;
}
constraintForce
=
tempForce
;
}
RealOpenMM
damping
=
one
;
//(RealOpenMM) (iterations%2 == 0 ? 0.5 : 1.0);
// for (unsigned int i = 0; i < _rigidClusters.size(); i++) {
// const vector<int>& cluster = _rigidClusters[i];
// RealOpenMM** matrix = _matrices[i];
// unsigned int size = cluster.size();
// if (size > tempForce.size())
// tempForce.resize(size);
// for (unsigned int j = 0; j < size; j++) {
// tempForce[j] = zero;
// for (unsigned int k = 0; k < size; k++)
// tempForce[j] += matrix[j][k]*constraintForce[cluster[k]];
// }
// for (unsigned int j = 0; j < size; j++)
// constraintForce[cluster[j]] = tempForce[j];
//
// }
RealOpenMM
damping
=
one
;
//(RealOpenMM) (iterations < 2 ? 0.5 : 1.0);
for
(
int
ii
=
0
;
ii
<
_numberOfConstraints
;
ii
++
){
int
atomI
=
_atomIndices
[
ii
][
0
];
...
...
platforms/reference/src/SimTKReference/ReferenceRigidShakeAlgorithm.h
View file @
6fd7f3bb
...
...
@@ -26,6 +26,7 @@
#define __ReferenceQShakeAlgorithm_H__
#include "ReferenceConstraintAlgorithm.h"
#include <utility>
#include <vector>
#include <set>
...
...
@@ -47,10 +48,12 @@ class ReferenceRigidShakeAlgorithm : public ReferenceConstraintAlgorithm {
RealOpenMM
*
_distanceTolerance
;
RealOpenMM
*
_reducedMasses
;
bool
_hasInitializedMasses
;
std
::
vector
<
std
::
vector
<
int
>
>
_rigidClusters
;
std
::
vector
<
RealOpenMM
**>
_matrices
;
// std::vector<std::vector<int> > _rigidClusters;
// std::vector<RealOpenMM**> _matrices;
std
::
vector
<
std
::
vector
<
std
::
pair
<
int
,
RealOpenMM
>
>
>
_matrix
;
public:
class
AngleInfo
;
/**---------------------------------------------------------------------------------------
...
...
@@ -64,7 +67,7 @@ class ReferenceRigidShakeAlgorithm : public ReferenceConstraintAlgorithm {
--------------------------------------------------------------------------------------- */
ReferenceRigidShakeAlgorithm
(
int
numberOfAtoms
,
int
numberOfConstraints
,
int
**
atomIndices
,
RealOpenMM
*
distance
,
RealOpenMM
*
masses
,
RealOpenMM
tolerance
);
ReferenceRigidShakeAlgorithm
(
int
numberOfAtoms
,
int
numberOfConstraints
,
int
**
atomIndices
,
RealOpenMM
*
distance
,
RealOpenMM
*
masses
,
std
::
vector
<
AngleInfo
>&
angles
,
RealOpenMM
tolerance
);
/**---------------------------------------------------------------------------------------
...
...
@@ -171,6 +174,17 @@ class ReferenceRigidShakeAlgorithm : public ReferenceConstraintAlgorithm {
int
reportShake
(
int
numberOfAtoms
,
RealOpenMM
**
atomCoordinates
,
std
::
stringstream
&
message
);
};
class
ReferenceRigidShakeAlgorithm
::
AngleInfo
{
public:
int
atom1
,
atom2
,
atom3
;
RealOpenMM
angle
;
AngleInfo
(
int
atom1
,
int
atom2
,
int
atom3
,
RealOpenMM
angle
)
:
atom1
(
atom1
),
atom2
(
atom2
),
atom3
(
atom3
),
angle
(
angle
)
{
}
};
// ---------------------------------------------------------------------------------------
#endif // __ReferenceQShakeAlgorithm_H__
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment