Coverage for geometric_kernels/spaces/base.py: 74%

57 statements  

« prev     ^ index     » next       coverage.py v7.11.3, created at 2025-11-16 21:43 +0000

1""" 

2Abstract base classes for all spaces (input domains) in the library. 

3""" 

4 

5import abc 

6 

7import lab as B 

8from beartype.typing import List, Optional 

9 

10from geometric_kernels.spaces.eigenfunctions import Eigenfunctions 

11 

12 

13class Space(abc.ABC): 

14 """ 

15 A space (input domain) on which a geometric kernel can be defined. 

16 """ 

17 

18 @abc.abstractproperty 

19 def dimension(self) -> int: 

20 """ 

21 Geometric dimension of the space. 

22 

23 Examples: 

24 

25 * :class:`~.spaces.Graph`: 0-dimensional. 

26 * :class:`~.spaces.Circle`: 1-dimensional. 

27 * :class:`~.spaces.Hypersphere`: d-dimensional, with d >= 2. 

28 * :class:`~.spaces.Hyperbolic`: d-dimensional, with d >= 2. 

29 """ 

30 raise NotImplementedError 

31 

32 @abc.abstractproperty 

33 def element_shape(self) -> List[int]: 

34 """ 

35 Shape of an element. 

36 

37 Examples: 

38 * :class:`~.spaces.Hypersphere`: [D + 1, ] 

39 * :class:`~.spaces.Mesh`: [1, ] 

40 * :class:`~.spaces.CompactMatrixLieGroup`: [n, n] 

41 """ 

42 raise NotImplementedError 

43 

44 @abc.abstractproperty 

45 def element_dtype(self) -> B.DType: 

46 """ 

47 Abstract DType of an element. 

48 

49 Examples: 

50 * :class:`~.spaces.Hypersphere`: B.Float 

51 * :class:`~.spaces.Mesh`: B.Int 

52 * :class:`~.spaces.SpecialUnitary`: B.Complex 

53 """ 

54 raise NotImplementedError 

55 

56 

57class DiscreteSpectrumSpace(Space): 

58 r""" 

59 A Space with discrete spectrum (of the Laplacian operator). 

60 

61 This includes, for instance, compact Riemannian manifolds, graphs & meshes. 

62 

63 Subclasses implement routines for computing the eigenvalues and 

64 eigenfunctions of the Laplacian operator, or certain combinations thereof. 

65 Since there is often an infinite or a prohibitively large number of those, 

66 they only compute a finite subset, consisting of the ones that are most 

67 important for approximating Matérn kernel best. 

68 

69 .. note:: 

70 See a brief introduction into the theory behind the geometric 

71 kernels on discrete spectrum spaces on the documentation pages devoted 

72 to :doc:`compact Riemannian manifolds </theory/compact>` (also 

73 :doc:`this </theory/addition_theorem>`), :doc:`graphs 

74 </theory/graphs>` and :doc:`meshes </theory/meshes>`. 

75 

76 .. note:: 

77 Typically used with :class:`~.kernels.MaternKarhunenLoeveKernel`. 

78 

79 """ 

80 

81 @abc.abstractproperty 

82 def dimension(self) -> int: 

83 """ 

84 Geometric dimension of the space. 

85 

86 Examples: 

87 

88 * :class:`~.spaces.Graph`: 0-dimensional. 

89 * :class:`~.spaces.Circle`: 1-dimensional. 

90 * :class:`~.spaces.Hypersphere`: d-dimensional, with d >= 2. 

91 """ 

92 raise NotImplementedError 

93 

94 @abc.abstractmethod 

95 def get_eigenfunctions(self, num: int) -> Eigenfunctions: 

96 """ 

97 Returns the :class:`~.Eigenfunctions` object with `num` levels. 

98 

99 :param num: 

100 Number of levels. 

101 

102 .. note:: 

103 The notion of *levels* is discussed in the documentation of the 

104 :class:`~.kernels.MaternKarhunenLoeveKernel`. 

105 """ 

106 raise NotImplementedError 

107 

108 @abc.abstractmethod 

109 def get_eigenvalues(self, num: int) -> B.Numeric: 

