funcprops 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. funcprops/__init__.py +234 -0
  2. funcprops/_semialg.py +246 -0
  3. funcprops/api.py +70 -0
  4. funcprops/branchcuts/__init__.py +141 -0
  5. funcprops/branchcuts/computation.py +664 -0
  6. funcprops/branchcuts/core.py +1204 -0
  7. funcprops/branchcuts/post_simplify.py +461 -0
  8. funcprops/conditions.py +124 -0
  9. funcprops/data/catalogue.json +127449 -0
  10. funcprops/data/dlmf_audit.json +3382 -0
  11. funcprops/dlmf.py +29 -0
  12. funcprops/engine.py +324 -0
  13. funcprops/exceptions.py +29 -0
  14. funcprops/proof_cache.py +373 -0
  15. funcprops/real_analysis/__init__.py +52 -0
  16. funcprops/real_analysis/advanced_convexity.py +217 -0
  17. funcprops/real_analysis/boundedness.py +168 -0
  18. funcprops/real_analysis/common.py +244 -0
  19. funcprops/real_analysis/convexity.py +698 -0
  20. funcprops/real_analysis/differentiability.py +112 -0
  21. funcprops/real_analysis/domain.py +188 -0
  22. funcprops/real_analysis/mapping.py +374 -0
  23. funcprops/real_analysis/monotonic_certificates.py +867 -0
  24. funcprops/real_analysis/monotonicity.py +673 -0
  25. funcprops/real_analysis/oscillation.py +151 -0
  26. funcprops/real_analysis/piecewise.py +174 -0
  27. funcprops/real_analysis/range.py +552 -0
  28. funcprops/real_analysis/sign.py +561 -0
  29. funcprops/real_analysis/smoothness.py +268 -0
  30. funcprops/real_analysis/special_functions.py +515 -0
  31. funcprops/real_analysis/structural_properties.py +558 -0
  32. funcprops/real_analysis/zeros.py +327 -0
  33. funcprops/registry.py +274 -0
  34. funcprops/results.py +239 -0
  35. funcprops/singularities.py +1767 -0
  36. funcprops/stratification.py +494 -0
  37. funcprops/sympy_compare.py +63 -0
  38. funcprops/transcendental/__init__.py +140 -0
  39. funcprops/transcendental/algebraize.py +201 -0
  40. funcprops/transcendental/analytic.py +261 -0
  41. funcprops/transcendental/complex_roots.py +542 -0
  42. funcprops/transcendental/exp_fourier.py +221 -0
  43. funcprops/transcendental/extrema.py +821 -0
  44. funcprops/transcendental/periodic.py +222 -0
  45. funcprops/transcendental/proof.py +104 -0
  46. funcprops/transcendental/real_interval.py +128 -0
  47. funcprops/transcendental/real_sign.py +117 -0
  48. funcprops/transcendental/reduce.py +288 -0
  49. funcprops/transcendental/roots.py +1380 -0
  50. funcprops/transcendental/zero_geometry.py +1197 -0
  51. funcprops/verification.py +410 -0
  52. funcprops-0.1.0.dist-info/METADATA +208 -0
  53. funcprops-0.1.0.dist-info/RECORD +56 -0
  54. funcprops-0.1.0.dist-info/WHEEL +5 -0
  55. funcprops-0.1.0.dist-info/licenses/LICENSE +674 -0
  56. funcprops-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,410 @@
