Skip to content

Commit 60f4ced

Browse files
authored
Merge pull request #162 from ComputationalCryoEM/develop
Update functions on block diagonal matrix and basis class for polar 2D
2 parents a5f0669 + bb1363a commit 60f4ced

23 files changed

+2478
-1133
lines changed

CONTRIBUTORS.rst

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
ASPIRE has contributions from a growing team of collaborators.
2+
To learn more about them please visit our `Team webpage <http://spr.math.princeton.edu/team>`_.
3+
4+
Developers of the Python and Matlab collection of ASPIRE codes are listed below.
5+
6+
7+
|
8+
9+
10+
.. table:: Python Contributors
11+
12+
+------------------+--------------+---------------------------+----------------------+
13+
| Name | GithubID | Email | Affiliations |
14+
+==================+==============+===========================+======================+
15+
| Joakim Andén | janden | [email protected] | Princeton University |
16+
+------------------+--------------+---------------------------+----------------------+
17+
| Vineet Bansal | vineetbansal | [email protected] | Princeton University |
18+
+------------------+--------------+---------------------------+----------------------+
19+
| Robbie Brook | rbrook | [email protected] | Princeton University |
20+
+------------------+--------------+---------------------------+----------------------+
21+
| Ayelet Heimowitz | ayeltg | [email protected] | Princeton University |
22+
+------------------+--------------+---------------------------+----------------------+
23+
| Gabi Pragier | pgabi | [email protected] | Tel Aviv University |
24+
+------------------+--------------+---------------------------+----------------------+
25+
| Itay Sason | itaysason | [email protected] | Tel Aviv University |
26+
+------------------+--------------+---------------------------+----------------------+
27+
| Yoel Shkolnisky | yoelsh | [email protected] | Tel Aviv University |
28+
+------------------+--------------+---------------------------+----------------------+
29+
| Amit Singer | amitsinger | [email protected] | Princeton University |
30+
+------------------+--------------+---------------------------+----------------------+
31+
| Garrett Wright | garrettwrong | [email protected] | Princeton University |
32+
+------------------+--------------+---------------------------+----------------------+
33+
| Junchao Xia | junchaoxia | [email protected] | Princeton University |
34+
+------------------+--------------+---------------------------+----------------------+
35+
36+
|
37+
38+
39+
.. table:: Additional MATLAB Contributors not listed above:
40+
41+
42+
+-------------+----------+-------+----------------------+
43+
| Name | GithubID | Email | Affiliations |
44+
+=============+==========+=======+======================+
45+
| Mar Cohen | | | Tel Aviv University |
46+
+-------------+----------+-------+----------------------+
47+
| Lanhui Wang | | | Princeton University |
48+
+-------------+----------+-------+----------------------+
49+
| Jane Zhao | | | Princeton University |
50+
+-------------+----------+-------+----------------------+
51+
52+
53+
If we've missed you or would like to update your details, please contact us and we'll be happy to do so.

azure-pipelines.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
schedules:
2+
- cron: "0 0 * * *" # cron syntax defining a schedule
3+
displayName: Daily Build
4+
branches:
5+
include:
6+
- master
7+
- develop
8+
always: true # Always run the Daily Build
9+
110
jobs:
211
- job:
312
displayName: ubuntu-latest
@@ -36,7 +45,7 @@ jobs:
3645

3746
# - bash: conda update -q -y conda
3847
# displayName: Update conda
39-
48+
4049
- bash: conda env create --name myEnvironment --file environment.yml
4150
displayName: Create Anaconda environment
4251

@@ -96,10 +105,10 @@ jobs:
96105

97106
- bash: conda clean -i -t -y
98107
displayName: Removing conda cached package tarballs.
99-
108+
100109
- bash: conda env create --name myEnvironment --file environment.yml
101110
displayName: Create Anaconda environment
102-
111+
103112
- bash: |
104113
source activate myEnvironment
105114
python setup.py install
@@ -149,7 +158,7 @@ jobs:
149158

150159
- script: conda update -q -y conda
151160
displayName: Update conda
152-
161+
153162
- script: |
154163
call activate myEnvironment
155164
python setup.py install

docs/source/authors.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Authors
2+
=======
3+
4+
.. include:: ../../CONTRIBUTORS.rst

docs/source/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ linear and nonlinear dimensionality reduction, randomized algorithms in numerica
1717
installation
1818
quickstart
1919
modules
20+
authors
2021

2122

2223
Indices and tables
@@ -30,4 +31,4 @@ Indices and tables
3031
References
3132
==========
3233

33-
.. bibliography:: references.bib
34+
.. bibliography:: references.bib