110 """ 

111 Eigenvalues of the Laplacian corresponding to the first `num` levels. 

112 

113 :param num: 

114 Number of levels. 

115 :return: 

116 (num, 1)-shaped array containing the eigenvalues. 

117 

118 .. note:: 

119 The notion of *levels* is discussed in the documentation of the 

120 :class:`~.kernels.MaternKarhunenLoeveKernel`. 

121 """ 

122 raise NotImplementedError 

123 

124 @abc.abstractmethod 

125 def get_repeated_eigenvalues(self, num: int) -> B.Numeric: 

126 """ 

127 Eigenvalues of the Laplacian corresponding to the first `num` levels, 

128 repeated according to their multiplicity within levels. 

129 

130 :param num: 

131 Number of levels. 

132 

133 :return: 

134 (J, 1)-shaped array containing the repeated eigenvalues, J is 

135 the resulting number of the repeated eigenvalues. 

136 

137 .. note:: 

138 The notion of *levels* is discussed in the documentation of the 

139 :class:`~.kernels.MaternKarhunenLoeveKernel`. 

140 """ 

141 raise NotImplementedError 

142 

143 @abc.abstractmethod 

144 def random(self, key: B.RandomState, number: int) -> B.Numeric: 

145 """ 

146 Sample uniformly random points in the space. 

147 

148 :param key: 

149 Either `np.random.RandomState`, `tf.random.Generator`, 

150 `torch.Generator` or `jax.tensor` (representing random state). 

151 :param number: 

152 Number of samples to draw. 

153 

154 :return: 

155 An array of `number` uniformly random samples on the space. 

156 """ 

157 raise NotImplementedError 

158 

159 

160class HodgeDiscreteSpectrumSpace(DiscreteSpectrumSpace): 

161 r""" 

162 A Space with discrete spectrum (of the Laplacian) and Hodge decomposition. 

163 

164 Separates eigenpairs according to the Hodge decomposition, into the curl 

165 type (divergence-free), the gradient type (curl-free), and the harmonic 

166 type (both divergence- and curl-free). 

167 

168 Examples of such spaces are the edge space of a graph, or tangent bundles 

169 of compact Riemannian manifolds. 

170 

171 .. note:: 

172 Hodge decomposition is briefly discussed on :doc:`this </theory/graphs>` 

173 documentation page. 

174 

175 .. note:: 

176 Typically used with :class:`~.kernels.MaternHodgeCompositionalKernel`. 

177 """ 

178 

179 @abc.abstractmethod 

180 def get_eigenfunctions( 

181 self, num: int, type: Optional[str] = None 

182 ) -> Eigenfunctions: 

183 """ 

184 Returns the :class:`~.Eigenfunctions` object with `num` levels. 

185 If `type` is specified, returns only the eigenfunctions of that type. 

186 

187 .. warning:: 

188 If `type` is specified, the returned :class:`~.Eigenfunctions` 

189 object does not have to have `num` levels. It can have fewer but can 

190 never have more. 

191 

192 :param num: 

193 Number of levels. 

194 

195 :param type: 

196 Type of the eigenfunctions to return. Can be one of "harmonic", 

197 "curl" or "gradient". 

198 

199 .. note:: 

200 The notion of *levels* is discussed in the documentation of the 

201 :class:`~.kernels.MaternKarhunenLoeveKernel`. 

202 """ 

203 raise NotImplementedError 

204 

205 @abc.abstractmethod 

206 def get_eigenvalues(self, num: int, type: Optional[str] = None) -> B.Numeric: 

207 """ 

208 Eigenvalues of the Laplacian corresponding to the first `num` levels. 

209 If `type` is specified, returns only the eigenvalues corresponding to 

210 the eigenfunctions of that type. 

211 

212 .. warning:: 

213 If `type` is specified, the array can have fewer than `num` elements. 

214 

215 :param num: 

216 Number of levels. 

217 

218 :return: 

219 (n, 1)-shaped array containing the eigenvalues. n <= num. 

220 

221 .. note:: 

222 The notion of *levels* is discussed in the documentation of the 

223 :class:`~.kernels.MaternKarhunenLoeveKernel`. 

224 """ 

225 raise NotImplementedError 

