Skip to content

Commit b464e1c

Browse files
committed
Initial vector feature added
1 parent 9b73c63 commit b464e1c

4 files changed

Lines changed: 53 additions & 3 deletions

File tree

cpp/pylanczos.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ void declare_template_lanczos(pybind11::module& m, const std::string& suffix) {
2020
.def_readwrite("find_maximum", &PyLanczosCpp<T>::find_maximum)
2121
.def_readwrite("eigenvalue_offset", &PyLanczosCpp<T>::eigenvalue_offset)
2222
.def(pybind11::init<std::function<void(pybind11::array_t<T>, pybind11::array_t<T>)>, size_t, bool, size_t>())
23-
.def("run", &PyLanczosCpp<T>::run);
23+
.def("run",
24+
static_cast<std::tuple<pybind11::array_t<T>, pybind11::array_t<T>, std::vector<size_t>> (PyLanczosCpp<T>::*)(
25+
void)>(&PyLanczosCpp<T>::run))
26+
.def("run",
27+
static_cast<std::tuple<pybind11::array_t<T>, pybind11::array_t<T>, std::vector<size_t>> (PyLanczosCpp<T>::*)(
28+
const std::vector<T>&)>(&PyLanczosCpp<T>::run));
2429
}
2530

2631
template <typename T>

include/pylanczos.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,21 @@ class PyLanczosCpp : public lambda_lanczos::LambdaLanczos<T> {
3030

3131
// This tuple will be interpreted as multiple-value return (python tuple) in Python.
3232
std::tuple<pybind11::array_t<T>, pybind11::array_t<T>, std::vector<size_t>> run() {
33+
this->lambda_lanczos::LambdaLanczos<T>::init_vector = lambda_lanczos::VectorRandomInitializer<T>::init;
34+
35+
return this->run_impl();
36+
};
37+
38+
std::tuple<pybind11::array_t<T>, pybind11::array_t<T>, std::vector<size_t>> run(const std::vector<T>& initial_vec) {
39+
this->lambda_lanczos::LambdaLanczos<T>::init_vector = [&initial_vec](std::vector<T>& out_vec) {
40+
std::copy(initial_vec.begin(), initial_vec.end(), out_vec.begin());
41+
};
42+
43+
return this->run_impl();
44+
};
45+
46+
private:
47+
std::tuple<pybind11::array_t<T>, pybind11::array_t<T>, std::vector<size_t>> run_impl() {
3348
using RT = lambda_lanczos::util::real_t<T>;
3449
std::vector<RT> eigenvalues;
3550
std::vector<std::vector<T>> eigenvectors;

pylanczos/pylanczos.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,13 @@ def create_custom(mv_mul, n, dtype, find_maximum, num_eigs):
116116

117117
return pylanczos_obj
118118

119-
def run(self):
119+
def run(self, initial_vector=None):
120120
"""Executes the Lanczos algorithm.
121+
Parameters
122+
----------
123+
initial_vector : numpy.ndarray, optional
124+
Initial vector to start the Lanczos iteration.
125+
If not specified, a random vector will be used.
121126
122127
Returns
123128
-------
@@ -130,7 +135,10 @@ def run(self):
130135
klass = PyLanczos._dtype_to_suffix[self._dtype]
131136
engine = klass(self._mv_mul, self._n, self._find_maximum, self._num_eigs)
132137

133-
eigenvalues, eigenvectors, iteration_counts = engine.run()
138+
if initial_vector is not None:
139+
eigenvalues, eigenvectors, iteration_counts = engine.run(initial_vector)
140+
else:
141+
eigenvalues, eigenvectors, iteration_counts = engine.run()
134142

135143
self._iteration_counts = iteration_counts
136144

test/test_pylanczos.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,28 @@ def mv_mul(v_in, v_out):
128128

129129
np.testing.assert_allclose(eigvec, correct_eigvec)
130130

131+
def test_sparse_matrix_with_initial_vector(self):
132+
n = 10
133+
134+
matrix = np.zeros((n, n), dtype='float64')
135+
for i in range(n-1):
136+
matrix[i, i+1] = -1
137+
matrix[i+1, i] = -1
138+
139+
correct_eigvec = np.sin((1+np.array(range(n)))*np.pi/(n+1))
140+
correct_eigvec /= np.linalg.norm(correct_eigvec)
141+
142+
engine = PyLanczos(matrix, False, 1)
143+
eigenvalues, eigenvectors = engine.run(correct_eigvec)
144+
eigval = eigenvalues[0]
145+
eigvec = eigenvectors[:, 0]
146+
147+
np.testing.assert_almost_equal(eigval, -2.0*np.cos(np.pi/(n+1)))
148+
sign = np.sign(eigvec[0])
149+
correct_eigvec *= sign
150+
151+
np.testing.assert_allclose(eigvec, correct_eigvec)
152+
np.testing.assert_equal(engine.iteration_counts[0], 1)
131153

132154
def test_complex_matrix(self):
133155
matrix = np.array([[ 0, 1j, 1],

0 commit comments

Comments
 (0)