Coverage for src / chebpy / onefun.py: 100%

4 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-22 21:33 +0000

1"""Abstract base class for functions defined on the standard interval [-1, 1]. 

2 

3This module provides the Onefun abstract base class, which defines the interface for 

4all function representations on the standard interval [-1, 1] in ChebPy. It specifies 

5the methods and properties that concrete function classes must implement. 

6 

7The Onefun class serves as the foundation for representing functions on the standard 

8interval, with concrete implementations like Chebtech inheriting from it. Functions 

9defined on arbitrary intervals are typically mapped to this standard interval for 

10internal representation and manipulation. 

11""" 

12 

13from abc import ABC, abstractmethod 

14from typing import Any 

15 

16import numpy as np 

17 

18 

19class Onefun(ABC): 

20 """Abstract base class for functions defined on the interval [-1, 1]. 

21 

22 This class defines the interface for all function representations on the 

23 standard interval [-1, 1]. It serves as the base class for specific 

24 implementations like Chebtech. 

25 

26 Concrete subclasses must implement all the abstract methods defined here, 

27 which include constructors, algebraic operations, calculus operations, 

28 and utility functions. 

29 """ 

30 

31 # -------------------------- 

32 # alternative constructors 

33 # -------------------------- 

34 @classmethod 

35 @abstractmethod 

36 def initconst(cls, c: float) -> "Onefun": # pragma: no cover 

37 """Initialize a constant function. 

38 

39 This constructor creates a function that represents a constant value 

40 on the interval [-1, 1]. 

41 

42 Args: 

43 c: The constant value. 

44 

45 Returns: 

46 Onefun: A new instance representing the constant function f(x) = c. 

47 """ 

48 raise NotImplementedError 

49 

50 @classmethod 

51 @abstractmethod 

52 def initempty(cls) -> "Onefun": # pragma: no cover 

53 """Initialize an empty function. 

54 

55 This constructor creates an empty function representation, which is 

56 useful as a placeholder or for special cases. 

57 

58 Returns: 

59 Onefun: A new empty instance. 

60 """ 

61 raise NotImplementedError 

62 

63 @classmethod 

64 @abstractmethod 

65 def initidentity(cls) -> "Onefun": # pragma: no cover 

66 """Initialize the identity function f(x) = x. 

67 

68 This constructor creates a function that represents f(x) = x 

69 on the interval [-1, 1]. 

70 

71 Returns: 

72 Onefun: A new instance representing the identity function. 

73 """ 

74 raise NotImplementedError 

75 

76 @classmethod 

77 @abstractmethod 

78 def initfun(cls, f: Any, n: Any = None) -> "Onefun": # pragma: no cover 

79 """Initialize from a callable function. 

80 

81 This is a general constructor that delegates to either initfun_adaptive 

82 or initfun_fixedlen based on the provided parameters. 

83 

84 Args: 

85 f (callable): The function to be approximated. 

86 n (int, optional): If provided, specifies the number of points to use. 

87 If None, determines the number adaptively. 

88 

89 Returns: 

90 Onefun: A new instance representing the function f. 

91 """ 

92 raise NotImplementedError 

93 

94 @classmethod 

95 @abstractmethod 

96 def initfun_adaptive(cls, f: Any) -> "Onefun": # pragma: no cover 

97 """Initialize from a callable function using adaptive sampling. 

98 

99 This constructor determines the appropriate number of points needed to 

100 represent the function to a specified tolerance using an adaptive algorithm. 

101 

102 Args: 

103 f (callable): The function to be approximated. 

104 

105 Returns: 

106 Onefun: A new instance representing the function f. 

107 """ 

108 raise NotImplementedError 

109 

110 @classmethod 

111 @abstractmethod 

112 def initfun_fixedlen(cls, f: Any, n: int) -> "Onefun": # pragma: no cover 

113 """Initialize from a callable function using a fixed number of points. 

114 

115 This constructor uses a specified number of points to represent the function, 

116 rather than determining the number adaptively. 

117 

118 Args: 

119 f (callable): The function to be approximated. 

120 n (int): The number of points to use. 

121 

122 Returns: 

123 Onefun: A new instance representing the function f. 

124 """ 