1
+ """Independent, conservative replay checks for exact property certificates.
2
+
3
+ Verifiers return True only when the certificate's stated conclusion can be
4
+ re-established from its payload and current proof primitives. False means the
5
+ certificate is internally inconsistent or unsupported; verifiers never turn an
6
+ unknown symbolic comparison into success.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import sympy as sp
12
+ from sympy import S
13
+
14
+ from .exceptions import SYMBOLIC_QUERY_ERRORS
15
+ from .results import Monotonicity, Sign
16
+
17
+
18
+ def _truth(q):
19
+ if q in (True, S.true):
20
+ return True
21
+ if q in (False, S.false):
22
+ return False
23
+ try:
24
+ z = sp.simplify(q)
25
+ if z is S.true:
26
+ return True
27
+ if z is S.false:
28
+ return False
29
+ except SYMBOLIC_QUERY_ERRORS:
30
+ pass
31
+ return None
32
+
33
+
34
+ def verify_monotonic_decomposition(cert):
35
+ from .real_analysis.monotonic_certificates import MonotonicDecomposition
36
+
37
+ if not isinstance(cert, MonotonicDecomposition):
38
+ return False
39
+ try:
40
+ return sp.simplify(cert.reconstruct() - cert.expression) == 0
41
+ except SYMBOLIC_QUERY_ERRORS:
42
+ return False
43
+
44
+
45
+ def verify_monotonic_partition(expr, var, cert):
46
+ from .proof_cache import property_proof_context
47
+ from .real_analysis.monotonic_certificates import MonotonicPartition
48
+
49
+ if not isinstance(cert, MonotonicPartition):
50
+ return False
51
+ expr = sp.sympify(expr)
52
+ var = sp.sympify(var)
53
+ ctx = property_proof_context(expr, var, domain=cert.domain)
54
+ try:
55
+ d = ctx.derivative(1, factored=True)
56
+ if cert.derivative is not None and sp.simplify(d - cert.derivative) != 0:
57
+ return False
58
+ except SYMBOLIC_QUERY_ERRORS:
59
+ return False
60
+ if cert.indexed is not None:
61
+ return bool(cert.indexed.boundary_geometry)
62
+ for cell in cert.cells:
63
+ if not isinstance(cell.interval, sp.Set):
64
+ return False
65
+ sg = property_proof_context(d, var, domain=cell.interval).sign(
66
+ domain=cell.interval
67
+ )
68
+ if cell.direction is Monotonicity.STRICTLY_INCREASING and sg not in (
69
+ Sign.POSITIVE,
70
+ Sign.NONNEGATIVE,
71
+ ):
72
+ return False
73
+ if cell.direction is Monotonicity.STRICTLY_DECREASING and sg not in (
74
+ Sign.NEGATIVE,
75
+ Sign.NONPOSITIVE,
76
+ ):
77
+ return False
78
+ if cell.direction is Monotonicity.NONDECREASING and sg not in (
79
+ Sign.POSITIVE,
80
+ Sign.NONNEGATIVE,
81
+ Sign.ZERO,
82
+ ):
83
+ return False
84
+ if cell.direction is Monotonicity.NONINCREASING and sg not in (
85
+ Sign.NEGATIVE,
86
+ Sign.NONPOSITIVE,
87
+ Sign.ZERO,
88
+ ):
89
+ return False
90
+ return True
91
+
92
+
93
+ def verify_zero_geometry(cert):
94
+ from .transcendental.zero_geometry import IndexedZero, ZeroGeometryCertificate
95
+
96
+ if not isinstance(cert, ZeroGeometryCertificate):
97
+ return False
98
+ if not isinstance(cert.support, sp.Set):
99
+ return False
100
+ if cert.derivative_order < 0:
101
+ return False
102
+ for z in cert.indexed_family:
103
+ if not isinstance(z, IndexedZero):
104
+ return False
105
+ if z.family != cert.family or z.derivative_order != cert.derivative_order:
106
+ return False
107
+ for o in cert.orderings:
108
+ if o.relation not in ("<", "<=", ">", ">="):
109
+ return False
110
+ return all(inter.pattern for inter in cert.interlacings)
111
+
112
+
113
+ def verify_convexity_certificate(expr, var, cert):
114
+ from .proof_cache import property_proof_context
115
+ from .real_analysis.advanced_convexity import ConvexityCertificate
116
+
117
+ if not isinstance(cert, ConvexityCertificate):
118
+ return False
119
+ if cert.modulus is None:
120
+ return bool(cert.method and cert.classification is not None)
121
+ if cert.modulus.is_positive is not True:
122
+ return False
123
+ d2 = property_proof_context(expr, var, domain=cert.domain).derivative(2)
124
+ concave = cert.classification.name.endswith("CONCAVE")
125
+ target = sp.simplify((-d2 if concave else d2) - cert.modulus)
126
+ sg = property_proof_context(target, var, domain=cert.domain).sign(
127
+ domain=cert.domain
128
+ )
129
+ return sg in (Sign.ZERO, Sign.NONNEGATIVE, Sign.POSITIVE)
130
+
131
+
132
+ def verify_extremum_ordering_theorem(cert):
133
+ from .transcendental.extrema import ExtremumOrderingTheorem
134
+
135
+ if not isinstance(cert, ExtremumOrderingTheorem):
136
+ return False
137
+ if cert.magnitude_direction not in ("increasing", "decreasing"):
138
+ return False
139
+ if not cert.family or not cert.source:
140
+ return False
141
+ return cert.proof is not None
142
+
143
+
144
+ def verify_indexed_tail_inversion(cert):
145
+ from .transcendental.zero_geometry import (
146
+ IndexedTailInversionCertificate,
147
+ IndexedZero,
148
+ )
149
+
150
+ if not isinstance(cert, IndexedTailInversionCertificate):
151
+ return False
152
+ if cert.direction not in ("left", "right"):
153
+ return False
154
+ if not isinstance(cert.zero_template, IndexedZero):
155
+ return False
156
+ if cert.zero_template.family != cert.family:
157
+ return False
158
+ if cert.integer_bracket is not None:
159
+ b = cert.integer_bracket
160
+ try:
161
+ if (sp.simplify(b.upper - b.lower)).is_negative is True:
162
+ return False
163
+ if (
164
+ getattr(b, "exact", False)
165
+ and sp.simplify(cert.first_index - b.lower) != 0
166
+ ):
167
+ return False
168
+ except SYMBOLIC_QUERY_ERRORS:
169
+ return False
170
+ return True
171
+
172
+
173
+ def verify_certificate(cert, *, expr=None, var=None):
174
+ """Dispatch a supported certificate to its replay verifier."""
175
+ from .real_analysis.advanced_convexity import ConvexityCertificate
176
+ from .real_analysis.monotonic_certificates import (
177
+ MonotonicDecomposition,
178
+ MonotonicPartition,
179
+ )
180
+ from .real_analysis.structural_properties import (
181
+ HomogeneityResult,
182
+ PeriodicityResult,
183
+ SymmetryResult,
184
+ )
185
+ from .transcendental.extrema import (
186
+ ExtremumFamilyCertificate,
187
+ ExtremumOrderingTheorem,
188
+ ExtremumRange,
189
+ )
190
+ from .transcendental.roots import RootCertificate
191
+ from .transcendental.zero_geometry import (
192
+ CertifiedIntegerBracket,
193
+ IndexedTailInversionCertificate,
194
+ ZeroGeometryCertificate,
195
+ )
196
+
197
+ if isinstance(cert, MonotonicDecomposition):
198
+ return verify_monotonic_decomposition(cert)
199
+ if isinstance(cert, MonotonicPartition):
200
+ if expr is None or var is None:
201
+ raise ValueError("expr and var are required for MonotonicPartition replay")
202
+ return verify_monotonic_partition(expr, var, cert)
203
+ if isinstance(cert, ConvexityCertificate):
204
+ if expr is None or var is None:
205
+ raise ValueError("expr and var are required for convexity replay")
206
+ return verify_convexity_certificate(expr, var, cert)
207
+ if isinstance(cert, ZeroGeometryCertificate):
208
+ return verify_zero_geometry(cert)
209
+ if isinstance(cert, RootCertificate):
210
+ return verify_root_certificate(cert)
211
+ if isinstance(cert, ExtremumFamilyCertificate):
212
+ return verify_extremum_family_certificate(cert)
213
+ if isinstance(cert, ExtremumRange):
214
+ return verify_extremum_range(cert)
215
+ if isinstance(cert, ExtremumOrderingTheorem):
216
+ return verify_extremum_ordering_theorem(cert)
217
+ if isinstance(cert, CertifiedIntegerBracket):
218
+ return verify_integer_bracket(cert)
219
+ if isinstance(cert, IndexedTailInversionCertificate):
220
+ return verify_indexed_tail_inversion(cert)
221
+ if isinstance(cert, PeriodicityResult):
222
+ if expr is None or var is None:
223
+ raise ValueError("expr and var are required for periodicity replay")
224
+ return verify_periodicity_result(expr, var, cert)
225
+ if isinstance(cert, SymmetryResult):
226
+ if expr is None or var is None:
227
+ raise ValueError("expr and var are required for symmetry replay")
228
+ return verify_symmetry_result(expr, var, cert)
229
+ if isinstance(cert, HomogeneityResult):
230
+ if expr is None:
231
+ raise ValueError("expr is required for homogeneity replay")
232
+ return verify_homogeneity_result(expr, cert)
233
+ raise TypeError(f"unsupported certificate type: {type(cert).__name__}")
234
+
235
+
236
+ def verify_root_certificate(cert):
237
+ from .transcendental.roots import RootCertificate
238
+
239
+ if not isinstance(cert, RootCertificate):
240
+ return False
241
+ if not isinstance(cert.domain, sp.Set):
242
+ return False
243
+ try:
244
+ if cert.root_count is not None and cert.root_count is not sp.oo:
245
+ n = sp.sympify(cert.root_count)
246
+ if n.is_integer is False or n.is_nonnegative is False:
247
+ return False
248
+ except SYMBOLIC_QUERY_ERRORS:
249
+ return False
250
+ return bool(cert.method)
251
+
252
+
253
+ def verify_extremum_family_certificate(cert):
254
+ from .transcendental.extrema import ExtremumFamilyCertificate
255
+
256
+ if not isinstance(cert, ExtremumFamilyCertificate):
257
+ return False
258
+ if not cert.family:
259
+ return False
260
+ if not all(verify_zero_geometry(g) for g in cert.critical_geometry):
261
+ return False
262
+ return all(getattr(e, "family", cert.family) == cert.family for e in cert.extrema)
263
+
264
+
265
+ def verify_extremum_range(cert):
266
+ from .transcendental.extrema import ExtremumRange
267
+
268
+ if not isinstance(cert, ExtremumRange):
269
+ return False
270
+ try:
271
+ d = sp.simplify(sp.sympify(cert.upper) - sp.sympify(cert.lower))
272
+ if d.is_negative is True:
273
+ return False
274
+ except SYMBOLIC_QUERY_ERRORS:
275
+ return False
276
+ return not (
277
+ cert.complete and (cert.lower_attained is None or cert.upper_attained is None)
278
+ )
279
+
280
+
281
+ def verify_integer_bracket(cert):
282
+ from .transcendental.zero_geometry import CertifiedIntegerBracket
283
+
284
+ if not isinstance(cert, CertifiedIntegerBracket):
285
+ return False
286
+ try:
287
+ d = sp.simplify(cert.upper - cert.lower)
288
+ if d.is_negative is True:
289
+ return False
290
+ if cert.lower.is_integer is False or cert.upper.is_integer is False:
291
+ return False
292
+ except SYMBOLIC_QUERY_ERRORS:
293
+ return False
294
+ return True
295
+
296
+
297
+ def verify_periodicity_result(expr, var, cert):
298
+ from .real_analysis.structural_properties import PeriodicityResult
299
+ from .results import Periodicity
300
+
301
+ if not isinstance(cert, PeriodicityResult):
302
+ return False
303
+ expr = sp.sympify(expr)
304
+ var = sp.sympify(var)
305
+ if cert.classification is Periodicity.CONSTANT:
306
+ return not expr.has(var)
307
+ if cert.classification is Periodicity.PERIODIC:
308
+ if cert.period is None:
309
+ return False
310
+ if (
311
+ cert.period.is_positive is not True
312
+ and "conditional-affine-frequency" not in cert.evidence
313
+ ):
314
+ return False
315
+ try:
316
+ if sp.simplify(expr.subs(var, var + cert.period) - expr) == 0:
317
+ return True
318
+ if "conditional-affine-frequency" in cert.evidence and expr.func in (
319
+ sp.sin,
320
+ sp.cos,
321
+ sp.tan,
322
+ sp.cot,
323
+ ):
324
+ a = sp.simplify(sp.diff(expr.args[0], var))
325
+ return not a.has(var) and cert.conditions == sp.Ne(a, 0)
326
+ return False
327
+ except SYMBOLIC_QUERY_ERRORS:
328
+ return False
329
+ if cert.classification is Periodicity.APERIODIC:
330
+ try:
331
+ return (
332
+ bool(expr.is_polynomial(var) and sp.Poly(expr, var).degree() > 0)
333
+ or "incommensurate-component-periods" in cert.evidence
334
+ )
335
+ except SYMBOLIC_QUERY_ERRORS:
336
+ return "incommensurate-component-periods" in cert.evidence
337
+ return cert.classification.value == "unknown"
338
+
339
+
340
+ def verify_symmetry_result(expr, var, cert):
341
+ from .real_analysis.structural_properties import SymmetryResult
342
+ from .results import Symmetry
343
+
344
+ if not isinstance(cert, SymmetryResult):
345
+ return False
346
+ expr = sp.sympify(expr)
347
+ var = sp.sympify(var)
348
+ c = sp.sympify(cert.center)
349
+ try:
350
+ ref = sp.simplify(expr.subs(var, 2 * c - var))
351
+ ev = sp.simplify(ref - expr) == 0
352
+ od = sp.simplify(ref + expr) == 0
353
+ except SYMBOLIC_QUERY_ERRORS:
354
+ return False
355
+ if cert.classification is Symmetry.BOTH:
356
+ return ev and od
357
+ if cert.classification is Symmetry.EVEN:
358
+ return ev
359
+ if cert.classification is Symmetry.ODD:
360
+ return od
361
+ if cert.classification is Symmetry.CENTRAL:
362
+ try:
363
+ return sp.simplify(ref + expr - 2 * cert.central_value) == 0
364
+ except SYMBOLIC_QUERY_ERRORS:
365
+ return False
366
+ if cert.classification is Symmetry.NEITHER:
367
+ return not ev and not od
368
+ return True
369
+
370
+
371
+ def _substitute_equalities(expr, assumptions):
372
+ repl = {}
373
+ atoms = assumptions.args if isinstance(assumptions, sp.And) else (assumptions,)
374
+ for a in atoms:
375
+ if isinstance(a, sp.Equality):
376
+ if getattr(a.lhs, "is_Symbol", False) and not a.rhs.has(a.lhs):
377
+ repl[a.lhs] = a.rhs
378
+ elif getattr(a.rhs, "is_Symbol", False) and not a.lhs.has(a.rhs):
379
+ repl[a.rhs] = a.lhs
380
+ return sp.simplify(expr.xreplace(repl)) if repl else sp.simplify(expr)
381
+
382
+
383
+ def verify_homogeneity_result(expr, cert):
384
+ from .real_analysis.structural_properties import HomogeneityResult
385
+ from .results import Homogeneity
386
+
387
+ if not isinstance(cert, HomogeneityResult):
388
+ return False
389
+ expr = sp.sympify(expr)
390
+ assumptions = getattr(cert, "assumptions", S.true)
391
+ if cert.classification is not Homogeneity.HOMOGENEOUS:
392
+ return True
393
+ if cert.degree is None:
394
+ reduced = _substitute_equalities(expr, assumptions)
395
+ return reduced == 0 or not any(reduced.has(v) for v in cert.variables)
396
+ t = sp.Dummy("_verify_scale", positive=True)
397
+ try:
398
+ scaled = expr.xreplace(
399
+ {
400
+ v: t**w * v
401
+ for v, w in zip(
402
+ cert.variables,
403
+ cert.weights or (S.One,) * len(cert.variables),
404
+ strict=False,
405
+ )
406
+ }
407
+ )
408
+ return _substitute_equalities(scaled - t**cert.degree * expr, assumptions) == 0
409
+ except SYMBOLIC_QUERY_ERRORS:
410
+ return False
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: funcprops
3
+ Version: 0.1.0
4
+ Summary: Symbolic global function properties backed by SymPy
5
+ Author-email: Bhuvanesh Bhatt <bhuvaneshbhatt@gmail.com>
6
+ License-Expression: GPL-3.0-only
7
+ Project-URL: Homepage, https://github.com/BhuvaneshBhatt/funcprops
8
+ Project-URL: Documentation, https://github.com/BhuvaneshBhatt/funcprops#readme
9
+ Project-URL: Repository, https://github.com/BhuvaneshBhatt/funcprops
10
+ Keywords: sympy,symbolic mathematics,symbolic computation,function analysis,function properties,real analysis,complex analysis,domains,ranges,zeros,root isolation,monotonicity,convexity,continuity,differentiability,smoothness,singularities,branch cuts,injectivity,surjectivity,bijectivity,sign analysis,semialgebraic,certified computation,exact computation
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: sympy>=1.14
18
+ Requires-Dist: mpmath>=1.3
19
+ Requires-Dist: semialg>=1.0.0
20
+ Provides-Extra: test
21
+ Requires-Dist: pytest>=8; extra == "test"
22
+ Requires-Dist: hypothesis>=6; extra == "test"
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=8; extra == "dev"
25
+ Requires-Dist: hypothesis>=6; extra == "dev"
26
+ Requires-Dist: ruff>=0.8; extra == "dev"
27
+ Dynamic: license-file
28
+
29
+ # funcprops
30
+
31
+ `funcprops` is a SymPy-backed package for global function properties.
32
+ It combines a conditional function property registry, exact semialgebraic reasoning from the semialgebraic geometry package `semialg`, transcendental interval analysis, special-function zero geometry, and branch-cut/singularity analysis.
33
+
34
+ The package is careful: parameter conditions are retained instead of guessed, piecewise branches are analyzed on their effective domains, incomplete numerical searches are never promoted to exact proofs, and undecidable comparisons remain unknown.
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install funcprops
40
+ ```
41
+
42
+ The core runtime requires SymPy, mpmath, and semialg 1.0.0 or newer.
43
+
44
+ ## Quick start
45
+
46
+ ```python
47
+ import sympy as sp
48
+ from funcprops import (
49
+ function_analytic,
50
+ function_branchcuts,
51
+ function_continuous,
52
+ function_convexity,
53
+ function_domain,
54
+ function_homogeneity,
55
+ function_meromorphic,
56
+ function_monotonicity,
57
+ function_periodicity,
58
+ function_poles,
59
+ function_range,
60
+ function_symmetry,
61
+ )
62
+
63
+ x, y = sp.symbols("x y", real=True)
64
+ z = sp.Symbol("z")
65
+
66
+ function_domain(sp.sqrt(x - 1), x)
67
+ # x >= 1
68
+
69
+ function_range(x**2, x, y)
70
+ # y >= 0
71
+
72
+ function_monotonicity(sp.exp(x), x)
73
+ # Monotonicity.STRICTLY_INCREASING
74
+
75
+ function_convexity(x**2, x)
76
+ # Convexity.STRONGLY_CONVEX
77
+
78
+ function_periodicity(sp.sin(2 * x) + sp.cos(3 * x), x, details=True).period
79
+ # 2*pi
80
+
81
+ function_symmetry((x - 2) ** 2, x, center=None, details=True).center
82
+ # 2
83
+
84
+ function_homogeneity(x**2 + y**4, (x, y), weights=(2, 1), details=True).degree
85
+ # 4
86
+
87
+ function_branchcuts(sp.log(1 - z), z)
88
+ # structural pullback of the principal logarithm cut
89
+
90
+ function_poles(sp.sin(z) / z**3, z)[0].multiplicity
91
+ # 2
92
+
93
+ function_analytic(sp.log(z), z, domain=sp.S.Complexes)
94
+ # Analyticity.ANALYTIC on the principal branch's natural domain
95
+
96
+ function_meromorphic(sp.log(z), z)
97
+ # Meromorphicity.NOT_MEROMORPHIC
98
+
99
+ function_continuous(sp.Abs(x), x)
100
+ # Continuity.CONTINUOUS
101
+ ```
102
+
103
+ ## Property model
104
+
105
+ API functions return exact classifications when the available proof machinery is sufficient. `PropertyResult` and `ConditionalValue` are the common representation for parameter strata across real and complex properties, so unresolved guards are preserved instead of being collapsed into a single answer. `PropertyResult.as_piecewise()` provides a Piecewise-style view when useful.
106
+
107
+ Three-valued reasoning is used throughout proof-oriented code. An undecidable set relation, domain implication, branch-locus intersection, or symbolic comparison is not treated as false merely because Python cannot decide it.
108
+
109
+ ## Real-domain analysis
110
+
111
+ `funcprops` owns the property vocabulary. For semialgebraic functions on semialgebraic real domains `funcprops` delegates exact domain, range, sign, monotonicity, convexity, smoothness, and mapping-property problems to `semialg`, while retaining stronger exact `funcprops` results when they are already certified. A shared sign engine is the main inequality proof primitive: derivative signs feed monotonicity and convexity, while relation queries reduce comparisons to the sign of a difference. Transcendental expressions are handled compositionally using primitive facts, exact domain restrictions, periodic reductions, derivative geometry, and certified interval reasoning.
112
+
113
+ Mixed variable/parameter domains are split once by the shared stratification layer and each variable-domain branch is analyzed independently. Finite `Piecewise` expressions likewise use one effective-branch representation. Consumers add only the interface conditions their property requires: monotonicity checks jump direction, convexity checks continuity and derivative ordering, and sign and boundedness combine exact branch classifications.
114
+
115
+ The main real-analysis APIs include:
116
+
117
+ - `function_domain()` and `function_range()`;
118
+ - `function_sign()`;
119
+ - `function_boundedness()`;
120
+ - `function_monotonicity()`;
121
+ - `function_oscillation()`;
122
+ - `function_convexity()` with normalized `ConvexityCertificate` evidence;
123
+ - `function_injective()`, `function_surjective()`, and `function_bijective()`;
124
+ - `function_continuous()`, `function_differentiability()`, `function_smoothness()`, and `function_analytic()`;
125
+ - `function_periodicity()`, `function_symmetry()`, and `function_homogeneity()`.
126
+
127
+ Multivariate APIs normalize variable collections explicitly rather than treating a tuple as one symbolic atom. Constant-Hessian convexity and affine mapping cases are handled exactly; unsupported nonlinear multivariate mapping questions give unknown.
128
+
129
+ ## Monotonic partitions and exact inverse solving
130
+
131
+ `MonotonicPartition` is the shared exact interval representation used by monotonicity, range, injectivity, inverse solving, oscillation, and extrema. Finite partitions retain exact critical points, endpoint limits, and endpoint attainment. Infinite oscillatory partitions retain indexed zero geometry without guessing an unsupported increasing/decreasing phase.
132
+
133
+ `solve_monotonic_inverse()` first attempts a whole-domain exact solve. If that is insufficient, it uses monotonic cells and exact image pruning. On a strict finite cell, an unresolved symbolic inverse can still be completed by certified endpoint signs and a rational isolating interval. `certified_monotonic_inverse()` is the explicit certification-oriented spelling of the same reusable primitive. The same partition can be passed explicitly to consumers or reused through the bounded proof cache.
134
+
135
+ ## Certified real-root backends
136
+
137
+ Real root isolation is domain-cell aware: denominator zeros, logarithm boundaries, noninteger-power branch boundaries, Piecewise switch points, and other exact domain boundaries split the problem before any interval certificate is constructed. Identically-zero interval cells are retained as ordinary parts of the mathematical zero set.
138
+
139
+ For finite elementary cells, an outward-rounded interval evaluator can prove that zero is excluded from the function image, or from the derivative image. The latter certifies strict monotonicity even when symbolic monotonicity is unresolved. Point signs use `robust_real_sign()`, which combines exact SymPy sign reasoning with an audited exp/log interval fallback to avoid overflow and underflow.
140
+
141
+ `exponential_fourier_count()` provides a restricted derivative-sequence root counter for real exponential polynomials. After multiplication by a positive exponential factor, each derivative step removes the lowest exponential term. When every derivative root and endpoint/critical sign is exact, recursive Rolle/monotonicity reasoning certifies the number of distinct roots on the requested interval.
142
+
143
+ ## Certified complex root isolation
144
+
145
+ `function_complex_zeros` isolates zeros in finite complex rectangles. It uses exact complex solving when available and otherwise a validated argument-principle contour: structural holomorphy certification, adaptive complex-interval boundary enclosures that exclude zero, winding-number counting, and count-preserving rational rectangle subdivision. Uncertified numerical winding estimates remain diagnostic only.
146
+
147
+ ## Zero geometry and oscillatory extrema
148
+
149
+ Special-function zeros are represented symbolically when closed forms are not available. `IndexedZero`, `ZeroOrdering`, `ZeroInterlacing`, and `ZeroGeometryCertificate` describe exact support, simplicity, ordering, interlacing, and completeness information.
150
+
151
+ Derivative-zero geometry feeds interval decomposition. A finite exact root set produces concrete cells; a complete infinite family can produce an indexed alternating-cell structure. This allows exact reasoning about Airy, Bessel, and classical orthogonal-polynomial behavior without truncating an infinite zero sequence numerically.
152
+
153
+ `IndexedExtremumValue` and `ExtremumEnvelope` represent exact critical values and infinite extremum families. `symbolic_extremum_range()` combines them with exact endpoint values or limits. For supported Airy and Bessel families, analytic ordering theorems reduce infinite extremum envelopes to finite exact candidates.
154
+
155
+ `IndexedTailIndex` and indexed-tail inversion represent the least zero/extremum index entering a semi-infinite domain. Same-family cutoffs and certified interlacing can reduce the symbolic selector to an ordinary integer; otherwise it remains exact as a symbolic set-theoretic minimum.
156
+
157
+ ## Periodicity, symmetry, and homogeneity
158
+
159
+ Periodicity propagates exact common periods through commensurate sums, products, and compositions. Parameter-dependent affine frequencies retain their nonzero frequency condition, and a returned period is not called fundamental unless minimality is established.
160
+
161
+ Symmetry supports a specified reflection center as well as exact center discovery for supported polynomial and affine-trigonometric forms. Detail results can retain families of equivalent even/odd centers and central point symmetry.
162
+
163
+ Homogeneity supports ordinary and weighted multivariate scaling. Polynomial analysis preserves exact parameter strata when coefficients determine which weighted-degree blocks survive, including the identically zero case.
164
+
165
+ ## Singularities and branch cuts
166
+
167
+ `function_singularity_analysis()` performs condition-aware structural traversal of poles, removable singularities, essential singularities, branch points, branch cuts, definition cuts, and discontinuities. Piecewise guards and parameter guards are retained. Unknown primitive heads are recorded instead of silently treated as regular.
168
+
169
+ `function_branchcuts()` provides inexpensive structural pullback of principal cuts. Boundary-value and jump computations are available under `funcprops.branchcuts`.
170
+
171
+ Real analyticity and complex holomorphy are kept distinct from meromorphicity. For example, the principal logarithm is locally holomorphic on its natural complex domain but is not meromorphic on the complex plane because of its branch structure.
172
+
173
+ ## Special-function property registry
174
+
175
+ The conditional registry contains SymPy/mpmath family metadata from an audited property catalogue. Catalogue values and guards are stored in deterministic SymPy constructor syntax, so rule loading does not depend on a second expression grammar. Concrete SymPy overloads are matched before guards are instantiated, and more-specific rules take precedence over generic ones. Literal pattern failures do not count as matches.
176
+
177
+ Selected special-function facts are cross-checked against the NIST Digital Library of Mathematical Functions (DLMF). The audit distinguishes direct formula-backed facts from derived wrapper/helper facts and from merely related DLMF material. The machine-readable manifest is `src/funcprops/data/dlmf_audit.json`.
178
+
179
+ ## Proof cache and certificate replay
180
+
181
+ Reusable proof primitives are coordinated through a lazy `PropertyProofContext`. Constructing a context does no mathematical work. Independent bounded LRU caches hold raw and factored derivatives, natural domains, sign results, endpoint limits, zero geometry, singularity analyses, and monotonic partitions.
182
+
183
+ Cache-key normalization is intentionally inexpensive and syntactic; it does not run quantifier elimination or expensive logical simplification simply to form a key. Raw and factored derivatives use separate cache slots so callers that need only a derivative do not pay for factorization.
184
+
185
+ Certificates can be replayed with `verify_certificate()` and specialized verifiers. Convexity uses one `ConvexityCertificate` shape for ordinary, strict, and strong classifications; strong certificates additionally carry the certified modulus. Replay is conservative: an undecidable comparison never counts as a successful verification.
186
+
187
+ ## Documentation
188
+
189
+ - [Function property reference](https://github.com/BhuvaneshBhatt/funcprops/blob/main/docs/properties/index.md) — comprehensive definitions, API contracts, examples, applications, proof strategies, and limitations for every public `function_*` query.
190
+ - [Function properties tutorial notebook](https://github.com/BhuvaneshBhatt/funcprops/blob/main/docs/notebooks/function-properties-tour.ipynb) — an executable tour built from the same tested examples as the reference documentation.
191
+ - [Architecture](https://github.com/BhuvaneshBhatt/funcprops/blob/main/docs/architecture.md)
192
+ - [DLMF audit methodology](https://github.com/BhuvaneshBhatt/funcprops/blob/main/docs/dlmf_audit.md)
193
+ - [Source repository](https://github.com/BhuvaneshBhatt/funcprops)
194
+
195
+ ## Development
196
+
197
+ Run the test suite against the source tree with:
198
+
199
+ ```bash
200
+ PYTHONPATH=src pytest
201
+ ```
202
+
203
+ The package intentionally keeps exact fast paths ahead of heavier partition, root-isolation, or semialgebraic machinery. Refactors should preserve that order unless a benchmark and correctness argument justify changing it.
204
+
205
+ ## License
206
+
207
+ funcprops is licensed under the GNU General Public License version 3 only
208
+ (`GPL-3.0-only`). See [LICENSE](https://github.com/BhuvaneshBhatt/funcprops/blob/main/LICENSE).
@@ -0,0 +1,56 @@
1
+ funcprops/__init__.py,sha256=gzGoGBBiTD-uo_-GfL9X_trGYAOGCxCw9hHEySHraek,6832
2
+ funcprops/_semialg.py,sha256=04IlXW1SLas-qqRNpU7OSd-s3i8nOqyzefJW65F8Q0g,8169
3
+ funcprops/api.py,sha256=oD4W_-kiuZzVt6kdNUuHG9m0SWMlfxQSXsQ4cRwbp2c,2205
4
+ funcprops/conditions.py,sha256=d0ni0VVlksAfzle_wFdYK5eDRcWWJGZGvH-niUjo9H0,2377
5
+ funcprops/dlmf.py,sha256=NAwz49M80Zi7hP2w3Z_rzyJU4wkmpPU7Z9DhLuLVn9A,778
6
+ funcprops/engine.py,sha256=Z0uJ7J8Qdf-cfUwqDlF9LTNGDkArqq1r6QrNJqXOVk0,10468
7
+ funcprops/exceptions.py,sha256=ZejGRT6XaGtH6Ix1jeG8QeEG6unkNbrO0pVrb83elSs,1220
8
+ funcprops/proof_cache.py,sha256=ZSjiKRvexNcgzq0e15mkBs7XsGjsUcnn7aFSh_rm2iI,11912
9
+ funcprops/registry.py,sha256=1EuQ3vn36vFbRHqXIW6BXfvcpRmkJqcQxR6gb_Sg3Mc,8504
10
+ funcprops/results.py,sha256=h22ulm7AQwACPI8UsTaJTOwAFCcTMNf_2QS44Z4aQJo,6486
11
+ funcprops/singularities.py,sha256=bu_TOlvB__gJ1OqnTSLaSDUtanpTCs-oUNZ63fPM_4Y,62140
12
+ funcprops/stratification.py,sha256=DdqOEXf4cJabneX5UwdxLrhuglYlrezD9KbafZ9SXRI,17448
13
+ funcprops/sympy_compare.py,sha256=j2zRRJPQLwmfgyUBWHECqPe0BIGbTKxCTImjpaC-rpM,1879
14
+ funcprops/verification.py,sha256=obC7qJPaVBHwiXDwDKuUtQvcsdBmnvHD1PiEu55-7jM,14278
15
+ funcprops/branchcuts/__init__.py,sha256=xsZ-PXkvLe5MuiaCln3LaVp6x81dZ3PrFwzNwyoQufM,4171
16
+ funcprops/branchcuts/computation.py,sha256=rxJRC198IMhdjLMmurcU4RjoHWPs2Hppf3ShiXsHkXU,21800
17
+ funcprops/branchcuts/core.py,sha256=ZEBdt_xyuZlHA6syzaSz6NxxH9LZ_Vd1eRSgDeIAiAs,33469
18
+ funcprops/branchcuts/post_simplify.py,sha256=_dGDGasbrm3OjFnFZaYXtLPeBV5gR-NnlZqFv5JKoBo,14633
19
+ funcprops/data/catalogue.json,sha256=Ycj8Gu5lX8tU4lySrNPxVJd4iF9scANpectCh2qE3PI,5269115
20
+ funcprops/data/dlmf_audit.json,sha256=HlK_-uIcJgwtFmmyflFW_LaYsauXt64WEjYTTc1rdU0,92775
21
+ funcprops/real_analysis/__init__.py,sha256=zi8cTlFhDs9qxHA5-EdGx_Vr4qXrHoJdr9Sxcrc1ryo,1595
22
+ funcprops/real_analysis/advanced_convexity.py,sha256=fCQNcoiYx39UUbwSM-LzRLVYheGxoEhi33YDbzgATgs,8320
23
+ funcprops/real_analysis/boundedness.py,sha256=MmFnkzVfKzHPxRrDItJfJj-Q44kIWryJuvWlNuXliVU,6561
24
+ funcprops/real_analysis/common.py,sha256=8e01kciN91APhn1HAumh-i_M1p_xuF-SGja0Fyv-iEE,9288
25
+ funcprops/real_analysis/convexity.py,sha256=Q5witapGOuv2HisK3rC0JDyY7wJyNDMQvi9qn3ndgE4,24439
26
+ funcprops/real_analysis/differentiability.py,sha256=2ba3b5hGxZbcV0AB2HreoNs7VGJbFc1lrzTG2poHdaU,4268
27
+ funcprops/real_analysis/domain.py,sha256=HZyAUV9l5tlIMew5OAAVAxsDs1jtGe_ox66D-7RNM_A,7593
28
+ funcprops/real_analysis/mapping.py,sha256=YHBrM5fXQaFbRdIbAwLaVZV4lPXqf-yXAra0dlpThRw,13841
29
+ funcprops/real_analysis/monotonic_certificates.py,sha256=nsF-QhTSINg8TGCtLHwmJFIES_WMATPFidAjMyKYFnM,29458
30
+ funcprops/real_analysis/monotonicity.py,sha256=r_nlgYcgPQ1-G6MtvR4IWLaVXvHrzByiCGiVxXJsvhs,25145
31
+ funcprops/real_analysis/oscillation.py,sha256=qXayFA7-iPW6iUqd179LXz1nFM5HEh_cO9kodcL0iGw,5133
32
+ funcprops/real_analysis/piecewise.py,sha256=DJSqxt71M437-Skv4P2mrrB4jXuXiEZQZ43_66lUQt4,6413
33
+ funcprops/real_analysis/range.py,sha256=QdVRVryF590_c0TLJG7e0mPbV7tm0kz4YIOsqrY6fD4,20158
34
+ funcprops/real_analysis/sign.py,sha256=trRj15zD85s5FS6qL65M3AGBs9TpzQIsvT05m4jxURs,19146
35
+ funcprops/real_analysis/smoothness.py,sha256=1dDf7UOWJmMRuIIc-dHmNzQ5ohFZg5FLpEABv_0BRS4,9118
36
+ funcprops/real_analysis/special_functions.py,sha256=yAmQFoqQ0Zt1JStuvzKKXr_tjIAvF47CZ6oAKvRKVBg,16644
37
+ funcprops/real_analysis/structural_properties.py,sha256=GyxqxH2hqidjJIRvMuML__0NUB2ftCwUiNFJ28lDQ1I,20110
38
+ funcprops/real_analysis/zeros.py,sha256=dUUAln-YW72kYM9cqsPkSmMRL2QmYI6ueAKeFK1Nflc,11057
39
+ funcprops/transcendental/__init__.py,sha256=TiNrrKrpZBwlmVty2paqsAS7LzW41qYThTLesMyNfyM,3648
40
+ funcprops/transcendental/algebraize.py,sha256=VmKAWKKS4vYbv6qV1vE5bdqGW3qhg2947hADGmAJGns,6032
41
+ funcprops/transcendental/analytic.py,sha256=DZ22HGn-aZ3VCy50yARmOmOF8lzIhGf-9ACuers7_xI,7973
42
+ funcprops/transcendental/complex_roots.py,sha256=Ks3dWVmr84-fTzFziiZaO9y9OKz6nv3xzDfbCS0hz9o,15974
43
+ funcprops/transcendental/exp_fourier.py,sha256=C_U5s18U89PmwJU1pFQWNr_IF80ZkLQHVuKEVco2ywI,6977
44
+ funcprops/transcendental/extrema.py,sha256=fg1z3G6zRkA2Wsnp-aFNXulff5vC9ajJmn5SPX2XF7I,29285
45
+ funcprops/transcendental/periodic.py,sha256=E83TmL_hR_YfgvH5ovji66ZpTxqvHMsYXBEEcZ75InQ,7276
46
+ funcprops/transcendental/proof.py,sha256=UbAcJgdK17VxTElCHzKlAMwKduoC25TGxxosRvGLG0g,3050
47
+ funcprops/transcendental/real_interval.py,sha256=dV8m4q1O0pnNgAJKke1erd4l3b9NUIpc9meLzsvuD5g,3765
48
+ funcprops/transcendental/real_sign.py,sha256=gS-WLexzlw2txLJktgqUg0A3jptKWCeFWrTK-5g6ViY,3702
49
+ funcprops/transcendental/reduce.py,sha256=AmC1fEZRVE015xT2x2trrIIMX3ljXhdGMQhQm577lcU,9593
50
+ funcprops/transcendental/roots.py,sha256=HXVT_OOWdGdD5nkrDIkoOB5jUQ7gZeGEZTJTvUvzfiE,48303
51
+ funcprops/transcendental/zero_geometry.py,sha256=oCKOor-UEYnWb_LhMeIkI9vJ5UF5fpsdo-TG0iq6Gs4,38801
52
+ funcprops-0.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
53
+ funcprops-0.1.0.dist-info/METADATA,sha256=YfrjmYtndK-6rDh9nnqcuML8D1K27pFcUnMimcUAzKA,14263
54
+ funcprops-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
55
+ funcprops-0.1.0.dist-info/top_level.txt,sha256=jk186mdxNzdJCigjKQx_lwqvKSd2CrSWAQZWWlWrDsw,10
56
+ funcprops-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+