Spaces:
Sleeping
Sleeping
| from sympy.concrete.products import Product | |
| from sympy.concrete.summations import Sum | |
| from sympy.core.basic import Basic | |
| from sympy.core.function import Lambda | |
| from sympy.core.numbers import (I, pi) | |
| from sympy.core.singleton import S | |
| from sympy.core.symbol import Dummy | |
| from sympy.functions.elementary.complexes import Abs | |
| from sympy.functions.elementary.exponential import exp | |
| from sympy.functions.special.gamma_functions import gamma | |
| from sympy.integrals.integrals import Integral | |
| from sympy.matrices.expressions.matexpr import MatrixSymbol | |
| from sympy.matrices.expressions.trace import Trace | |
| from sympy.tensor.indexed import IndexedBase | |
| from sympy.core.sympify import _sympify | |
| from sympy.stats.rv import _symbol_converter, Density, RandomMatrixSymbol, is_random | |
| from sympy.stats.joint_rv_types import JointDistributionHandmade | |
| from sympy.stats.random_matrix import RandomMatrixPSpace | |
| from sympy.tensor.array import ArrayComprehension | |
| __all__ = [ | |
| 'CircularEnsemble', | |
| 'CircularUnitaryEnsemble', | |
| 'CircularOrthogonalEnsemble', | |
| 'CircularSymplecticEnsemble', | |
| 'GaussianEnsemble', | |
| 'GaussianUnitaryEnsemble', | |
| 'GaussianOrthogonalEnsemble', | |
| 'GaussianSymplecticEnsemble', | |
| 'joint_eigen_distribution', | |
| 'JointEigenDistribution', | |
| 'level_spacing_distribution' | |
| ] | |
| def _(x): | |
| return True | |
| class RandomMatrixEnsembleModel(Basic): | |
| """ | |
| Base class for random matrix ensembles. | |
| It acts as an umbrella and contains | |
| the methods common to all the ensembles | |
| defined in sympy.stats.random_matrix_models. | |
| """ | |
| def __new__(cls, sym, dim=None): | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| if dim.is_integer == False: | |
| raise ValueError("Dimension of the random matrices must be " | |
| "integers, received %s instead."%(dim)) | |
| return Basic.__new__(cls, sym, dim) | |
| symbol = property(lambda self: self.args[0]) | |
| dimension = property(lambda self: self.args[1]) | |
| def density(self, expr): | |
| return Density(expr) | |
| def __call__(self, expr): | |
| return self.density(expr) | |
| class GaussianEnsembleModel(RandomMatrixEnsembleModel): | |
| """ | |
| Abstract class for Gaussian ensembles. | |
| Contains the properties common to all the | |
| gaussian ensembles. | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Random_matrix#Gaussian_ensembles | |
| .. [2] https://arxiv.org/pdf/1712.07903.pdf | |
| """ | |
| def _compute_normalization_constant(self, beta, n): | |
| """ | |
| Helper function for computing normalization | |
| constant for joint probability density of eigen | |
| values of Gaussian ensembles. | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Selberg_integral#Mehta's_integral | |
| """ | |
| n = S(n) | |
| prod_term = lambda j: gamma(1 + beta*S(j)/2)/gamma(S.One + beta/S(2)) | |
| j = Dummy('j', integer=True, positive=True) | |
| term1 = Product(prod_term(j), (j, 1, n)).doit() | |
| term2 = (2/(beta*n))**(beta*n*(n - 1)/4 + n/2) | |
| term3 = (2*pi)**(n/2) | |
| return term1 * term2 * term3 | |
| def _compute_joint_eigen_distribution(self, beta): | |
| """ | |
| Helper function for computing the joint | |
| probability distribution of eigen values | |
| of the random matrix. | |
| """ | |
| n = self.dimension | |
| Zbn = self._compute_normalization_constant(beta, n) | |
| l = IndexedBase('l') | |
| i = Dummy('i', integer=True, positive=True) | |
| j = Dummy('j', integer=True, positive=True) | |
| k = Dummy('k', integer=True, positive=True) | |
| term1 = exp((-S(n)/2) * Sum(l[k]**2, (k, 1, n)).doit()) | |
| sub_term = Lambda(i, Product(Abs(l[j] - l[i])**beta, (j, i + 1, n))) | |
| term2 = Product(sub_term(i).doit(), (i, 1, n - 1)).doit() | |
| syms = ArrayComprehension(l[k], (k, 1, n)).doit() | |
| return Lambda(tuple(syms), (term1 * term2)/Zbn) | |
| class GaussianUnitaryEnsembleModel(GaussianEnsembleModel): | |
| def normalization_constant(self): | |
| n = self.dimension | |
| return 2**(S(n)/2) * pi**(S(n**2)/2) | |
| def density(self, expr): | |
| n, ZGUE = self.dimension, self.normalization_constant | |
| h_pspace = RandomMatrixPSpace('P', model=self) | |
| H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) | |
| return Lambda(H, exp(-S(n)/2 * Trace(H**2))/ZGUE)(expr) | |
| def joint_eigen_distribution(self): | |
| return self._compute_joint_eigen_distribution(S(2)) | |
| def level_spacing_distribution(self): | |
| s = Dummy('s') | |
| f = (32/pi**2)*(s**2)*exp((-4/pi)*s**2) | |
| return Lambda(s, f) | |
| class GaussianOrthogonalEnsembleModel(GaussianEnsembleModel): | |
| def normalization_constant(self): | |
| n = self.dimension | |
| _H = MatrixSymbol('_H', n, n) | |
| return Integral(exp(-S(n)/4 * Trace(_H**2))) | |
| def density(self, expr): | |
| n, ZGOE = self.dimension, self.normalization_constant | |
| h_pspace = RandomMatrixPSpace('P', model=self) | |
| H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) | |
| return Lambda(H, exp(-S(n)/4 * Trace(H**2))/ZGOE)(expr) | |
| def joint_eigen_distribution(self): | |
| return self._compute_joint_eigen_distribution(S.One) | |
| def level_spacing_distribution(self): | |
| s = Dummy('s') | |
| f = (pi/2)*s*exp((-pi/4)*s**2) | |
| return Lambda(s, f) | |
| class GaussianSymplecticEnsembleModel(GaussianEnsembleModel): | |
| def normalization_constant(self): | |
| n = self.dimension | |
| _H = MatrixSymbol('_H', n, n) | |
| return Integral(exp(-S(n) * Trace(_H**2))) | |
| def density(self, expr): | |
| n, ZGSE = self.dimension, self.normalization_constant | |
| h_pspace = RandomMatrixPSpace('P', model=self) | |
| H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) | |
| return Lambda(H, exp(-S(n) * Trace(H**2))/ZGSE)(expr) | |
| def joint_eigen_distribution(self): | |
| return self._compute_joint_eigen_distribution(S(4)) | |
| def level_spacing_distribution(self): | |
| s = Dummy('s') | |
| f = ((S(2)**18)/((S(3)**6)*(pi**3)))*(s**4)*exp((-64/(9*pi))*s**2) | |
| return Lambda(s, f) | |
| def GaussianEnsemble(sym, dim): | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| model = GaussianEnsembleModel(sym, dim) | |
| rmp = RandomMatrixPSpace(sym, model=model) | |
| return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) | |
| def GaussianUnitaryEnsemble(sym, dim): | |
| """ | |
| Represents Gaussian Unitary Ensembles. | |
| Examples | |
| ======== | |
| >>> from sympy.stats import GaussianUnitaryEnsemble as GUE, density | |
| >>> from sympy import MatrixSymbol | |
| >>> G = GUE('U', 2) | |
| >>> X = MatrixSymbol('X', 2, 2) | |
| >>> density(G)(X) | |
| exp(-Trace(X**2))/(2*pi**2) | |
| """ | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| model = GaussianUnitaryEnsembleModel(sym, dim) | |
| rmp = RandomMatrixPSpace(sym, model=model) | |
| return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) | |
| def GaussianOrthogonalEnsemble(sym, dim): | |
| """ | |
| Represents Gaussian Orthogonal Ensembles. | |
| Examples | |
| ======== | |
| >>> from sympy.stats import GaussianOrthogonalEnsemble as GOE, density | |
| >>> from sympy import MatrixSymbol | |
| >>> G = GOE('U', 2) | |
| >>> X = MatrixSymbol('X', 2, 2) | |
| >>> density(G)(X) | |
| exp(-Trace(X**2)/2)/Integral(exp(-Trace(_H**2)/2), _H) | |
| """ | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| model = GaussianOrthogonalEnsembleModel(sym, dim) | |
| rmp = RandomMatrixPSpace(sym, model=model) | |
| return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) | |
| def GaussianSymplecticEnsemble(sym, dim): | |
| """ | |
| Represents Gaussian Symplectic Ensembles. | |
| Examples | |
| ======== | |
| >>> from sympy.stats import GaussianSymplecticEnsemble as GSE, density | |
| >>> from sympy import MatrixSymbol | |
| >>> G = GSE('U', 2) | |
| >>> X = MatrixSymbol('X', 2, 2) | |
| >>> density(G)(X) | |
| exp(-2*Trace(X**2))/Integral(exp(-2*Trace(_H**2)), _H) | |
| """ | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| model = GaussianSymplecticEnsembleModel(sym, dim) | |
| rmp = RandomMatrixPSpace(sym, model=model) | |
| return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) | |
| class CircularEnsembleModel(RandomMatrixEnsembleModel): | |
| """ | |
| Abstract class for Circular ensembles. | |
| Contains the properties and methods | |
| common to all the circular ensembles. | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Circular_ensemble | |
| """ | |
| def density(self, expr): | |
| # TODO : Add support for Lie groups(as extensions of sympy.diffgeom) | |
| # and define measures on them | |
| raise NotImplementedError("Support for Haar measure hasn't been " | |
| "implemented yet, therefore the density of " | |
| "%s cannot be computed."%(self)) | |
| def _compute_joint_eigen_distribution(self, beta): | |
| """ | |
| Helper function to compute the joint distribution of phases | |
| of the complex eigen values of matrices belonging to any | |
| circular ensembles. | |
| """ | |
| n = self.dimension | |
| Zbn = ((2*pi)**n)*(gamma(beta*n/2 + 1)/S(gamma(beta/2 + 1))**n) | |
| t = IndexedBase('t') | |
| i, j, k = (Dummy('i', integer=True), Dummy('j', integer=True), | |
| Dummy('k', integer=True)) | |
| syms = ArrayComprehension(t[i], (i, 1, n)).doit() | |
| f = Product(Product(Abs(exp(I*t[k]) - exp(I*t[j]))**beta, (j, k + 1, n)).doit(), | |
| (k, 1, n - 1)).doit() | |
| return Lambda(tuple(syms), f/Zbn) | |
| class CircularUnitaryEnsembleModel(CircularEnsembleModel): | |
| def joint_eigen_distribution(self): | |
| return self._compute_joint_eigen_distribution(S(2)) | |
| class CircularOrthogonalEnsembleModel(CircularEnsembleModel): | |
| def joint_eigen_distribution(self): | |
| return self._compute_joint_eigen_distribution(S.One) | |
| class CircularSymplecticEnsembleModel(CircularEnsembleModel): | |
| def joint_eigen_distribution(self): | |
| return self._compute_joint_eigen_distribution(S(4)) | |
| def CircularEnsemble(sym, dim): | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| model = CircularEnsembleModel(sym, dim) | |
| rmp = RandomMatrixPSpace(sym, model=model) | |
| return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) | |
| def CircularUnitaryEnsemble(sym, dim): | |
| """ | |
| Represents Circular Unitary Ensembles. | |
| Examples | |
| ======== | |
| >>> from sympy.stats import CircularUnitaryEnsemble as CUE | |
| >>> from sympy.stats import joint_eigen_distribution | |
| >>> C = CUE('U', 1) | |
| >>> joint_eigen_distribution(C) | |
| Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k]))**2, (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) | |
| Note | |
| ==== | |
| As can be seen above in the example, density of CiruclarUnitaryEnsemble | |
| is not evaluated because the exact definition is based on haar measure of | |
| unitary group which is not unique. | |
| """ | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| model = CircularUnitaryEnsembleModel(sym, dim) | |
| rmp = RandomMatrixPSpace(sym, model=model) | |
| return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) | |
| def CircularOrthogonalEnsemble(sym, dim): | |
| """ | |
| Represents Circular Orthogonal Ensembles. | |
| Examples | |
| ======== | |
| >>> from sympy.stats import CircularOrthogonalEnsemble as COE | |
| >>> from sympy.stats import joint_eigen_distribution | |
| >>> C = COE('O', 1) | |
| >>> joint_eigen_distribution(C) | |
| Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k])), (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) | |
| Note | |
| ==== | |
| As can be seen above in the example, density of CiruclarOrthogonalEnsemble | |
| is not evaluated because the exact definition is based on haar measure of | |
| unitary group which is not unique. | |
| """ | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| model = CircularOrthogonalEnsembleModel(sym, dim) | |
| rmp = RandomMatrixPSpace(sym, model=model) | |
| return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) | |
| def CircularSymplecticEnsemble(sym, dim): | |
| """ | |
| Represents Circular Symplectic Ensembles. | |
| Examples | |
| ======== | |
| >>> from sympy.stats import CircularSymplecticEnsemble as CSE | |
| >>> from sympy.stats import joint_eigen_distribution | |
| >>> C = CSE('S', 1) | |
| >>> joint_eigen_distribution(C) | |
| Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k]))**4, (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) | |
| Note | |
| ==== | |
| As can be seen above in the example, density of CiruclarSymplecticEnsemble | |
| is not evaluated because the exact definition is based on haar measure of | |
| unitary group which is not unique. | |
| """ | |
| sym, dim = _symbol_converter(sym), _sympify(dim) | |
| model = CircularSymplecticEnsembleModel(sym, dim) | |
| rmp = RandomMatrixPSpace(sym, model=model) | |
| return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) | |
| def joint_eigen_distribution(mat): | |
| """ | |
| For obtaining joint probability distribution | |
| of eigen values of random matrix. | |
| Parameters | |
| ========== | |
| mat: RandomMatrixSymbol | |
| The matrix symbol whose eigen values are to be considered. | |
| Returns | |
| ======= | |
| Lambda | |
| Examples | |
| ======== | |
| >>> from sympy.stats import GaussianUnitaryEnsemble as GUE | |
| >>> from sympy.stats import joint_eigen_distribution | |
| >>> U = GUE('U', 2) | |
| >>> joint_eigen_distribution(U) | |
| Lambda((l[1], l[2]), exp(-l[1]**2 - l[2]**2)*Product(Abs(l[_i] - l[_j])**2, (_j, _i + 1, 2), (_i, 1, 1))/pi) | |
| """ | |
| if not isinstance(mat, RandomMatrixSymbol): | |
| raise ValueError("%s is not of type, RandomMatrixSymbol."%(mat)) | |
| return mat.pspace.model.joint_eigen_distribution() | |
| def JointEigenDistribution(mat): | |
| """ | |
| Creates joint distribution of eigen values of matrices with random | |
| expressions. | |
| Parameters | |
| ========== | |
| mat: Matrix | |
| The matrix under consideration. | |
| Returns | |
| ======= | |
| JointDistributionHandmade | |
| Examples | |
| ======== | |
| >>> from sympy.stats import Normal, JointEigenDistribution | |
| >>> from sympy import Matrix | |
| >>> A = [[Normal('A00', 0, 1), Normal('A01', 0, 1)], | |
| ... [Normal('A10', 0, 1), Normal('A11', 0, 1)]] | |
| >>> JointEigenDistribution(Matrix(A)) | |
| JointDistributionHandmade(-sqrt(A00**2 - 2*A00*A11 + 4*A01*A10 + A11**2)/2 | |
| + A00/2 + A11/2, sqrt(A00**2 - 2*A00*A11 + 4*A01*A10 + A11**2)/2 + A00/2 + A11/2) | |
| """ | |
| eigenvals = mat.eigenvals(multiple=True) | |
| if not all(is_random(eigenval) for eigenval in set(eigenvals)): | |
| raise ValueError("Eigen values do not have any random expression, " | |
| "joint distribution cannot be generated.") | |
| return JointDistributionHandmade(*eigenvals) | |
| def level_spacing_distribution(mat): | |
| """ | |
| For obtaining distribution of level spacings. | |
| Parameters | |
| ========== | |
| mat: RandomMatrixSymbol | |
| The random matrix symbol whose eigen values are | |
| to be considered for finding the level spacings. | |
| Returns | |
| ======= | |
| Lambda | |
| Examples | |
| ======== | |
| >>> from sympy.stats import GaussianUnitaryEnsemble as GUE | |
| >>> from sympy.stats import level_spacing_distribution | |
| >>> U = GUE('U', 2) | |
| >>> level_spacing_distribution(U) | |
| Lambda(_s, 32*_s**2*exp(-4*_s**2/pi)/pi**2) | |
| References | |
| ========== | |
| .. [1] https://en.wikipedia.org/wiki/Random_matrix#Distribution_of_level_spacings | |
| """ | |
| return mat.pspace.model.level_spacing_distribution() | |