/usr/lib/python2.7/dist-packages/dipy/reconst/multi_voxel.py is in python-dipy 0.10.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | """Tools to easily make multi voxel models"""
import numpy as np
from numpy.lib.stride_tricks import as_strided
from ..core.ndindex import ndindex
from .quick_squash import quick_squash as _squash
from .base import ReconstFit
def multi_voxel_fit(single_voxel_fit):
"""Method decorator to turn a single voxel model fit
definition into a multi voxel model fit definition
"""
def new_fit(self, data, mask=None):
"""Fit method for every voxel in data"""
# If only one voxel just return a normal fit
if data.ndim == 1:
return single_voxel_fit(self, data)
# Make a mask if mask is None
if mask is None:
shape = data.shape[:-1]
strides = (0,) * len(shape)
mask = as_strided(np.array(True), shape=shape, strides=strides)
# Check the shape of the mask if mask is not None
elif mask.shape != data.shape[:-1]:
raise ValueError("mask and data shape do not match")
# Fit data where mask is True
fit_array = np.empty(data.shape[:-1], dtype=object)
for ijk in ndindex(data.shape[:-1]):
if mask[ijk]:
fit_array[ijk] = single_voxel_fit(self, data[ijk])
return MultiVoxelFit(self, fit_array, mask)
return new_fit
class MultiVoxelFit(ReconstFit):
"""Holds an array of fits and allows access to their attributes and
methods"""
def __init__(self, model, fit_array, mask):
self.model = model
self.fit_array = fit_array
self.mask = mask
@property
def shape(self):
return self.fit_array.shape
def __getattr__(self, attr):
result = CallableArray(self.fit_array.shape, dtype=object)
for ijk in ndindex(result.shape):
if self.mask[ijk]:
result[ijk] = getattr(self.fit_array[ijk], attr)
return _squash(result, self.mask)
def __getitem__(self, index):
item = self.fit_array[index]
if isinstance(item, np.ndarray):
return MultiVoxelFit(self.model, item, self.mask[index])
else:
return item
def predict(self, *args, **kwargs):
"""
Predict for the multi-voxel object using each single-object's
prediction API, with S0 provided from an array.
"""
if not hasattr(self.model, 'predict'):
msg = "This model does not have prediction implemented yet"
raise NotImplementedError(msg)
S0 = kwargs.get('S0', np.ones(self.fit_array.shape))
idx = ndindex(self.fit_array.shape)
ijk = next(idx)
def gimme_S0(S0, ijk):
if isinstance(S0, np.ndarray):
return S0[ijk]
else:
return S0
kwargs['S0'] = gimme_S0(S0, ijk)
# If we have a mask, we might have some Nones up front, skip those:
while self.fit_array[ijk] is None:
ijk = next(idx)
first_pred = self.fit_array[ijk].predict(*args, **kwargs)
result = np.zeros(self.fit_array.shape + (first_pred.shape[-1],))
result[ijk] = first_pred
for ijk in idx:
kwargs['S0'] = gimme_S0(S0, ijk)
# If it's masked, we predict a 0:
if self.fit_array[ijk] is None:
result[ijk] *= 0
else:
result[ijk] = self.fit_array[ijk].predict(*args, **kwargs)
return result
class CallableArray(np.ndarray):
"""An array which can be called like a function"""
def __call__(self, *args, **kwargs):
result = np.empty(self.shape, dtype=object)
for ijk in ndindex(self.shape):
item = self[ijk]
if item is not None:
result[ijk] = item(*args, **kwargs)
return _squash(result)
|