def decode(self, ssp, method='from-set', num_sample_pts=10000, from_set_method='grid', num_init_pts=10):
    if (method == 'least-squares'):
        x = np.linalg.lstsq(self.phase_matrix, (1j * np.log(np.fft.fft(ssp, axis=0))).real)[0]
        return x
    elif (method == 'from-set'):
        (sample_ssps, sample_points) = self.get_sample_ssps(num_sample_pts, method=from_set_method)
        sims = (sample_ssps.T @ ssp)
        return sample_points[:, np.argmax(sims)]
    elif (method == 'direct-optim'):
        x0 = self.decode(ssp, method='from-set', num_sample_pts=num_init_pts)

        def min_func(x, target=ssp):
            x_ssp = self.encode(np.atleast_2d(x))
            return (- np.inner(x_ssp, target).flatten())
        soln = minimize(min_func, x0, method='L-BFGS-B')
        return soln.x
    elif (method == 'grad_descent'):
        x = self.decode(ssp, method='from-set', num_sample_pts=num_init_pts)
        fssp = np.fft.fft(ssp, axis=0)
        ls_mat = np.diag((1 / self.length_scale.flatten()))
        for j in range(10):
            scaled_x = (ls_mat @ x)
            x_enc = np.exp(((1j * self.phase_matrix) @ scaled_x))
            grad_mat = ((1j * (self.phase_matrix @ ls_mat).T) * x_enc)
            grad = (grad_mat @ fssp.T).flatten()
            x = (x - (0.1 * grad.real))
        return x
    elif (method == 'nonlin-reg'):
        x = self.decode(ssp, method='from-set', num_sample_pts=num_init_pts)
        fssp = np.fft.fft(ssp, axis=0)
        dy = np.hstack([fssp.real, fssp.imag])
        ls_mat = np.diag((1 / self.length_scale.flatten()))
        for j in range(10):
            J = np.vstack([(self.phase_matrix * np.sin(((self.phase_matrix @ x) @ ls_mat)).reshape(1, (- 1))), ((- self.phase_matrix) * np.cos(((self.phase_matrix @ x) @ ls_mat)).reshape(1, (- 1)))])
            soln = ((np.linalg.pinv((J.T @ J)) @ J.T) @ dy)
            x = (x + soln)
        return x
    else:
        raise NotImplementedError()
def decode(self, ssp, method='from-set', num_sample_pts=10000, from_set_method='grid', num_init_pts=10):
    if (method == 'least-squares'):
        x = np.linalg.lstsq(self.phase_matrix, (1j * np.log(np.fft.fft(ssp, axis=0))).real)[0]
        return x
    elif (method == 'from-set'):
        (sample_ssps, sample_points) = self.get_sample_ssps(num_sample_pts, method=from_set_method)
        sims = (sample_ssps.T @ ssp)
        return sample_points[:, np.argmax(sims)]
    elif (method == 'direct-optim'):
        x0 = self.decode(ssp, method='from-set', num_sample_pts=num_init_pts)

        def min_func(x, target=ssp):
            x_ssp = self.encode(np.atleast_2d(x))
            return (- np.inner(x_ssp, target).flatten())
        soln = minimize(min_func, x0, method='L-BFGS-B')
        return soln.x
    elif (method == 'grad_descent'):
        x = self.decode(ssp, method='from-set', num_sample_pts=num_init_pts)
        fssp = np.fft.fft(ssp, axis=0)
        ls_mat = np.diag((1 / self.length_scale.flatten()))
        for j in range(10):
            scaled_x = (ls_mat @ x)
            x_enc = np.exp(((1j * self.phase_matrix) @ scaled_x))
            grad_mat = ((1j * (self.phase_matrix @ ls_mat).T) * x_enc)
            grad = (grad_mat @ fssp.T).flatten()
            x = (x - (0.1 * grad.real))
        return x
    elif (method == 'nonlin-reg'):
        x = self.decode(ssp, method='from-set', num_sample_pts=num_init_pts)
        fssp = np.fft.fft(ssp, axis=0)
        dy = np.hstack([fssp.real, fssp.imag])
        ls_mat = np.diag((1 / self.length_scale.flatten()))
        for j in range(10):
            J = np.vstack([(self.phase_matrix * np.sin(((self.phase_matrix @ x) @ ls_mat)).reshape(1, (- 1))), ((- self.phase_matrix) * np.cos(((self.phase_matrix @ x) @ ls_mat)).reshape(1, (- 1)))])
            soln = ((np.linalg.pinv((J.T @ J)) @ J.T) @ dy)
            x = (x + soln)
        return x
    else:
        raise NotImplementedError()