class_docstr: Hilbert Space Gaussian process approximation for the Periodic covariance function.
  
  Note, this is not actually a Hilbert space approximation, but it comes from the same
  paper (Ruitort-Mayol et al., 2022. See Appendix B) and follows the same spirit: using a basis
  approximation to a Gaussian process. In this case, the approximation is based on a series of
  stochastic resonators.
  
  For these reasons, we have followed the same API as `gp.HSGP`, and can be used as a drop-in
  replacement for `gp.Latent`. Like `gp.Latent`, it has `prior` and `conditional` methods.
  
  For information on choosing appropriate `m`, refer to Ruitort-Mayol et al.. Note, this approximation
  is only implemented for the 1-D case.
  
  To work with the approximation in its "linearized" form, as a matrix of basis vectors and a
  vector of coefficients, see the method `prior_linearized`.
  
  Parameters
  ----------
  m: int
      The number of basis vectors to use. Must be a positive integer.
  scale: TensorLike
      The standard deviation (square root of the variance) of the GP effect. Defaults to 1.0.
  cov_func: Must be an instance of instance of `Periodic` covariance
  mean_func: None, instance of Mean
      The mean function.  Defaults to zero.
  
  Examples
  --------
  .. code:: python
  
      # A three dimensional column vector of inputs.
      X = np.random.rand(100, 3)
  
      with pm.Model() as model:
          # Specify the covariance function, only for the 1-D case
          scale = pm.HalfNormal(10)
          cov_func = pm.gp.cov.Periodic(1, period=1, ls=0.1)
  
          # Specify the approximation with 25 basis vectors
          gp = pm.gp.HSGPPeriodic(m=25, scale=scale, cov_func=cov_func)
  
          # Place a GP prior over the function f.
          f = gp.prior("f", X=X)
  
      ...
  
      # After fitting or sampling, specify the distribution
      # at new points with .conditional
      Xnew = np.linspace(-1, 2, 50)[:, None]
  
      with model:
          fcond = gp.conditional("fcond", Xnew=Xnew)
  
  References
  ----------
  -   Ruitort-Mayol, G., and Anderson, M., and Solin, A., and Vehtari, A. (2022). Practical
      Hilbert Space Approximate Bayesian Gaussian Processes for Probabilistic Programming