125 raise NotImplementedError 

126 

127 @classmethod 

128 @abstractmethod 

129 def initvalues(cls, values: Any) -> "Onefun": # pragma: no cover 

130 """Initialize from function values at Chebyshev points. 

131 

132 This constructor creates a function representation from values 

133 at Chebyshev points. 

134 

135 Args: 

136 values: Function values at Chebyshev points. 

137 

138 Returns: 

139 Onefun: A new instance representing the function with the given values. 

140 """ 

141 raise NotImplementedError 

142 

143 # ------------------- 

144 # "private" methods 

145 # ------------------- 

146 @abstractmethod 

147 def __call__(self, x: Any) -> Any: # pragma: no cover 

148 """Evaluate the function at points x. 

149 

150 This method evaluates the function at the specified points. 

151 

152 Args: 

153 x (float or array-like): Points at which to evaluate the function. 

154 These should be in the interval [-1, 1]. 

155 

156 Returns: 

157 float or array-like: The value(s) of the function at the specified point(s). 

158 Returns a scalar if x is a scalar, otherwise an array of the same size as x. 

159 """ 

160 raise NotImplementedError 

161 

162 @abstractmethod 

163 def __init__(self) -> None: # pragma: no cover 

164 """Initialize a new Onefun instance. 

165 

166 This method initializes a new function representation on the interval [-1, 1]. 

167 The specific initialization depends on the concrete subclass implementation. 

168 """ 

169 raise NotImplementedError 

170 

171 @abstractmethod 

172 def __repr__(self) -> str: # pragma: no cover 

173 """Return a string representation of the function. 

174 

175 This method returns a string representation of the function that includes 

176 relevant information about its representation. 

177 

178 Returns: 

179 str: A string representation of the function. 

180 """ 

181 raise NotImplementedError 

182 

183 # ---------------- 

184 # algebra 

185 # ---------------- 

186 @abstractmethod 

187 def __add__(self, other: Any) -> "Onefun": # pragma: no cover 

188 """Add this function with another function or a scalar. 

189 

190 This method implements the addition operation between this function 

191 and another function or a scalar. 

192 

193 Args: 

194 other (Onefun or scalar): The function or scalar to add to this function. 

195 

196 Returns: 

197 Onefun: A new function representing the sum. 

198 """ 

199 raise NotImplementedError 

200 

201 @abstractmethod 

202 def __mul__(self, other: Any) -> "Onefun": # pragma: no cover 

203 """Multiply this function with another function or a scalar. 

204 

205 This method implements the multiplication operation between this function 

206 and another function or a scalar. 

207 

208 Args: 

209 other (Onefun or scalar): The function or scalar to multiply with this function. 

210 

211 Returns: 

212 Onefun: A new function representing the product. 

213 """ 

214 raise NotImplementedError 

215 

216 @abstractmethod 

217 def __neg__(self) -> "Onefun": # pragma: no cover 

218 """Return the negative of this function. 

219 

220 This method implements the unary negation operation for this function. 

221 

222 Returns: 

223 Onefun: A new function representing -f(x). 

224 """ 

225 raise NotImplementedError 

226 

227 @abstractmethod 

228 def __pos__(self) -> "Onefun": # pragma: no cover 

229 """Return the positive of this function (which is the function itself). 

230 

231 This method implements the unary plus operation for this function. 

232 

233 Returns: 

234 Onefun: This function object (unchanged). 

235 """ 

236 raise NotImplementedError 

237 

238 @abstractmethod 

239 def __pow__(self, power: Any) -> "Onefun": # pragma: no cover 

240 """Raise this function to a power. 

241 

242 This method implements the power operation for this function. 

243 

244 Args: 

245 power (int, float, or Onefun): The exponent to which this function is raised. 

246 

247 Returns: 

248 Onefun: A new function representing f(x)^power. 

249 """ 

250 raise NotImplementedError 

251 

252 @abstractmethod 

