'''
Transformations that primarily involve numerical computation on variables.
'''

import numpy as np
import pandas as pd
from bids.utils import listify
from .base import Transformation
from ...variables import SparseRunVariable


class scale(Transformation):

    def _transform(self, data, demean=True, rescale=True):
        if demean:
            data -= data.mean()
        if rescale:
            data /= data.std()
        return data


class sum(Transformation):

    _loopable = False
    _groupable = False
    _align = True
    _output_required = True

    def _transform(self, data, weights=None):
        if weights is None:
            weights = np.ones(data.shape[1])
        else:
            if len(weights.ravel()) != data.shape[1]:
                raise ValueError("If weights are passed to sum(), the number "
                                 "of elements must equal number of variables"
                                 "being summed.")
        data = pd.concat(data, axis=1)
        return data.dot(weights)


class product(Transformation):

    _loopable = False
    _groupable = False
    _align = True
    _output_required = True

    def _transform(self, data):
        data = pd.concat(data, axis=1)
        return data.product(1)


class orthogonalize(Transformation):

    _variables_used = ('variables', 'other')
    _densify = ('variables', 'other')
    _align = ('other')

    def _transform(self, var, other):

        other = listify(other)

        # Set up X matrix and slice into it based on target variable indices
        X = np.array([self._variables[c].values.values.squeeze()
                      for c in other]).T
        X = X[var.index, :]
        assert len(X) == len(var)
        y = var.values
        _aX = np.c_[np.ones(len(y)), X]
        coefs, resids, rank, s = np.linalg.lstsq(_aX, y)
        result = pd.DataFrame(y - X.dot(coefs[1:]), index=var.index)
        return result


class threshold(Transformation):
    ''' Threshold and/or binarize a variable.
    Args:
        data (Series/DF): The pandas structure to threshold.
        threshold (float): The value to binarize around (values above will
            be assigned 1, values below will be assigned 0).
        binarize (bool): If True, binarizes all non-zero values (i.e., every
            non-zero value will be set to 1).
        above (bool): Specifies which values to retain with respect to the
            cut-off. If True, all value above the threshold will be kept; if
            False, all values below the threshold will be kept. Defaults to
            True.
        signed (bool): Specifies whether to treat the threshold as signed
        (default) or unsigned. For example, when passing above=True and
        threshold=3, if signed=True, all and only values above +3 would be
        retained. If signed=False, all absolute values > 3 would be retained
        (i.e.,values in  the range -3 < X < 3 would be set to 0).

    '''

    _groupable = False

    def _transform(self, data, threshold=0., binarize=False, above=True,
                   signed=True):
        if not signed:
            threshold = np.abs(threshold)
            data = data.abs()
        keep = data >= threshold if above else data <= threshold
        # print("Keep:", keep)
        data[~keep] = 0
        if binarize:
            data[keep] = 1
        return data


class or_(Transformation):
    ''' Logical OR (inclusive) on two or more variables.
    Args:
        dfs (list of DFs): variables to enter into the disjunction.
    '''

    _loopable = False
    _groupable = False
    _output_required = True

    def _transform(self, dfs):
        df = pd.concat(dfs, axis=1)
        return df.any(axis=1)


class and_(Transformation):
    ''' Logical AND on two or more variables.
    Args:
        dfs (list of DFs): variables to enter into the conjunction.
    '''

    _input_type = 'variable'
    _return_type = 'variable'
    _loopable = False
    _groupable = False
    _output_required = True

    def _transform(self, var):
        if isinstance(var[0], SparseRunVariable):
            onset = var[0].onset
            for v in var[1:]:
                onset = onset[np.in1d(onset, v.onset)]

            selector = np.in1d(var[0].onset, onset)
            duration = var[0].duration[selector]
            values = var[0].values[selector]
            for v in var:
                selector = np.in1d(v.onset, onset)
                if not (np.allclose(duration, v.duration[selector]) and
                        np.allclose(values, v.values[selector])):
                    raise ValueError("Mismatched onset/duration/weights")
            return SparseRunVariable(
                var[0].name,
                pd.DataFrame({'onset': onset, 'duration': duration,
                              'amplitude': values}),
                run_info = var[0].run_info,
                source = var[0].run_info)

        df = pd.concat(var, axis=1)
        return df.all(axis=1)

@@ -184,51 +184,8 @@
 ion%0A
-from ...variables import SparseRunVariable%0A
 %0A%0Acl
@@ -3838,67 +3838,8 @@
 ''%0A%0A
-    _input_type = 'variable'%0A    _return_type = 'variable'%0A
     
@@ -3937,919 +3937,40 @@
 lf, 
-var):%0A        if isinstance(var%5B0%5D, SparseRunVariable):%0A            onset = var%5B0%5D.onset%0A            for v in var%5B1:%5D:%0A                onset = onset%5Bnp.in1d(onset, v.onset)%5D%0A%0A            selector = np.in1d(var%5B0%5D.onset, onset)%0A            duration = var%5B0%5D.duration%5Bselector%5D%0A            values = var%5B0%5D.values%5Bselector%5D%0A            for v in var:%0A                selector = np.in1d(v.onset, onset)%0A                if not (np.allclose(duration, v.duration%5Bselector%5D) and%0A                        np.allclose(values, v.values%5Bselector%5D)):%0A                    raise ValueError(%22Mismatched onset/duration/weights%22)%0A            return SparseRunVariable(%0A                var%5B0%5D.name,%0A                pd.DataFrame(%7B'onset': onset, 'duration': duration,%0A                              'amplitude': values%7D),%0A                run_info = var%5B0%5D.run_info,%0A                source = var%5B0%5D.run_info)%0A%0A        df = pd.concat(var
+dfs):%0A        df = pd.concat(dfs
 , ax

revert changes to compute.py