class_docstr_tok: ["Hilbert","Space","Gaussian","process","approximation","for","the","Periodic","covariance","function",".","Note",",","this","is","not","actually","a","Hilbert","space","approximation",",","but","it","comes","from","the","same","paper","(","Ruitort-Mayol","et","al.",",","2022",".","See","Appendix","B",")","and","follows","the","same","spirit",":","using","a","basis","approximation","to","a","Gaussian","process",".","In","this","case",",","the","approximation","is","based","on","a","series","of","stochastic","resonators",".","For","these","reasons",",","we","have","followed","the","same","API","as","`","gp.HSGP","`",",","and","can","be","used","as","a","drop-in","replacement","for","`","gp.Latent","`",".","Like","`","gp.Latent","`",",","it","has","`","prior","`","and","`","conditional","`","methods",".","For","information","on","choosing","appropriate","`","m","`",",","refer","to","Ruitort-Mayol","et","al","..","Note",",","this","approximation","is","only","implemented","for","the","1-D","case",".","To","work","with","the","approximation","in","its","``","linearized","''","form",",","as","a","matrix","of","basis","vectors","and","a","vector","of","coefficients",",","see","the","method","`","prior_linearized","`",".","Parameters","--","--","--","--","--","m",":","int","The","number","of","basis","vectors","to","use",".","Must","be","a","positive","integer",".","scale",":","TensorLike","The","standard","deviation","(","square","root","of","the","variance",")","of","the","GP","effect",".","Defaults","to","1.0.","cov_func",":","Must","be","an","instance","of","instance","of","`","Periodic","`","covariance","mean_func",":","None",",","instance","of","Mean","The","mean","function",".","Defaults","to","zero",".","Examples","--","--","--","--","..","code",":",":","python","#","A","three","dimensional","column","vector","of","inputs",".","X","=","np.random.rand","(","100",",","3",")","with","pm.Model","(",")","as","model",":","#","Specify","the","covariance","function",",","only","for","the","1-D","case","scale","=","pm.HalfNormal","(","10",")","cov_func","=","pm.gp.cov.Periodic","(","1",",","period=1",",","ls=0.1",")","#","Specify","the","approximation","with","25","basis","vectors","gp","=","pm.gp.HSGPPeriodic","(","m=25",",","scale=scale",",","cov_func=cov_func",")","#","Place","a","GP","prior","over","the","function","f.","f","=","gp.prior","(","``","f","''",",","X=X",")","...","#","After","fitting","or","sampling",",","specify","the","distribution","#","at","new","points","with",".conditional","Xnew","=","np.linspace","(","-1",",","2",",","50",")","[",":",",","None","]","with","model",":","fcond","=","gp.conditional","(","``","fcond","''",",","Xnew=Xnew",")","References","--","--","--","--","--","-","Ruitort-Mayol",",","G.",",","and","Anderson",",","M.",",","and","Solin",",","A.",",","and","Vehtari",",","A",".","(","2022",")",".","Practical","Hilbert","Space","Approximate","Bayesian","Gaussian","Processes","for","Probabilistic","Programming"]
docstr: Linearized version of the approximation. Returns the cosine and sine bases and coefficients
  of the expansion needed to create the GP.
  
  This function allows the user to bypass the GP interface and work directly with the basis
  and coefficients directly.  This format allows the user to create predictions using
  `pm.set_data` similarly to a linear model.  It also enables computational speed ups in
  multi-GP models since they may share the same basis.
  
  Correct results when using `prior_linearized` in tandem with `pm.set_data` and
  `pm.MutableData` require that the `Xs` are zero-centered, so it's mean must be subtracted.
  An example is given below.
  
  Parameters
  ----------
  Xs: array-like
      Function input values.  Assumes they have been mean subtracted or centered at zero.
  
  Returns
  -------
  (phi_cos, phi_sin): Tuple[array-like]
      List of either Numpy or PyTensor 2D array of the cosine and sine fixed basis vectors.
      There are n rows, one per row of `Xs` and `m` columns, one for each basis vector.
  psd: array-like
      Either a Numpy or PyTensor 1D array of the coefficients of the expansion.
  
  Examples
  --------
  .. code:: python
  
      # A one dimensional column vector of inputs.
      X = np.linspace(0, 10, 100)[:, None]
  
      with pm.Model() as model:
          scale = pm.HalfNormal(10)
          cov_func = pm.gp.cov.Periodic(1, period=1, ls=ell)
  
          # m=200 means 200 basis vectors
          gp = pm.gp.HSGPPeriodic(m=200, scale=scale, cov_func=cov_func)
  
          # Order is important.  First calculate the mean, then make X a shared variable,
          # then subtract the mean.  When X is mutated later, the correct mean will be
          # subtracted.
          X_mean = np.mean(X, axis=0)
          X = pm.MutableData("X", X)
          Xs = X - X_mean
  
          # Pass the zero-subtracted Xs in to the GP
          (phi_cos, phi_sin), psd = gp.prior_linearized(Xs=Xs)
  
          # Specify standard normal prior in the coefficients.  The number of which
          # is twice the number of basis vectors minus one.
          # This is so that each cosine term has a `beta` and all but one of the
          # sine terms, as first eigenfunction for the sine component is zero
          m = gp._m
          beta = pm.Normal("beta", size=(m * 2 - 1))
  
          # The (non-centered) GP approximation is given by
          f = pm.Deterministic(
              "f",
              phi_cos @ (psd * beta[:m]) + phi_sin[..., 1:] @ (psd[1:] * beta[m:])
          )
          ...
  
  
      # Then it works just like a linear regression to predict on new data.
      # First mutate the data X,
      x_new = np.linspace(-10, 10, 100)
      with model:
          model.set_data("X", x_new[:, None])
  
      # and then make predictions for the GP using posterior predictive sampling.
      with model:
          ppc = pm.sample_posterior_predictive(idata, var_names=["f"])