226 

227 @abc.abstractmethod 

228 def get_repeated_eigenvalues( 

229 self, num: int, type: Optional[str] = None 

230 ) -> B.Numeric: 

231 """ 

232 Eigenvalues of the Laplacian corresponding to the first `num` levels, 

233 repeated according to their multiplicity within levels. If `type` is 

234 specified, returns only the eigenvalues corresponding to the 

235 eigenfunctions of that type. 

236 

237 :param num: 

238 Number of levels. 

239 

240 :param type: 

241 Type of the eigenvalues to return. Can be one of "harmonic", 

242 "curl" or "gradient". 

243 

244 :return: 

245 (J, 1)-shaped array containing the repeated eigenvalues, J is 

246 the resulting number of the repeated eigenvalues (of the specified 

247 type, if `type` is given). 

248 

249 .. note:: 

250 The notion of *levels* is discussed in the documentation of the 

251 :class:`~.kernels.MaternKarhunenLoeveKernel`. 

252 """ 

253 raise NotImplementedError 

254 

255 

256class NoncompactSymmetricSpace(Space): 

257 """ 

258 Non-compact symmetric space. 

259 

260 This includes, for instance, hyperbolic spaces and manifolds of symmetric 

261 positive definite matrices (endowed with the affine-invariant metric). 

262 

263 .. note:: 

264 See a brief introduction into the theory behind the geometric 

265 kernels on non-compact symmetric spaces on the 

266 :doc:`respective documentation page </theory/symmetric>`. 

267 

268 .. note:: 

269 Typically used with :class:`~.kernels.MaternFeatureMapKernel` that 

270 builds on a space-specific feature map like the 

271 :class:`~.feature_maps.RejectionSamplingFeatureMapHyperbolic` and the 

272 :class:`~.feature_maps.RejectionSamplingFeatureMapSPD`, or, in the 

273 absence of a space-specific feature map, on the general (typically less 

274 effective) map :class:`~.feature_maps.RandomPhaseFeatureMapNoncompact`. 

275 

276 .. note:: .. _quotient note: 

277 

278 Mathematically, any non-compact symmetric space can be represented as 

279 a quotient $G/H$ of a Lie group of symmetries $G$ and its compact 

280 isotropy subgroup $H$. We sometimes refer to these $G$ and $H$ in 

281 the documentation. See mathematical details in :cite:t:`azangulov2024b`. 

282 """ 

283 

284 @abc.abstractproperty 

285 def dimension(self) -> int: 

286 """ 

287 Geometric dimension of the space. 

288 

289 Examples: 

290 

291 * :class:`~.spaces.Hyperbolic`: d-dimensional, with d >= 2. 

292 * :class:`~.spaces.SymmetricPositiveDefiniteMatrices`: $n(n+1)/2$-dimensional, 

293 with n >= 2. 

294 """ 

295 raise NotImplementedError 

296 

297 @abc.abstractmethod 

298 def inv_harish_chandra(self, lam: B.Numeric) -> B.Numeric: 

299 r""" 

300 Implements $c^{-1}(\lambda)$, where $c$ is the Harish-Chandra's $c$ 

301 function. 

302 

303 This is one of the computational primitives required to (approximately) 

304 compute the :class:`~.feature_maps.RandomPhaseFeatureMapNoncompact` 

305 feature map and :class:`~.kernels.MaternFeatureMapKernel` on top of it. 

306 

307 :param lam: 

308 A batch of frequencies, vectors of dimension equal to the rank of 

309 symmetric space. 

310 

311 :return: 

312 $c^{-1}(\lambda)$ evaluated at every $\lambda$ in the batch `lam`. 

313 """ 

314 raise NotImplementedError 

315 

316 @abc.abstractmethod 

317 def power_function(self, lam: B.Numeric, g: B.Numeric, h: B.Numeric) -> B.Numeric: 