253 def __radd__(self, other: Any) -> "Onefun": # pragma: no cover 

254 """Add a scalar or another function to this function (from the right). 

255 

256 This method is called when a scalar or another function is added to this function, 

257 i.e., other + self. 

258 

259 Args: 

260 other (scalar or Onefun): The scalar or function to add to this function. 

261 

262 Returns: 

263 Onefun: A new function representing the sum. 

264 """ 

265 raise NotImplementedError 

266 

267 @abstractmethod 

268 def __rmul__(self, other: Any) -> "Onefun": # pragma: no cover 

269 """Multiply a scalar or another function with this function (from the right). 

270 

271 This method is called when a scalar or another function is multiplied with this function, 

272 i.e., other * self. 

273 

274 Args: 

275 other (scalar or Onefun): The scalar or function to multiply with this function. 

276 

277 Returns: 

278 Onefun: A new function representing the product. 

279 """ 

280 raise NotImplementedError 

281 

282 @abstractmethod 

283 def __rsub__(self, other: Any) -> "Onefun": # pragma: no cover 

284 """Subtract this function from a scalar or another function. 

285 

286 This method is called when this function is subtracted from a scalar or another function, 

287 i.e., other - self. 

288 

289 Args: 

290 other (scalar or Onefun): The scalar or function from which to subtract this function. 

291 

292 Returns: 

293 Onefun: A new function representing the difference. 

294 """ 

295 raise NotImplementedError 

296 

297 @abstractmethod 

298 def __sub__(self, other: Any) -> "Onefun": # pragma: no cover 

299 """Subtract another function or a scalar from this function. 

300 

301 This method implements the subtraction operation between this function 

302 and another function or a scalar. 

303 

304 Args: 

305 other (Onefun or scalar): The function or scalar to subtract from this function. 

306 

307 Returns: 

308 Onefun: A new function representing the difference. 

309 """ 

310 raise NotImplementedError 

311 

312 # --------------- 

313 # properties 

314 # --------------- 

315 @property 

316 @abstractmethod 

317 def coeffs(self) -> np.ndarray: # pragma: no cover 

318 """Get the coefficients of the function representation. 

319 

320 This property returns the coefficients used in the function representation, 

321 such as Chebyshev coefficients for a Chebyshev series. 

322 

323 Returns: 

324 array-like: The coefficients of the function representation. 

325 """ 

326 raise NotImplementedError 

327 

328 @property 

329 @abstractmethod 

330 def isconst(self) -> bool: # pragma: no cover 

331 """Check if this function represents a constant. 

332 

333 This property determines whether the function is constant (i.e., f(x) = c 

334 for some constant c) over the interval [-1, 1]. 

335 

336 Returns: 

337 bool: True if the function is constant, False otherwise. 

338 """ 

339 raise NotImplementedError 

340 

341 @property 

342 @abstractmethod 

343 def isempty(self) -> bool: # pragma: no cover 

344 """Check if this function is empty. 

345 

346 This property determines whether the function is empty, which is a special 

347 state used as a placeholder or for special cases. 

348 

349 Returns: 

350 bool: True if the function is empty, False otherwise. 

351 """ 

352 raise NotImplementedError 

353 

354 @property 

355 @abstractmethod 

356 def size(self) -> int: # pragma: no cover 

357 """Get the size of the function representation. 

358 

359 This property returns the number of coefficients or other measure of the 

360 complexity of the function representation. 

361 

362 Returns: 

363 int: The size of the function representation. 

364 """ 

365 raise NotImplementedError 

366 

367 @property 

368 @abstractmethod 

369 def vscale(self) -> float: # pragma: no cover 

370 """Get the vertical scale of the function. 

371 

372 This property returns a measure of the range of function values, typically 

373 the maximum absolute value of the function on the interval [-1, 1]. 

374 

375 Returns: 

376 float: The vertical scale of the function. 

377 """ 

378 raise NotImplementedError 

379 

380 # --------------- 

381 # utilities 

382 # --------------- 

383 @abstractmethod 

384 def copy(self) -> "Onefun": # pragma: no cover 