docstr_tok: ["Linearized","version","of","the","approximation",".","Returns","the","cosine","and","sine","bases","and","coefficients","of","the","expansion","needed","to","create","the","GP",".","This","function","allows","the","user","to","bypass","the","GP","interface","and","work","directly","with","the","basis","and","coefficients","directly",".","This","format","allows","the","user","to","create","predictions","using","`","pm.set_data","`","similarly","to","a","linear","model",".","It","also","enables","computational","speed","ups","in","multi-GP","models","since","they","may","share","the","same","basis",".","Correct","results","when","using","`","prior_linearized","`","in","tandem","with","`","pm.set_data","`","and","`","pm.MutableData","`","require","that","the","`","Xs","`","are","zero-centered",",","so","it","'s","mean","must","be","subtracted",".","An","example","is","given","below",".","Parameters","--","--","--","--","--","Xs",":","array-like","Function","input","values",".","Assumes","they","have","been","mean","subtracted","or","centered","at","zero",".","Returns","--","--","--","-","(","phi_cos",",","phi_sin",")",":","Tuple","[","array-like","]","List","of","either","Numpy","or","PyTensor","2D","array","of","the","cosine","and","sine","fixed","basis","vectors",".","There","are","n","rows",",","one","per","row","of","`","Xs","`","and","`","m","`","columns",",","one","for","each","basis","vector",".","psd",":","array-like","Either","a","Numpy","or","PyTensor","1D","array","of","the","coefficients","of","the","expansion",".","Examples","--","--","--","--","..","code",":",":","python","#","A","one","dimensional","column","vector","of","inputs",".","X","=","np.linspace","(","0",",","10",",","100",")","[",":",",","None","]","with","pm.Model","(",")","as","model",":","scale","=","pm.HalfNormal","(","10",")","cov_func","=","pm.gp.cov.Periodic","(","1",",","period=1",",","ls=ell",")","#","m=200","means","200","basis","vectors","gp","=","pm.gp.HSGPPeriodic","(","m=200",",","scale=scale",",","cov_func=cov_func",")","#","Order","is","important",".","First","calculate","the","mean",",","then","make","X","a","shared","variable",",","#","then","subtract","the","mean",".","When","X","is","mutated","later",",","the","correct","mean","will","be","#","subtracted",".","X_mean","=","np.mean","(","X",",","axis=0",")","X","=","pm.MutableData","(","``","X","''",",","X",")","Xs","=","X","-","X_mean","#","Pass","the","zero-subtracted","Xs","in","to","the","GP","(","phi_cos",",","phi_sin",")",",","psd","=","gp.prior_linearized","(","Xs=Xs",")","#","Specify","standard","normal","prior","in","the","coefficients",".","The","number","of","which","#","is","twice","the","number","of","basis","vectors","minus","one",".","#","This","is","so","that","each","cosine","term","has","a","`","beta","`","and","all","but","one","of","the","#","sine","terms",",","as","first","eigenfunction","for","the","sine","component","is","zero","m","=","gp._m","beta","=","pm.Normal","(","``","beta","''",",","size=","(","m","*","2","-","1",")",")","#","The","(","non-centered",")","GP","approximation","is","given","by","f","=","pm.Deterministic","(","``","f","''",",","phi_cos","@","(","psd","*","beta","[",":","m","]",")","+","phi_sin","[","...",",","1",":","]","@","(","psd","[","1",":","]","*","beta","[","m",":","]",")",")","...","#","Then","it","works","just","like","a","linear","regression","to","predict","on","new","data",".","#","First","mutate","the","data","X",",","x_new","=","np.linspace","(","-10",",","10",",","100",")","with","model",":","model.set_data","(","``","X","''",",","x_new","[",":",",","None","]",")","#","and","then","make","predictions","for","the","GP","using","posterior","predictive","sampling",".","with","model",":","ppc","=","pm.sample_posterior_predictive","(","idata",",","var_names=","[","``","f","''","]",")"]
code: def prior_linearized(self, Xs: TensorLike):
      """Linearized version of the approximation. Returns the cosine and sine bases and coefficients
      of the expansion needed to create the GP.
  
      This function allows the user to bypass the GP interface and work directly with the basis
      and coefficients directly.  This format allows the user to create predictions using
      `pm.set_data` similarly to a linear model.  It also enables computational speed ups in
      multi-GP models since they may share the same basis.
  
      Correct results when using `prior_linearized` in tandem with `pm.set_data` and
      `pm.MutableData` require that the `Xs` are zero-centered, so it's mean must be subtracted.
      An example is given below.
  
      Parameters
      ----------
      Xs: array-like
          Function input values.  Assumes they have been mean subtracted or centered at zero.
  
      Returns
      -------
      (phi_cos, phi_sin): Tuple[array-like]
          List of either Numpy or PyTensor 2D array of the cosine and sine fixed basis vectors.
          There are n rows, one per row of `Xs` and `m` columns, one for each basis vector.
      psd: array-like
          Either a Numpy or PyTensor 1D array of the coefficients of the expansion.
  
      Examples
      --------
      .. code:: python
  
          # A one dimensional column vector of inputs.
          X = np.linspace(0, 10, 100)[:, None]
  
          with pm.Model() as model:
              scale = pm.HalfNormal(10)
              cov_func = pm.gp.cov.Periodic(1, period=1, ls=ell)
  
              # m=200 means 200 basis vectors
              gp = pm.gp.HSGPPeriodic(m=200, scale=scale, cov_func=cov_func)
  
              # Order is important.  First calculate the mean, then make X a shared variable,
              # then subtract the mean.  When X is mutated later, the correct mean will be
              # subtracted.
              X_mean = np.mean(X, axis=0)
              X = pm.MutableData("X", X)
              Xs = X - X_mean
  
              # Pass the zero-subtracted Xs in to the GP
              (phi_cos, phi_sin), psd = gp.prior_linearized(Xs=Xs)
  
              # Specify standard normal prior in the coefficients.  The number of which
              # is twice the number of basis vectors minus one.
              # This is so that each cosine term has a `beta` and all but one of the
              # sine terms, as first eigenfunction for the sine component is zero
              m = gp._m
              beta = pm.Normal("beta", size=(m * 2 - 1))
  
              # The (non-centered) GP approximation is given by
              f = pm.Deterministic(
                  "f",
                  phi_cos @ (psd * beta[:m]) + phi_sin[..., 1:] @ (psd[1:] * beta[m:])
              )
              ...
  
  
          # Then it works just like a linear regression to predict on new data.
          # First mutate the data X,
          x_new = np.linspace(-10, 10, 100)
          with model:
              model.set_data("X", x_new[:, None])
  
          # and then make predictions for the GP using posterior predictive sampling.
          with model:
              ppc = pm.sample_posterior_predictive(idata, var_names=["f"])
      """
      Xs, _ = self.cov_func._slice(Xs)
  
      phi_cos, phi_sin = calc_basis_periodic(
          Xs, self.cov_func.period, self._m, tl=pt
      )
      J = pt.arange(0, self._m, 1)
      # rescale basis coefficients by the sqrt variance term
      psd = self.scale * self.cov_func.power_spectral_density_approx(J)
      return (phi_cos, phi_sin), psd
  
imports: import numbers
  import warnings
  from types import ModuleType
  from typing import Optional, Sequence, Union
  import numpy
  import pytensor.tensor
  import pymc
  from pymc.gp.cov import Covariance, Periodic
  from pymc.gp.gp import Base
  from pymc.gp.mean import Mean, Zero
label_desc: Use image node_id 2 for calling the HSGPPeriodic obj's underlying member method code with example usage: obj.prior_linearized(Xs) and returns: phi_cos,  phi_sin,  psd