src/aspire/basis/__init__.py

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Basis:
1515
Define a base class for expanding 2D particle images and 3D structure volumes
1616
1717
"""
18-
def __init__(self, size, ell_max=None):
18+
def __init__(self, size, ell_max=None, dtype=np.float64):
1919
"""
2020
Initialize an object for the base of basis class
2121
@@ -36,6 +36,9 @@ def __init__(self, size, ell_max=None):
3636
self.count = 0
3737
self.ell_max = ell_max
3838
self.ndim = ndim
39+
self.dtype = dtype
40+
if self.dtype != np.float64:
41+
raise NotImplementedError("Currently only implemented for default double (np.float64) type")
3942

4043
self._build()
4144

@@ -149,46 +152,46 @@ def mat_evaluate_t(self, X):
149152
"""
150153
return mdim_mat_fun_conj(X, len(self.sz), 1, self.evaluate_t)
151154

152-
def expand(self, v):
155+
def expand(self, x):
153156
"""
154-
Expand array in basis
157+
Obtain coefficients in the basis from those in standard coordinate basis
155158
156-
This is a similar function to `evaluate_t` but with more accuracy by
157-
using the cg optimizing of linear equation, Ax=b.
159+
This is a similar function to evaluate_t but with more accuracy by using
160+
the cg optimizing of linear equation, Ax=b.
158161
159-
If `v` is a matrix of size `basis.ct`-by-..., `B` is the change-of-basis
160-
matrix of this basis, and `x` is a matrix of size `self.sz`-by-...,
161-
the function calculates v = (B' * B)^(-1) * B' * x, where the rows
162-
of `B` and columns of `x` are read as vectorized arrays.
163-
164-
:param v: An array whose first few dimensions are to be expanded in this basis.
165-
These dimensions must equal `self.sz`.
166-
:return: The coefficients of `v` expanded in this basis. If more than
167-
one array of size `self.sz` is found in `v`, the second and higher
168-
dimensions of the return value correspond to those higher dimensions of `v`.
162+
:param x: An array whose first two or three dimensions are to be expanded
163+
the desired basis. These dimensions must equal `self.sz`.
164+
:return : The coefficients of `v` expanded in the desired basis.
165+
The first dimension of `v` is with size of `count` and the
166+
second and higher dimensions of the return value correspond to
167+
those higher dimensions of `x`.
169168
170169
"""
171-
ensure(v.shape[:self.ndim] == self.sz, f'First {self.ndim} dimensions of v must match {self.sz}.')
170+
# ensure the first dimensions with size of self.sz
171+
x, sz_roll = unroll_dim(x, self.ndim + 1)
172+
ensure(x.shape[:self.ndim] == self.sz,
173+
f'First {self.ndim} dimensions of x must match {self.sz}.')
172174

173-
v, sz_roll = unroll_dim(v, self.ndim + 1)
174-
b = self.evaluate_t(v)
175-
operator = LinearOperator(
176-
shape=(self.count, self.count),
177-
matvec=lambda x: self.evaluate_t(self.evaluate(x))
178-
)
175+
operator = LinearOperator(shape=(self.count, self.count),
176+
matvec=lambda v: self.evaluate_t(self.evaluate(v)))
179177

180178
# TODO: (from MATLAB implementation) - Check that this tolerance make sense for multiple columns in v
181-
tol = 10 * np.finfo(v.dtype).eps
179+
tol = 10*np.finfo(x.dtype).eps
182180
logger.info('Expanding array in basis')
183-
v, info = cg(operator, b, tol=tol)
184181

185-
v = v[..., np.newaxis]
182+
# number of image samples
183+
n_data = np.size(x, self.ndim)
184+
v = np.zeros((self.count, n_data), dtype=x.dtype)
186185

187-
if info != 0:
188-
raise RuntimeError('Unable to converge!')
186+
for isample in range(0, n_data):
187+
b = self.evaluate_t(x[..., isample])
188+
# TODO: need check the initial condition x0 can improve the results or not.
189+
v[..., isample], info = cg(operator, b, tol=tol)
190+
if info != 0:
191+
raise RuntimeError('Unable to converge!')
189192

193+
# return v coefficients with the first dimension of self.count
190194
v = roll_dim(v, sz_roll)
191-
192195
return v
193196

194197
def expand_t(self, v):

src/aspire/basis/dirac.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,74 @@
1+
import logging
2+
import numpy as np
3+
14
from aspire.basis import Basis
5+
from aspire.utils.matrix import roll_dim, unroll_dim
6+
from aspire.utils.matlab_compat import m_flatten, m_reshape
7+
8+
logger = logging.getLogger(__name__)
29

310

411
class DiracBasis(Basis):
5-
pass
12+
"""
13+
Define a derived class for Dirac basis
14+
"""
15+
def __init__(self, sz, mask=None):
16+
"""
17+
Initialize an object for Dirac basis
18+
:param sz: The shape of the vectors for which to define the basis.
19+
:param mask: A boolean _mask of size sz indicating which coordinates
20+
to include in the basis (default np.full(sz, True)).
21+
"""
22+
if mask is None:
23+
mask = np.full(sz, True)
24+
self._mask = m_flatten(mask)
25+
26+
super().__init__(sz)
27+
28+
def _build(self):
29+
"""
30+
Build the internal data structure to Dirac basis
31+
"""
32+
logger.info('Expanding object in a Dirac basis.')
33+
self.count = np.sum(self._mask)
34+
self._sz_prod = self.nres ** self.ndim
35+
36+
def evaluate(self, v):
37+
"""
38+
Evaluate coefficients in standard coordinate basis from those in Dirac basis
39+
40+
:param v: A coefficient vector (or an array of coefficient vectors) to
41+
be evaluated. The first dimension must equal `self.count`.
42+
:return: The evaluation of the coefficient vector(s) `v` for this basis.
43+
This is an array whose first dimensions equal `self.sz` and the remaining
44+
dimensions correspond to dimensions two and higher of `v`.
45+
"""
46+
v, sz_roll = unroll_dim(v, 2)
47+
x = np.zeros(shape=(self._sz_prod,) + v.shape[1:])
48+
x[self._mask, ...] = v
49+
x = m_reshape(x, self.sz + x.shape[1:])
50+
x = roll_dim(x, sz_roll)
51+
52+
return x
53+
54+
def evaluate_t(self, x):
55+
"""
56+
Evaluate coefficient in Dirac basis from those in standard coordinate basis
57+
58+
:param x: The coefficient array to be evaluated. The first dimensions
59+
must equal `self.sz`.
60+
:return: The evaluation of the coefficient array `v` in the dual basis
61+
of `basis`. This is an array of vectors whose first dimension equals
62+
`self.count` and whose remaining dimensions correspond to
63+
higher dimensions of `v`.
64+
"""
65+
x, sz_roll = unroll_dim(x, self.ndim + 1)
66+
x = m_reshape(x, new_shape=(self._sz_prod,) + x.shape[self.ndim:])
67+
v = np.zeros(shape=(self.count, ) + x.shape[1:])
68+
v = x[self._mask, ...]
69+
v = roll_dim(v, sz_roll)
70+
71+
return v
72+
73+
def expand(self, x):
74+
return self.evaluate_t(x)

src/aspire/basis/ffb_2d.py

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
from numpy import pi
44
from scipy.special import jv
55
from scipy.fftpack import ifft, fft
6-
from scipy.sparse.linalg import LinearOperator, cg
76

87
from aspire.nfft import anufft3, nufft3
9-
10-
from aspire.utils import ensure
118
from aspire.utils.matrix import roll_dim, unroll_dim
129
from aspire.utils.matlab_compat import m_reshape
1310
from aspire.basis.basis_utils import lgwt
@@ -246,45 +243,3 @@ def evaluate_t(self, x):
246243
# return v coefficients with the first dimension of self.count
247244
v = roll_dim(v, sz_roll)
248245
return v
249-
250-
def expand(self, x):
251-
"""
252-
Obtain coefficients in FB basis from those in standard 2D coordinate basis
253-
254-
This is a similar function to evaluate_t but with more accuracy by using
255-
the cg optimizing of linear equation, Ax=b.
256-
257-
:param x: An array whose first two dimensions are to be expanded in FB basis.
258-
These dimensions must equal `self.sz`.
259-
:return : The coefficients of `v` expanded in FB basis. The first dimension
260-
of `v` is with size of `count` and the second and higher dimensions
261-
of the return value correspond to those higher dimensions of `x`.
262-
263-
"""
264-
# ensure the first two dimensions with size of self.sz
265-
x, sz_roll = unroll_dim(x, self.ndim + 1)
266-
x = m_reshape(x, (self.sz[0], self.sz[1], -1))
267-
ensure(x.shape[:self.ndim] == self.sz,
268-
f'First {self.ndim} dimensions of x must match {self.sz}.')
269-
270-
operator = LinearOperator(shape=(self.count, self.count),
271-
matvec=lambda v: self.evaluate_t(self.evaluate(v)))
272-
273-
# TODO: (from MATLAB implementation) - Check that this tolerance make sense for multiple columns in v
274-
tol = 10*np.finfo(x.dtype).eps
275-
logger.info('Expanding array in basis')
276-
277-
# number of image samples
278-
n_data = np.size(x, self.ndim)
279-
v = np.zeros((self.count, n_data), dtype=x.dtype)
280-
281-
for isample in range(0, n_data):
282-
b = self.evaluate_t(x[..., isample])
283-
# TODO: need check the initial condition x0 can improve the results or not.
284-
v[..., isample], info = cg(operator, b, tol=tol)
285-
if info != 0:
286-
raise RuntimeError('Unable to converge!')
287-
288-
# return v coefficients with the first dimension of self.count
289-
v = roll_dim(v, sz_roll)
290-
return v

0 commit comments

Comments
 (0)