class_docstr: Simple Harmonic Oscillator based Reconstruction and Estimation
  (SHORE) [1]_ of the diffusion signal.
  
  The main idea is to model the diffusion signal as a linear combination of
  continuous functions $\phi_i$,
  
  ..math::
      :nowrap:
          \begin{equation}
              S(\mathbf{q})= \sum_{i=0}^I  c_{i} \phi_{i}(\mathbf{q}).
          \end{equation}
  
  where $\mathbf{q}$ is the wave vector which corresponds to different
  gradient directions. Numerous continuous functions $\phi_i$ can be used to
  model $S$. Some are presented in [2,3,4]_.
  
  From the $c_i$ coefficients, there exist analytical formulae to estimate
  the ODF, the return to the origin probability (RTOP), the mean square
  displacement (MSD), amongst others [5]_.
  
  References
  ----------
  .. [1] Ozarslan E. et al., "Simple harmonic oscillator based reconstruction
         and estimation for one-dimensional q-space magnetic resonance
         1D-SHORE)", Proc Intl Soc Mag Reson Med, vol. 16, p. 35., 2008.
  
  .. [2] Merlet S. et al., "Continuous diffusion signal, EAP and ODF
         estimation via Compressive Sensing in diffusion MRI", Medical
         Image Analysis, 2013.
  
  .. [3] Rathi Y. et al., "Sparse multi-shell diffusion imaging", MICCAI,
         2011.
  
  .. [4] Cheng J. et al., "Theoretical Analysis and Practical Insights on
         EAP Estimation via a Unified HARDI Framework", MICCAI workshop on
         Computational Diffusion MRI, 2011.
  
  .. [5] Ozarslan E. et al., "Mean apparent propagator (MAP) MRI: A novel
         diffusion imaging method for mapping tissue microstructure",
         NeuroImage, 2013.
  
  Notes
  -----
  The implementation of SHORE depends on CVXPY (https://www.cvxpy.org/).
class_docstr_tok: ["Simple","Harmonic","Oscillator","based","Reconstruction","and","Estimation","(","SHORE",")","[","1","]","_","of","the","diffusion","signal",".","The","main","idea","is","to","model","the","diffusion","signal","as","a","linear","combination","of","continuous","functions","$","\\phi_i","$",",","..","math",":",":",":","nowrap",":","\\begin","{","equation","}","S","(","\\mathbf","{","q","}",")","=","\\sum_","{","i=0","}","^I","c_","{","i","}","\\phi_","{","i","}","(","\\mathbf","{","q","}",")",".","\\end","{","equation","}","where","$","\\mathbf","{","q","}","$","is","the","wave","vector","which","corresponds","to","different","gradient","directions",".","Numerous","continuous","functions","$","\\phi_i","$","can","be","used","to","model","$","S","$",".","Some","are","presented","in","[","2,3,4","]","_",".","From","the","$","c_i","$","coefficients",",","there","exist","analytical","formulae","to","estimate","the","ODF",",","the","return","to","the","origin","probability","(","RTOP",")",",","the","mean","square","displacement","(","MSD",")",",","amongst","others","[","5","]","_.","References","--","--","--","--","--","..","[","1","]","Ozarslan","E.","et","al.",",","``","Simple","harmonic","oscillator","based","reconstruction","and","estimation","for","one-dimensional","q-space","magnetic","resonance","1D-SHORE",")","''",",","Proc","Intl","Soc","Mag","Reson","Med",",","vol",".","16",",","p.","35.",",","2008",".","..","[","2","]","Merlet","S.","et","al.",",","``","Continuous","diffusion","signal",",","EAP","and","ODF","estimation","via","Compressive","Sensing","in","diffusion","MRI","''",",","Medical","Image","Analysis",",","2013",".","..","[","3","]","Rathi","Y.","et","al.",",","``","Sparse","multi-shell","diffusion","imaging","''",",","MICCAI",",","2011",".","..","[","4","]","Cheng","J.","et","al.",",","``","Theoretical","Analysis","and","Practical","Insights","on","EAP","Estimation","via","a","Unified","HARDI","Framework","''",",","MICCAI","workshop","on","Computational","Diffusion","MRI",",","2011",".","..","[","5","]","Ozarslan","E.","et","al.",",","``","Mean","apparent","propagator","(","MAP",")","MRI",":","A","novel","diffusion","imaging","method","for","mapping","tissue","microstructure","''",",","NeuroImage",",","2013",".","Notes","--","--","-","The","implementation","of","SHORE","depends","on","CVXPY","(","https",":","\/\/www.cvxpy.org\/",")","."]
code: def fit(self, data):
      Lshore = l_shore(self.radial_order)
      Nshore = n_shore(self.radial_order)
      # Generate the SHORE basis
      M = self.cache_get("shore_matrix", key=self.gtab)
      if M is None:
          M = shore_matrix(
              self.radial_order, self.zeta, self.gtab, self.tau
          )
          self.cache_set("shore_matrix", self.gtab, M)
  
      MpseudoInv = self.cache_get(
          "shore_matrix_reg_pinv", key=self.gtab
      )
      if MpseudoInv is None:
          MpseudoInv = np.dot(
              np.linalg.inv(
                  np.dot(M.T, M)
                  + self.lambdaN * Nshore
                  + self.lambdaL * Lshore
              ),
              M.T,
          )
          self.cache_set("shore_matrix_reg_pinv", self.gtab, MpseudoInv)
  
      # Compute the signal coefficients in SHORE basis
      if not self.constrain_e0:
          coef = np.dot(MpseudoInv, data)
  
          signal_0 = 0
  
          for n in range(int(self.radial_order / 2) + 1):
              signal_0 += coef[n] * (
                  genlaguerre(n, 0.5)(0)
                  * (
                      (factorial(n))
                      / (
                          2
                          * np.pi
                          * (self.zeta**1.5)
                          * gamma(n + 1.5)
                      )
                  )
                  ** 0.5
              )
  
          coef = coef / signal_0
      else:
          data_norm = data / data[self.gtab.b0s_mask].mean()
          M0 = M[self.gtab.b0s_mask, :]
  
          c = cvxpy.Variable(M.shape[1])
          design_matrix = cvxpy.Constant(M) @ c
          objective = cvxpy.Minimize(
              cvxpy.sum_squares(design_matrix - data_norm)
              + self.lambdaN * cvxpy.quad_form(c, Nshore)
              + self.lambdaL * cvxpy.quad_form(c, Lshore)
          )
  
          if not self.positive_constraint:
              constraints = [M0[0] @ c == 1]
          else:
              lg = int(np.floor(self.pos_grid**3 / 2))
              v, t = create_rspace(self.pos_grid, self.pos_radius)
              psi = self.cache_get(
                  "shore_matrix_positive_constraint",
                  key=(self.pos_grid, self.pos_radius),
              )
              if psi is None:
                  psi = shore_matrix_pdf(
                      self.radial_order, self.zeta, t[:lg]
                  )
                  self.cache_set(
                      "shore_matrix_positive_constraint",
                      (self.pos_grid, self.pos_radius),
                      psi,
                  )
              constraints = [(M0[0] @ c) == 1.0, (psi @ c) >= 1e-3]
          prob = cvxpy.Problem(objective, constraints)
          try:
              prob.solve(solver=self.cvxpy_solver)
              coef = np.asarray(c.value).squeeze()
          except Exception:
              warn("Optimization did not find a solution")
              coef = np.zeros(M.shape[1])
      return ShoreFit(self, coef)
  
imports: from warnings import warn
  from math import factorial
  import numpy
  from scipy.special import genlaguerre, gamma, hyp2f1
  from dipy.reconst.cache import Cache
  from dipy.reconst.multi_voxel import multi_voxel_fit
  from dipy.reconst.shm import real_sh_descoteaux_from_index
  from dipy.core.geometry import cart2sphere
  from dipy.utils.optpkg import optional_package
label_desc: Use image node_id 2 for calling the ShoreModel obj's underlying member method code with example usage: obj.fit(data) and returns: ShoreFit