385 """Create a deep copy of this function. 

386 

387 This method creates a new function that is a deep copy of this function, 

388 ensuring that modifications to the copy do not affect the original. 

389 

390 Returns: 

391 Onefun: A new function that is a deep copy of this function. 

392 """ 

393 raise NotImplementedError 

394 

395 @abstractmethod 

396 def imag(self) -> "Onefun": # pragma: no cover 

397 """Get the imaginary part of this function. 

398 

399 This method returns a new function representing the imaginary part of this function. 

400 If this function is real-valued, returns a zero function. 

401 

402 Returns: 

403 Onefun: A new function representing the imaginary part of this function. 

404 """ 

405 raise NotImplementedError 

406 

407 @abstractmethod 

408 def prolong(self, n: int) -> "Onefun": # pragma: no cover 

409 """Extend the function representation to a larger size. 

410 

411 This method extends the function representation to use more coefficients 

412 or a higher degree, which can be useful for certain operations. 

413 

414 Args: 

415 n (int): The new size for the function representation. 

416 

417 Returns: 

418 Onefun: A new function with an extended representation. 

419 """ 

420 raise NotImplementedError 

421 

422 @abstractmethod 

423 def real(self) -> "Onefun": # pragma: no cover 

424 """Get the real part of this function. 

425 

426 This method returns a new function representing the real part of this function. 

427 If this function is already real-valued, returns this function. 

428 

429 Returns: 

430 Onefun: A new function representing the real part of this function. 

431 """ 

432 raise NotImplementedError 

433 

434 @abstractmethod 

435 def simplify(self) -> "Onefun": # pragma: no cover 

436 """Simplify the function representation. 

437 

438 This method simplifies the function representation by removing unnecessary 

439 coefficients or reducing the degree, while maintaining the specified accuracy. 

440 

441 Returns: 

442 Onefun: A new function with a simplified representation. 

443 """ 

444 raise NotImplementedError 

445 

446 @abstractmethod 

447 def values(self) -> np.ndarray: # pragma: no cover 

448 """Get the values of the function at Chebyshev points. 

449 

450 This method returns the values of the function at Chebyshev points, 

451 which can be useful for certain operations or for visualization. 

452 

453 Returns: 

454 array-like: The values of the function at Chebyshev points. 

455 """ 

456 raise NotImplementedError 

457 

458 # -------------- 

459 # rootfinding 

460 # -------------- 

461 @abstractmethod 

462 def roots(self) -> np.ndarray: # pragma: no cover 

463 """Find the roots (zeros) of the function on [-1, 1]. 

464 

465 This method computes the points where the function equals zero 

466 within the interval [-1, 1]. 

467 

468 Returns: 

469 array-like: An array of the roots of the function in the interval [-1, 1], 

470 sorted in ascending order. 

471 """ 

472 raise NotImplementedError 

473 

474 # ------------- 

475 # calculus 

476 # ------------- 

477 @abstractmethod 

478 def sum(self) -> float: # pragma: no cover 

479 """Compute the definite integral of the function over [-1, 1]. 

480 

481 This method calculates the definite integral of the function 

482 over the interval [-1, 1]. 

483 

484 Returns: 

485 float or complex: The definite integral of the function over [-1, 1]. 

486 """ 

487 raise NotImplementedError 

488 

489 @abstractmethod 

490 def cumsum(self) -> "Onefun": # pragma: no cover 

491 """Compute the indefinite integral of the function. 

492 

493 This method calculates the indefinite integral (antiderivative) of the function, 

494 with the constant of integration chosen so that the indefinite integral 

495 evaluates to 0 at x = -1. 

496 

497 Returns: 

498 Onefun: A new function representing the indefinite integral of this function. 

499 """ 

500 raise NotImplementedError 

501 

502 @abstractmethod 

503 def diff(self) -> "Onefun": # pragma: no cover 

504 """Compute the derivative of the function. 

505 

506 This method calculates the derivative of the function with respect to x. 

507 

508 Returns: 

509 Onefun: A new function representing the derivative of this function. 

510 """ 

511 raise NotImplementedError