318 r""" 

319 Implements the *power function* $p^{\lambda}(g, h)$, the integrand 

320 appearing in the definition of the zonal spherical function 

321 

322 .. math:: \pi^{\lambda}(g) = \int_{H} \underbrace{p^{\lambda}(g, h)}_{= e^{(i \lambda + \rho) a(h \cdot g)}} d h, 

323 

324 where $\lambda \in i \cdot \mathbb{R}^r$, with $r$ denoting the rank of 

325 the symmetric space and $i$ the imaginary unit, is a sort of frequency, 

326 $g$ is an element of the group of symmetries $G$, $h$ is an element 

327 of its isotropy subgroup $H$ ($G$ and $H$ are defined :ref:`here 

328 <quotient note>`), $\rho \in \mathbb{R}^r$ is as in :meth:`rho`, and 

329 the function $a$ is a certain space-dependent algebraic operation. 

330 

331 This is one of the computational primitives required to (approximately) 

332 compute the :class:`~.feature_maps.RandomPhaseFeatureMapNoncompact` 

333 feature map and :class:`~.kernels.MaternFeatureMapKernel` on top of it. 

334 

335 :param lam: 

336 A batch of L vectors of dimension `rank`, the rank of the 

337 symmetric space, representing the "sort of frequencies". 

338 

339 Typically of shape [1, L, rank]. 

340 :param g: 

341 A batch of N elements of the space (these can always be thought of 

342 as elements of the group of symmetries $G$ since the symmetric 

343 space $G/H$ can be trivially embedded into the group $G$). 

344 

345 Typically of shape [N, 1, <axes>], where <axes> is the shape of 

346 the elements of the space. 

347 :param h: 

348 A batch of L elements of the isotropy subgroup $H$. 

349 

350 Typically of shape [1, L, <axes_p>], where <axes_p> is the shape of 

351 arrays representing the elements of the isotropy subgroup $H$. 

352 

353 :return: 

354 An array of shape [N, L] with complex number entries, representing 

355 the value of the values of $p^{\lambda_l}(g_n, h_l)$ for all 

356 $1 \leq n \leq N$ and $1 \leq l \leq L$. 

357 

358 .. note:: 

359 Actually, $a$ may be a more appropriate primitive than the power 

360 function $p^{\lambda}$: everything but $a$ in the definition of 

361 the latter is either standard or available as other primitives. 

362 Us using $p^{\lambda}$ as a primitive is quite arbitrary. 

363 """ 

364 raise NotImplementedError 

365 

366 @abc.abstractproperty 

367 def rho(self): 

368 r""" 

369 `rho` vector of dimension equal to the rank of the symmetric space. 

370 

371 Algebraically, weighted sum of *roots*, depends only on the space. 

372 

373 This is one of the computational primitives required to (approximately) 

374 compute the :class:`~.feature_maps.RandomPhaseFeatureMapNoncompact` 

375 feature map and :class:`~.kernels.MaternFeatureMapKernel` on top of it. 

376 """ 

377 raise NotImplementedError 

378 

379 @abc.abstractmethod 

380 def random_phases(self, key: B.RandomState, num: int) -> B.Numeric: 

381 r""" 

382 Sample uniformly random points on the isotropy subgroup $H$ (defined 

383 :ref:`here <quotient note>`). 

384 

385 This is one of the computational primitives required to (approximately) 

386 compute the :class:`~.feature_maps.RandomPhaseFeatureMapNoncompact` 

387 feature map and :class:`~.kernels.MaternFeatureMapKernel` on top of it. 

388 

389 :param key: 

390 Either `np.random.RandomState`, `tf.random.Generator`, 

391 `torch.Generator` or `jax.tensor` (representing random state). 

392 :param num: 

393 Number of samples to draw. 

394 

395 :return: 

396 An array of `num` uniformly random samples in the isotropy 

397 subgroup $H$. 

398 

399 .. warning:: 

400 This does not sample random points on the space itself. Since the 

401 space itself is non-compact, uniform sampling on it is in principle 

402 impossible. However, the isotropy subgroup $H$ is always 

403 compact and thus allows uniform sampling needed to approximate the 

404 zonal spherical functions $\pi^{\lambda}(\cdot)$ via Monte Carlo. 

405 """ 

406 

407 @abc.abstractproperty 

408 def num_axes(self): 

409 """ 

410 Number of axes in an array representing a point in the space. 

411 

412 Usually 1 for vectors or 2 for matrices. 

413 """