diff --git a/Project.toml b/Project.toml index 8f5cb798..f49738cc 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ version = "0.10.6" DataInterpolations = "82cc6244-b520-54b8-b5a6-8a565e85f1d0" FastDifferentiation = "eb9bf01b-bf85-4b60-bf87-ee5de06c00be" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +IrrationalConstants = "92d709cd-6900-40b7-9082-c6be49f344b6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" @@ -26,9 +27,9 @@ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b" Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" -[extensions] -PostNewtonianForwardDiffExt = ["ForwardDiff"] -PostNewtonianSymbolicsExt = ["Symbolics", "SymbolicUtils"] +# [extensions] +# PostNewtonianForwardDiffExt = ["ForwardDiff"] +# PostNewtonianSymbolicsExt = ["Symbolics", "SymbolicUtils"] [compat] Aqua = "0.8" @@ -40,6 +41,7 @@ FileIO = "1.16.3" ForwardDiff = "0.10.38, 1" HDF5 = "0.17.2" InteractiveUtils = "1" +IrrationalConstants = "0.2.4" LinearAlgebra = "1" Logging = "1" MacroTools = "0.5.10" diff --git a/docs/Project.toml b/docs/Project.toml index 8a25f2f5..d7fec299 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,5 +1,7 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244" +DocumenterMermaid = "a078cd44-4d9c-4618-b545-3ab9d77f9177" LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589" PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" diff --git a/docs/make.jl b/docs/make.jl index bbabee6b..bf2accb3 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,6 +1,7 @@ using PostNewtonian using Symbolics # To document the extension using Documenter +using DocumenterMermaid DocMeta.setdocmeta!( PostNewtonian, :DocTestSetup, :(using PostNewtonian); recursive=true, warn=false @@ -33,6 +34,7 @@ makedocs(; "GWFrames" => "interface/gwframes.md", ], "Internals" => [ + "Code diagram" => "internals/code_diagram.md", "Code structure" => "internals/code_structure.md", "internals/pn_systems.md", "internals/fundamental_variables.md", diff --git a/docs/src/interface/high-level.md b/docs/src/interface/high-level.md index 0bf595c6..e6d94463 100644 --- a/docs/src/interface/high-level.md +++ b/docs/src/interface/high-level.md @@ -53,9 +53,9 @@ using Plots # Requires also installing `Plots` in your project plotlyjs() # hide default(size=(800,480), linewidth=2, leg=:top) # hide -plot(inspiral.t, inspiral[:χ⃗₁ˣ], label=raw"$\vec{\chi}_1^x$") -plot!(inspiral.t, inspiral[:χ⃗₁ʸ], label=raw"$\vec{\chi}_1^y$") -plot!(inspiral.t, inspiral[:χ⃗₁ᶻ], label=raw"$\vec{\chi}_1^z$") +plot(inspiral.t, inspiral[:χ₁ˣ], label=raw"$\vec{\chi}_1^x$") +plot!(inspiral.t, inspiral[:χ₁ʸ], label=raw"$\vec{\chi}_1^y$") +plot!(inspiral.t, inspiral[:χ₁ᶻ], label=raw"$\vec{\chi}_1^z$") plot!(xlabel="Time (𝑀)", ylabel="Dimensionless spin components") savefig("inspiral_spins.html"); nothing # hide ``` @@ -78,7 +78,7 @@ They can be accessed by their symbols, like the spins above, or by their number in this list. To access the `i`th variable at time step `j`, use `sol[i, j]`. You can also use colons: `sol[i, :]` is a vector of the `i`th variable at all times, and `sol[:, j]` is a vector of all the data at time step `j`. For -example, `inspiral[:χ⃗₁ˣ]` could also be written as `inspiral[3, :]`. +example, `inspiral[:χ₁ˣ]` could also be written as `inspiral[3, :]`. By default, the output of `orbital_evolution` is just the time steps to which the adaptive ODE integrator happened to step. If you know that you want the diff --git a/docs/src/interface/symbolics.md b/docs/src/interface/symbolics.md index 06da77b9..9df9afd6 100644 --- a/docs/src/interface/symbolics.md +++ b/docs/src/interface/symbolics.md @@ -23,7 +23,7 @@ symbols as usual: julia> using PostNewtonian, Symbolics julia> symbolic_pnsystem = PostNewtonian.SymbolicPNSystem() -PostNewtonian.SymbolicPNSystem{Vector{Num}, 9223372036854775805//2, Num}(Num[M₁, M₂, χ⃗₁ˣ, χ⃗₁ʸ, χ⃗₁ᶻ, χ⃗₂ˣ, χ⃗₂ʸ, χ⃗₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ], Λ₁, Λ₂) +PostNewtonian.SymbolicPNSystem{Vector{Num}, 9223372036854775805//2, Num}(Num[M₁, M₂, χ₁ˣ, χ₁ʸ, χ₁ᶻ, χ₂ˣ, χ₂ʸ, χ₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ], Λ₁, Λ₂) julia> v = PostNewtonian.v(symbolic_pnsystem) v diff --git a/docs/src/internals/code_diagram.md b/docs/src/internals/code_diagram.md new file mode 100644 index 00000000..816f53ea --- /dev/null +++ b/docs/src/internals/code_diagram.md @@ -0,0 +1,167 @@ +## Possibilities for Code Structure + +### `StaticArrays.FieldVector` + +This is a nice idea. Given a `struct` with a series of fields, making +it a subtype of `FieldVector` makes it an `SVector` or `MVector` +(depending on whether it is immutable or mutable). The fields can be +accessed by the names you give them, but everything else is like a +nicely completed `StaticArray`, which is handled well by all the SciML +packages. So, for example, we would define `BBH` as + +```julia +using StaticArrays: FieldVector + +struct BBH{T, PNOrder} <: FieldVector{14, T} + M₁::T + M₂::T + χ⃗₁::T + χ₁ˣ::T + χ₁ʸ::T + χ₁ᶻ::T + χ⃗₂::T + χ₂ˣ::T + χ₂ʸ::T + χ₂ᶻ::T + R::T + Rʷ::T + Rˣ::T + Rʸ::T + Rᶻ::T + v::T + Φ::T +end +``` + +The big disadvantage is that it is not possible to contain non-state +variables in the `struct` — for example, the tidal coupling +parameters. Making them into state variables would make the ODE +system larger than it needs to be. Making them into type parameters +would be bad design, lengthening compile times. I don't see any other +way to incorporate them into the `struct`, so this option is +discarded. + +### `LabelledArrays` + +This is a nice design, and works well with SciML. But it doesn't +allow any other metadata — even `PNOrder`, which would be possible +with `FieldVector`. So this is discarded. + +### Emulating `LabelledArrays`' use of `Syms` + +Part of the type of a `LabelledArray` is a `Syms` object, which is a +`Tuple` of `Symbol`s. I could basically reimplement this for +`PNSystem`s, which could bring a great deal of flexibility. For +example, if a `PNSystem` has an `e` field, it must be an eccentric +system. So, in principle, we could dispatch on `Syms`. This seems +clunky to me. Also, it would remove our ability to further +specialize, unless we defined adequate abstract super types. I don't +have a solid argument against this, but I think it would be better to +just define a `symbols` function for each subtype. + +### Make `symbols` as function of type, and emulate `LabelledArrays` features + +This will be a lot of work, but basically copying all the methods of +`LabelledArrays` seems like the way to go. + +### Separate types for mutable and immutable systems + +I think it would be too much work to maintain two separate types for +each of the `PNSystem`s, one mutable and one immutable. Probably +better to just store the container type as a type parameter, and test +whether that container `ismutabletype` — for example, inside +`setindex!`, we could test and raise a more informative error if the +system `!ismutabletype`. + +## Diagram + +```mermaid +flowchart TB + %% define each layer as its own box + subgraph Core["core
Building blocks of the code"] + + end + subgraph Systems["pn_systems
Types encoding various binaries"] + end + subgraph Literature["literature
Modules for each reference containing pieces of PN expressions"] + end + subgraph Expressions["pn_expressions
Functions for computing physical quantities"] + end + subgraph Interface["interface
High-level functions for users to call"] + end + + %% draw the arrows in build‐order + Core --> Systems + Systems --> Literature + Literature --> Expressions + Expressions --> Interface +``` + +- PostNewtonian + - interface: high-level functions for users to call + - orbital_evolution + - waveform + - pn + - pn_expressions: functions for computing physical quantities + - flux + - energy + - angular_momentum + - precession + - dynamics + - waveforms + - literature: modules for each reference containing pieces of PN expressions + - common variables + - Ref1 + - import fundamental variables + - import common variables + - define variables not in common variables + - write individual expressions as separate functions with `@pn_expression` + - pn_systems: types encoding various binaries + - PNSystem + - AbstractBBHSystem + - QuasicircularBBH + - QuasisphericalBBH + - EccentricNonspinningBBH + - BBH + - AbstractBHNSSystem + - BHNS + - AbstractNSNSSystem + - NSNS + - core: the building blocks of the code + - PNExpression + - PNReference + - PNExpansion + - PNTerm + +- `PNSystem` + - Define abstract subtypes: + - `AbstractBBHSystem` + - `QuasicircularBBH` + - `QuasisphericalBBH` + - `EccentricNonspinningBBH` + +- `PNExpression` +- `PNExpansion` +- `PNTerm` + +- literature + - common variables + - each reference + - directory and module named by bibtex key + - modules are imported directly under top-level `PostNewtonian` + - explicitly import any fundamental variables used in the expressions + - import variables that are defined the same as the common variables + - define variables that are not defined in the common variables + - write individuals + +- PN expressions + - Assemble functions for high-level quantities like flux, etc. + - Inside each function, simply call the expressions from the + literature, prepending with module name. + +`@pn_expression` will + +1. look for symbols in the expression, and for any that matches a function + name in the current module, add a `let` binding for that symbol to equal + the function called on the `pnsystem` argument. diff --git a/docs/src/internals/utilities.md b/docs/src/internals/utilities.md index 8228433d..6386a4ee 100644 --- a/docs/src/internals/utilities.md +++ b/docs/src/internals/utilities.md @@ -90,11 +90,6 @@ and replace them with the appropriate float values. ```@docs PostNewtonian.γₑ PostNewtonian.ζ3 -PostNewtonian.ln2 -PostNewtonian.ln3 -PostNewtonian.ln5 -PostNewtonian.ln³╱₂ -PostNewtonian.ln⁵╱₂ ``` ## Truncated series diff --git a/docs/src/references.bib b/docs/src/references.bib new file mode 100644 index 00000000..a0d6fb41 --- /dev/null +++ b/docs/src/references.bib @@ -0,0 +1,34 @@ +@article{Blanchet2024, + title = {{Post-Newtonian} theory for gravitational waves}, + volume = {27}, + issn = {1433-8351}, + url = {https://doi.org/10.1007/s41114-024-00050-z}, + doi = {10.1007/s41114-024-00050-z}, + number = {1}, + journal = {Living Reviews in Relativity}, + author = {Blanchet, Luc}, + month = jul, + year = {2024}, +} + +@article{TaylorPoisson2008, + title = {Nonrotating black hole in a {post-Newtonian} tidal environment}, + volume = {78}, + issn = {1550-7998, 1550-2368}, + url = {http://arxiv.org/abs/0806.3052}, + doi = {10.1103/PhysRevD.78.084016}, + number = {8}, + journal = {Physical Review D}, + author = {Taylor, Stephanne and Poisson, Eric}, + month = oct, + year = {2008}, +} + +@misc{Trestini2025, + title = {The Schott term in the binding energy for compact binaries on circular orbits at fourth {post-Newtonian} order}, + url = {http://arxiv.org/abs/2504.13245}, + doi = {10.48550/arXiv.2504.13245}, + author = {Trestini, David}, + month = apr, + year = {2025}, +} diff --git a/ext/PostNewtonianSymbolicsExt.jl b/ext/PostNewtonianSymbolicsExt.jl index a8d0a1b5..c7cd1b31 100644 --- a/ext/PostNewtonianSymbolicsExt.jl +++ b/ext/PostNewtonianSymbolicsExt.jl @@ -19,10 +19,9 @@ import PostNewtonian: causes_domain_error!, prepare_pn_order, order_index, + iscall, + isadd, 𝓔′, - apply_to_first_add!, - flatten_add!, - flatten_mul!, pn_expression, pn_expansion, @pn_expansion, @@ -44,13 +43,9 @@ import PostNewtonian: X₁, X₂, ln, - ln2, - ln3, - ln5, ζ3, γₑ, _efficient_vector -#apply_to_first_add!, flatten_add!, pn_expression, using RuntimeGeneratedFunctions: init, @RuntimeGeneratedFunction init(@__MODULE__) @@ -59,6 +54,46 @@ function _efficient_vector(N, ::Type{Symbolics.Num}) return Symbolics.variables(string(gensym()), 1:N) end +### Moved from src/core/utilities/misc.jl + +""" + flatten_binary!(expr, symbols) + +Flatten nested binary operations — that is, apply associativity repeatedly. +""" +function flatten_binary!(expr, symbols) + while iscall(expr, symbols) && any(x -> iscall(x, symbols), expr.args[2:end]) + args = expr.args[2:end] + i₊ = findfirst(x -> iscall(x, symbols), args) + args′ = [first(symbols); args[1:(i₊ - 1)]; args[i₊].args[2:end]; args[(i₊ + 1):end]] + expr.args[:] = args′[1:length(expr.args)] + append!(expr.args, args′[(1 + length(expr.args)):end]) + end + return expr +end + +flatten_add!(expr) = flatten_binary!(expr, ((+), :+)) +flatten_mul!(expr) = flatten_binary!(expr, ((*), :*)) + +""" + apply_to_first_add!(expr, func) + +Apply `func` to the first sub-expression found in a "prewalk"-traversal of `expr` that +satisfies [`isadd`](@ref). If `func` acts in place, so does this function. In either case, +the expression should be returned. +""" +function apply_to_first_add!(expr, func) + found_add = false + MacroTools.prewalk(expr) do x + if !found_add && isadd(x) + found_add = true + func(x) + else + x + end + end +end + ### Moved from src/utilities/macros.jl hold(x) = x @@ -68,7 +103,7 @@ Symbolics.derivative(::typeof(hold), args::NTuple{1,Any}, ::Val{1}) = 1 function unhold(expr) MacroTools.postwalk(expr) do x m = MacroTools.trymatch(:(f_(i_)), x) - m === nothing || m[:f] !== hold ? x : Symbol(m[:i]) + m ≡ nothing || m[:f] !== hold ? x : Symbol(m[:i]) end end @@ -260,10 +295,10 @@ end causes_domain_error!(u̇, ::PNSystem{VT}) where {VT<:Vector{Symbolics.Num}} = false function SymbolicPNSystem(PNOrder=typemax(Int)) - Symbolics.@variables M₁ M₂ χ⃗₁ˣ χ⃗₁ʸ χ⃗₁ᶻ χ⃗₂ˣ χ⃗₂ʸ χ⃗₂ᶻ Rʷ Rˣ Rʸ Rᶻ v Φ Λ₁ Λ₂ + Symbolics.@variables M₁ M₂ χ₁ˣ χ₁ʸ χ₁ᶻ χ₂ˣ χ₂ʸ χ₂ᶻ Rʷ Rˣ Rʸ Rᶻ v Φ Λ₁ Λ₂ ET = typeof(M₁) return SymbolicPNSystem{Vector{ET},prepare_pn_order(PNOrder),ET}( - [M₁, M₂, χ⃗₁ˣ, χ⃗₁ʸ, χ⃗₁ᶻ, χ⃗₂ˣ, χ⃗₂ʸ, χ⃗₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ], Λ₁, Λ₂ + [M₁, M₂, χ₁ˣ, χ₁ʸ, χ₁ᶻ, χ₂ˣ, χ₂ʸ, χ₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ], Λ₁, Λ₂ ) end diff --git a/sources/PNpedia/.gitignore b/sources/PNpedia/.gitignore new file mode 100644 index 00000000..d239ddcb --- /dev/null +++ b/sources/PNpedia/.gitignore @@ -0,0 +1 @@ +PNpedia diff --git a/sources/PNpedia/Project.toml b/sources/PNpedia/Project.toml new file mode 100644 index 00000000..4cffcc42 --- /dev/null +++ b/sources/PNpedia/Project.toml @@ -0,0 +1,3 @@ +[deps] +PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d" +SymPyPythonCall = "bc8888f7-b21e-4b7c-a06a-5d9c9496438c" diff --git a/sources/PNpedia/README.md b/sources/PNpedia/README.md new file mode 100644 index 00000000..e03ab610 --- /dev/null +++ b/sources/PNpedia/README.md @@ -0,0 +1,13 @@ +# PNpedia + +This directory contains code to translate results from David +Trestini's [PNpedia](https://github.com/davidtrestini/PNpedia) — which +are given as `.txt` files containing Mathematica output — into Julia +code. + +Though it is `.gitignore`d, to run the code you should first clone +PNpedia into this directory, so that the files are available + +```bash +git clone https://github.com/davidtrestini/PNpedia.git +``` diff --git a/sources/PNpedia/characters.html b/sources/PNpedia/characters.html new file mode 100644 index 00000000..80ccc0b6 --- /dev/null +++ b/sources/PNpedia/characters.html @@ -0,0 +1,20 @@ +

The Wolfram Language not only has systemwide support for arbitrary Unicode characters, but also includes nearly a thousand carefully designed characters for mathematical notation and technical presentationall fully integrated into the Wolfram Language's input, output, and graphics.

nnn or \[Name] named character (e.g. α, a, [Alpha])

Insert Special Character palette of all named special characters

Wolfram Language Syntax »

  ▪  °  ▪  π  ▪  ×  ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪  ...

\[Degree]  ▪  \[ImaginaryI]  ▪  \[Times]  ▪  \[Element]  ▪  \[Rule]  ▪  ...

Greek Letters »

α  ▪  β  ▪  θ  ▪  ϑ  ▪  ϕ  ▪  ω  ▪  Δ  ▪  Ψ  ▪  Ω  ▪  Ϡ  ▪  ...

\[Alpha]  ▪  \[CurlyTheta]  ▪  \[CapitalDelta]  ▪  \[Sampi]  ▪  ...

Notational Alphabets »

  ▪    ▪    ▪    ▪    ▪    ▪  a  ▪  A  ▪    ▪  ...

\[ScriptA]  ▪  \[ScriptCapitalA]  ▪  \[GothicA]  ▪  \[FormalA]  ▪  \[Aleph]  ▪  ...

Mathematical Notation »

  ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪  ...

\[Integral]  ▪  \[Sum]  ▪  \[Del]  ▪  \[ForAll]  ▪  \[CirclePlus]  ▪  ...

Arrows & Arrow-Like Forms »

  ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪  ...

\[RightArrow]  ▪  \[LongRightArrow]  ▪  \[DoubleRightArrow]  ▪  \[LeftRightArrow]  ▪  ...

Textual Forms »

  ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪  ¿  ▪  ©  ▪  ...

\[Dash]  ▪  \[LongDash]  ▪  \[Bullet]  ▪  \[Copyright]  ▪  ...

Currency, Units, and Special Notations »

  ▪  £  ▪  µ  ▪  Å  ▪    ▪    ▪    ▪    ▪    ▪    ▪  \[WhiteKnight]  ▪  ...

\[Euro]  ▪  \[Sterling]  ▪  \[Micro]  ▪  \[Mars]  ▪  \[Natural]  ▪  ...

User Interfaces & Documentation »

  ▪  »  ▪    ▪    ▪    ▪    ▪    ▪  ...

Shapes, Icons, etc. »

  ▪    ▪    ▪    ▪    ▪    ▪    ▪    ▪  ...

\[FilledSquare]  ▪  \[EmptySquare]  ▪  \[HappySmiley]  ▪  ...

Non-Printing Characters »

\[ThinSpace]  ▪  \[NonBreakingSpace]  ▪  \[InvisibleComma]  ▪  \[AlignmentMarker]  ▪  ...

International Characters »

é  ▪  ö  ▪  à  ▪  á  ▪  â  ▪  ã  ▪  ä  ▪  å  ▪  ç  ▪  č  ▪  ø  ▪  æ  ▪  ß  ▪  ...

\[EAcute]  ▪  \[ODoubleDot]  ▪  \[CHacek]  ▪  ...

Formal Symbols »

a  ▪  A  ▪  ω  ▪  ...

\[FormalA]  ▪  \[FormalCapitalA]  ▪  \[FormalOmega]  ▪  ...

FullForm show characters in their full named form

\.nn, \:nnnn, \|nnnnnn enter forms with hex values corresponding to Unicode code points

\alpha, &Alpha;, etc. enter TeX, HTML, SGML, etc. forms

ToCharacterCode  ▪  FromCharacterCode  ▪  CharacterRange

StringToByteArray  ▪  ByteArrayToString

Alphabet

+
+

+ Alphabet[] +

+

gives a list of the lowercase letters a through z in the English alphabet.

+
+
+

+ Alphabet[type] +

+

gives the alphabet for the language or class type.

+
+
+

+ Alphabet[type,prop] +

+

gives the alphabet defined by prop for the language or class type .

+
+
alphabets for different scripts

diff --git a/sources/PNpedia/test.jl b/sources/PNpedia/test.jl new file mode 100644 index 00000000..70138be7 --- /dev/null +++ b/sources/PNpedia/test.jl @@ -0,0 +1,96 @@ +raw""" + +We need to parse Mathematica expressions in Julia, using SymPy's parsing capabilities. +Unfortunately, at the moment, there is a bug in SymPy + + https://github.com/sympy/sympy/issues/27868 + +that prevents it from parsing, e.g., `Sqrt[2]*σ`, which does occur in these expressions. +There is a PR at + + https://github.com/sympy/sympy/pull/27876 + +that claims to fix this, but it has not been merged yet. + +Also, David Trestini has evidently used `FullForm` to output the Mathematica to TXT files, +which translates the Greek letters to their full names — e.g., `ν` becomes `\[Nu]` — which +sympy cannot parse. Specifically, `FullForm` encodes its output as "PrintableASCII". + +There are some packages that may be useful for translating quite generally (in descending +order of how up-to-date I would guess they are): + + * `pygments-mathematica` + * `mathics-scanner` + * `FoxySheep2` + +I'm wondering if it's worthwhile to to write a translator by getting all possible identifier +letters in Python, using + + import sys + [c for c in map(chr, range(sys.maxunicode+1)) if ("_"+c).isidentifier()] + +Then, we can take that into Mathematica, run each through `FullForm`, and create a JSON file +or something that we can read in with Python to replace the identifiers. There are 139,463 +such identifiers — some of which may not output at all with `FullForm`, and some of which +(not many) will be output exactly as input, so don't need to be included. + +Note that Python's spec for identifiers lives at + + https://docs.python.org/3/reference/lexical_analysis.html#identifiers + +A few useful pieces of information I glean from that: + +> Within the ASCII range (U+0001..U+007F), the valid characters for identifiers include the +> uppercase and lowercase letters A through Z, the underscore _ and, except for the first +> character, the digits 0 through 9. + +> All identifiers are converted into the normal form NFKC while parsing; comparison of +> identifiers is based on NFKC. + +I suppose it's possible that some of these things that map to the same character in NFKC +could come up, and be encoded differently in Mathematica. In that case, the output of the +"translate-to-python" function would be able to output different characters that map to the +same character in NFKC, but that's just a problem with how python works, so I don't know +that we can do anything about it. Maybe warn about it? + + +One problem is unicode's combining characters, some of which + +""" + +using Pkg +Pkg.activate(@__DIR__) + +import SymPyPythonCall +import PythonCall + +greek_replacements = ( + raw"\[Nu]" => "ν", + raw"\[Delta]" => "δ", + raw"\[Tau]" => "τ", + raw"\[Chi]" => "χ", + raw"\[Sigma]" => "σ", + raw"\[Kappa]" => "κ", + raw"\[Lambda]" => "λ", +) + +const parse_mathematica = PythonCall.pyimport( + "sympy.parsing.mathematica" => "parse_mathematica" +) + +s = replace( + raw"((1594323*I)/4480)*Sqrt[Pi/4199]*x^(9/2)*\[Nu]*(\[Delta] - 6*\[Delta]*\[Nu] + 10*\[Delta]*\[Nu]^2 - 4*\[Delta]*\[Nu]^3)", + greek_replacements..., +) + +ex = parse_mathematica(s)#, Dict("EllipticE[x]"=>"elliptic_e(x)")) + +const elliptic_e = PythonCall.pyimport( + "sympy.functions.special.elliptic_integrals" => "elliptic_e" +) + +s = raw"(Sqrt[Pi])/(2*EllipticE[m])" +s = raw"((1594323*I)/4480)*Sqrt[Pi/4199]*x^(9/2)*\[Nu]*(\[Delta] - 6*\[Delta]*\[Nu] + 10*\[Delta]*\[Nu]^2 - 4*\[Delta]*\[Nu]^3)" +ex = parse_mathematica(s)#, Dict("EllipticE[x]"=>"elliptic_e(x)")) + +ex.args[2].args[0].args diff --git a/sources/parse-literature/.python-version b/sources/parse-literature/.python-version new file mode 100644 index 00000000..e4fba218 --- /dev/null +++ b/sources/parse-literature/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/sources/parse-literature/README.md b/sources/parse-literature/README.md new file mode 100644 index 00000000..e69de29b diff --git a/sources/parse-literature/main.py b/sources/parse-literature/main.py new file mode 100644 index 00000000..839cdad8 --- /dev/null +++ b/sources/parse-literature/main.py @@ -0,0 +1,6 @@ +def main(): + print("Hello from parse-literature!") + + +if __name__ == "__main__": + main() diff --git a/sources/parse-literature/pyproject.toml b/sources/parse-literature/pyproject.toml new file mode 100644 index 00000000..5beb3793 --- /dev/null +++ b/sources/parse-literature/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "parse-literature" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "ipython>=9.3.0", + "mathics-omnibus>=8.0.0", +] diff --git a/sources/parse-literature/uv.lock b/sources/parse-literature/uv.lock new file mode 100644 index 00000000..503957c3 --- /dev/null +++ b/sources/parse-literature/uv.lock @@ -0,0 +1,1815 @@ +version = 1 +revision = 2 +requires-python = ">=3.12" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "asgiref" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/38/b3395cc9ad1b56d2ddac9970bc8f4141312dbaec28bc7c218b0dfafd0f42/asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590", size = 35186, upload-time = "2024-03-22T14:39:36.863Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", size = 23828, upload-time = "2024-03-22T14:39:34.521Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, +] + +[[package]] +name = "blis" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f3/7c5a47a0d5ec0362bab29fd4f497b4b1975473bf30b7a02bc9c0b0e84f7a/blis-1.3.0.tar.gz", hash = "sha256:1695a87e3fc4c20d9b9140f5238cac0514c411b750e8cdcec5d8320c71f62e99", size = 2510328, upload-time = "2025-04-03T15:09:47.767Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/3f/67140d6588e600577f92d2c938e9492a8cd0706bab770978ee84ecb86e70/blis-1.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef188f1f914d52acbbd75993ba25554e381ec9099758b340cd0da41af94ae8ae", size = 6988854, upload-time = "2025-04-03T15:09:13.203Z" }, + { url = "https://files.pythonhosted.org/packages/d1/05/30587d1b168fa27d1bf6869a1be4bcb3f10493f836381a033aa9c7a10ab8/blis-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:626f84522faa51d5a52f9820551a84a5e02490bf6d1abdfc8d27934a0ff939de", size = 1282465, upload-time = "2025-04-03T15:09:15.081Z" }, + { url = "https://files.pythonhosted.org/packages/35/13/60d2dd0443a7a56a0a160d873444e4b9189bb2939d93457864432ee18c90/blis-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56e0454ce44bc08797383ce427ee5e2b044aab1eafb450eab82e86f8bfac853", size = 3061088, upload-time = "2025-04-03T15:09:16.535Z" }, + { url = "https://files.pythonhosted.org/packages/2f/30/4909baf57c3cd48414c284e4fced42157c4768f83bf6c95b0bb446192b45/blis-1.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9bb5770efe233374d73a567af5cdef24f48bead83d118bdb9bd5c2187b0f010", size = 3259127, upload-time = "2025-04-03T15:09:18.528Z" }, + { url = "https://files.pythonhosted.org/packages/bb/bf/625121119107d3beafe96eb776b00a472f0210c07d07b1ed160ab7db292a/blis-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d52ce33a1895d82f2f39f7689d5e70b06ebba6bc6f610046ecd81db88d650aac", size = 11619003, upload-time = "2025-04-03T15:09:20.139Z" }, + { url = "https://files.pythonhosted.org/packages/81/92/0bad7a4c29c7a1ab10db27b04babec7ca4a3f504543ef2d1f985fb84c41a/blis-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6c78e8dd420e0e695df0ceecf950f3cf823e0a1b8c2871a7e35117c744d45861", size = 3062135, upload-time = "2025-04-03T15:09:22.142Z" }, + { url = "https://files.pythonhosted.org/packages/35/b5/ea9b4f6b75c9dce24ce0d6fa15d5eaab54b115a57967d504e460db901c59/blis-1.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7a060700ee98ea44a1b9833b16d3dd1375aaa9d3230222bfc5f13c4664e5710e", size = 4298755, upload-time = "2025-04-03T15:09:24.064Z" }, + { url = "https://files.pythonhosted.org/packages/e5/c5/9b7383752cdc4ca92359c161b1086bd158b4f3cda5813a390ff9c8c1b892/blis-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:250f0b0aeca0fdde7117751a54ae6d6b6818a446a619f3c0c63f3deb77f700a8", size = 14785385, upload-time = "2025-04-03T15:09:25.74Z" }, + { url = "https://files.pythonhosted.org/packages/0c/92/6bb1940a491ce9d3ec52372bc35988bec779b16ace7e87287d981df31eeb/blis-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2e6f468467a18a7c2ac2e411643f5cfa45a435701e2c04ad4aa46bb02fc3aa5c", size = 6260208, upload-time = "2025-04-03T15:09:28.207Z" }, + { url = "https://files.pythonhosted.org/packages/91/ec/2b1e366e7b4e3cdb052a4eeba33cc6a3e25fe20566f3062dbe59a8dd7f78/blis-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4d6a91c8726d0bc3345a8e0c8b7b8e800bee0b9acc4c2a0dbeb782b8b651f824", size = 6985730, upload-time = "2025-04-03T15:09:29.884Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8b/a3374a970e1ae6138b2ec6bffeb1018068c5f0dbf2b12dd8ab16a47ae4a0/blis-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e3c20bc3d7143383195cc472373fb301d3bafbacd8ab8f3bffc27c68bef45d81", size = 1280751, upload-time = "2025-04-03T15:09:32.007Z" }, + { url = "https://files.pythonhosted.org/packages/53/97/83cc91c451709c85650714df3464024bf37ef791be1e0fae0d2a0f945da6/blis-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:778c4b84c6eccab223d8afe20727820f6c7dd7a010c3bfb262104cc83b0a8e4c", size = 3047726, upload-time = "2025-04-03T15:09:33.521Z" }, + { url = "https://files.pythonhosted.org/packages/ae/21/fbf9b45d6af91c5ce32df4007886c0332b977558cba34b0bc00b98ebc188/blis-1.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69584589977366366cd99cc7cb23a76a814df8bcae8b777fde4a94e8684c1fb8", size = 3249935, upload-time = "2025-04-03T15:09:36.264Z" }, + { url = "https://files.pythonhosted.org/packages/ee/b1/5716b8cd784c0a0d08f9b3773c8eb4c37f5f9ed3a9f6ef961373e123b1cf/blis-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2adc4549e610b59e8db5a57ab7206e4ac1502ac5b261ed0e6de42d3fb311d5", size = 11614296, upload-time = "2025-04-03T15:09:38.342Z" }, + { url = "https://files.pythonhosted.org/packages/36/0f/e2ed2642cf41dcae3431cfbcd94543646adba46eaa2736ac27647216e4f7/blis-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9aaa84df638e0bb7909a35e3c220168df2b90f267967b3004a88f57b49fbe4ec", size = 3063082, upload-time = "2025-04-03T15:09:40.329Z" }, + { url = "https://files.pythonhosted.org/packages/cb/f0/627a36b99a9cd9af73be7bb451d6884d5b4aece297eb29b9fc13e70c1f2b/blis-1.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0da7b54331bed31aa55839da2d0e5451447e1f5e8a9367cce7ff1fb27498a22a", size = 4290919, upload-time = "2025-04-03T15:09:41.845Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f9/a415707185a82082b96ab857e5c3b7a59b0ad73ed04ace1cbb64835c3432/blis-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:682175bf2d047129b3715e3f1305c6b23a45e2ce24c4b1d0fa2eb03eb877edd4", size = 14795975, upload-time = "2025-04-03T15:09:43.611Z" }, + { url = "https://files.pythonhosted.org/packages/16/f1/8cc8118946dbb9cbd74f406d30d31ee8d2f723f6fb4c8245e2bc67175fd4/blis-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:91de2baf03da3a173cf62771f1d6b9236a27a8cbd0e0033be198f06ef6224986", size = 6258624, upload-time = "2025-04-03T15:09:46.056Z" }, +] + +[[package]] +name = "catalogue" +version = "2.0.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/b4/244d58127e1cdf04cf2dc7d9566f0d24ef01d5ce21811bab088ecc62b5ea/catalogue-2.0.10.tar.gz", hash = "sha256:4f56daa940913d3f09d589c191c74e5a6d51762b3a9e37dd53b7437afd6cda15", size = 19561, upload-time = "2023-09-25T06:29:24.962Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/96/d32b941a501ab566a16358d68b6eb4e4acc373fab3c3c4d7d9e649f7b4bb/catalogue-2.0.10-py3-none-any.whl", hash = "sha256:58c2de0020aa90f4a2da7dfad161bf7b3b054c86a5f09fcedc0b2b740c109a9f", size = 17325, upload-time = "2023-09-25T06:29:23.337Z" }, +] + +[[package]] +name = "certifi" +version = "2025.6.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b", size = 158753, upload-time = "2025-06-15T02:45:51.329Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057", size = 157650, upload-time = "2025-06-15T02:45:49.977Z" }, +] + +[[package]] +name = "chardet" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618, upload-time = "2023-08-01T19:23:02.662Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385, upload-time = "2023-08-01T19:23:00.661Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, + { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, + { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, + { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, + { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, + { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, + { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, + { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, + { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, + { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, + { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, + { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, + { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, + { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, + { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, + { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, + { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, + { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, + { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, + { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, + { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, +] + +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + +[[package]] +name = "cloudpathlib" +version = "0.21.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/15/ae3256348834b92b9594d73eb7230538bae2bf726c2d721b920a668017c5/cloudpathlib-0.21.1.tar.gz", hash = "sha256:f26a855abf34d98f267aafd15efdb2db3c9665913dbabe5fad079df92837a431", size = 45295, upload-time = "2025-05-15T02:32:05.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/e7/6fea57b887f8e367c1e4a496ba03bfaf57824b766f777723ce1faf28834b/cloudpathlib-0.21.1-py3-none-any.whl", hash = "sha256:bfe580ad72ec030472ec233cd7380701b2d3227da7b2898387bd170aa70c803c", size = 52776, upload-time = "2025-05-15T02:32:03.99Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "columnize" +version = "0.3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/ab/47c68ccca6052e18ccce562e6af92404b08cb2715edd9e9da31f4118cbcd/columnize-0.3.11.tar.gz", hash = "sha256:a631b863b310a6c1457629b7bf32a3777ea5a407f8985311ce8c24c31d1d8bb2", size = 18776, upload-time = "2022-03-12T01:17:02.747Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/da/c1f84838ecb3e84c3c85c691f51f1e2dfcf7be745761d9f6462c909175ad/columnize-0.3.11-py3-none-any.whl", hash = "sha256:3c474ca632e474df8f012843fb74a4c0bea4e8876d49a17f952f8e82f14cbc3d", size = 7750, upload-time = "2022-03-12T01:15:38.843Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c3/9902c94a4835f64d7151c6c5c40687de1438f37118d9270d15b5a2212ab1/columnize-0.3.11-py36-none-any.whl", hash = "sha256:10dc33cbe4ef96b777b407a96078cea2b195acfaf86592357e318180c81a83d9", size = 7728, upload-time = "2022-03-12T01:15:37.727Z" }, +] + +[[package]] +name = "confection" +version = "0.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "srsly" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/d3/57c6631159a1b48d273b40865c315cf51f89df7a9d1101094ef12e3a37c2/confection-0.1.5.tar.gz", hash = "sha256:8e72dd3ca6bd4f48913cd220f10b8275978e740411654b6e8ca6d7008c590f0e", size = 38924, upload-time = "2024-05-31T16:17:01.559Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/00/3106b1854b45bd0474ced037dfe6b73b90fe68a68968cef47c23de3d43d2/confection-0.1.5-py3-none-any.whl", hash = "sha256:e29d3c3f8eac06b3f77eb9dfb4bf2fc6bcc9622a98ca00a698e3d019c6430b14", size = 35451, upload-time = "2024-05-31T16:16:59.075Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, + { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, + { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, + { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, + { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, + { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, + { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630, upload-time = "2025-04-15T17:38:19.142Z" }, + { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670, upload-time = "2025-04-15T17:38:23.688Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694, upload-time = "2025-04-15T17:38:28.238Z" }, + { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986, upload-time = "2025-04-15T17:38:33.502Z" }, + { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060, upload-time = "2025-04-15T17:38:38.672Z" }, + { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747, upload-time = "2025-04-15T17:38:43.712Z" }, + { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895, upload-time = "2025-04-15T17:39:00.224Z" }, + { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098, upload-time = "2025-04-15T17:43:29.649Z" }, + { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535, upload-time = "2025-04-15T17:44:44.532Z" }, + { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096, upload-time = "2025-04-15T17:44:48.194Z" }, + { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090, upload-time = "2025-04-15T17:43:34.084Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643, upload-time = "2025-04-15T17:43:38.626Z" }, + { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443, upload-time = "2025-04-15T17:43:44.522Z" }, + { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865, upload-time = "2025-04-15T17:43:49.545Z" }, + { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162, upload-time = "2025-04-15T17:43:54.203Z" }, + { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355, upload-time = "2025-04-15T17:44:01.025Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935, upload-time = "2025-04-15T17:44:17.322Z" }, + { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168, upload-time = "2025-04-15T17:44:33.43Z" }, + { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550, upload-time = "2025-04-15T17:44:37.092Z" }, + { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "cymem" +version = "2.0.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/4a/1acd761fb6ac4c560e823ce40536a62f886f2d59b2763b5c3fc7e9d92101/cymem-2.0.11.tar.gz", hash = "sha256:efe49a349d4a518be6b6c6b255d4a80f740a341544bde1a807707c058b88d0bd", size = 10346, upload-time = "2025-01-16T21:50:41.045Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/67/0d74f7e9d79f934368a78fb1d1466b94bebdbff14f8ae94dd3e4ea8738bb/cymem-2.0.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0fbe19ce653cd688842d81e5819dc63f911a26e192ef30b0b89f0ab2b192ff2", size = 42621, upload-time = "2025-01-16T21:49:46.585Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d6/f7a19c63b48efc3f00a3ee8d69070ac90202e1e378f6cf81b8671f0cf762/cymem-2.0.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de72101dc0e6326f6a2f73e05a438d1f3c6110d41044236d0fbe62925091267d", size = 42249, upload-time = "2025-01-16T21:49:48.973Z" }, + { url = "https://files.pythonhosted.org/packages/d7/60/cdc434239813eef547fb99b6d0bafe31178501702df9b77c4108c9a216f6/cymem-2.0.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee4395917f6588b8ac1699499128842768b391fe8896e8626950b4da5f9a406", size = 224758, upload-time = "2025-01-16T21:49:51.382Z" }, + { url = "https://files.pythonhosted.org/packages/1d/68/8fa6efae17cd3b2ba9a2f83b824867c5b65b06f7aec3f8a0d0cabdeffb9b/cymem-2.0.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b02f2b17d760dc3fe5812737b1ce4f684641cdd751d67761d333a3b5ea97b83", size = 227995, upload-time = "2025-01-16T21:49:54.538Z" }, + { url = "https://files.pythonhosted.org/packages/e4/f3/ceda70bf6447880140602285b7c6fa171cb7c78b623d35345cc32505cd06/cymem-2.0.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:04ee6b4041ddec24512d6e969ed6445e57917f01e73b9dabbe17b7e6b27fef05", size = 215325, upload-time = "2025-01-16T21:49:57.229Z" }, + { url = "https://files.pythonhosted.org/packages/d3/47/6915eaa521e1ce7a0ba480eecb6870cb4f681bcd64ced88c2f0ed7a744b4/cymem-2.0.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e1048dae7e627ee25f22c87bb670b13e06bc0aecc114b89b959a798d487d1bf4", size = 216447, upload-time = "2025-01-16T21:50:00.432Z" }, + { url = "https://files.pythonhosted.org/packages/7b/be/8e02bdd31e557f642741a06c8e886782ef78f0b00daffd681922dc9bbc88/cymem-2.0.11-cp312-cp312-win_amd64.whl", hash = "sha256:0c269c7a867d74adeb9db65fa1d226342aacf44d64b7931282f0b0eb22eb6275", size = 39283, upload-time = "2025-01-16T21:50:03.384Z" }, + { url = "https://files.pythonhosted.org/packages/bd/90/b064e2677e27a35cf3605146abc3285d4f599cc1b6c18fc445ae876dd1e3/cymem-2.0.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4a311c82f743275c84f708df89ac5bf60ddefe4713d532000c887931e22941f", size = 42389, upload-time = "2025-01-16T21:50:05.925Z" }, + { url = "https://files.pythonhosted.org/packages/fd/60/7aa0561a6c1f0d42643b02c4fdeb2a16181b0ff4e85d73d2d80c6689e92a/cymem-2.0.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:02ed92bead896cca36abad00502b14fa651bdf5d8319461126a2d5ac8c9674c5", size = 41948, upload-time = "2025-01-16T21:50:08.375Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4e/88a29cc5575374982e527b4ebcab3781bdc826ce693c6418a0f836544246/cymem-2.0.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44ddd3588379f8f376116384af99e3fb5f90091d90f520c341942618bf22f05e", size = 219382, upload-time = "2025-01-16T21:50:13.089Z" }, + { url = "https://files.pythonhosted.org/packages/9b/3a/8f96e167e93b7f7ec105ed7b25c77bbf215d15bcbf4a24082cdc12234cd6/cymem-2.0.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87ec985623624bbd298762d8163fc194a096cb13282731a017e09ff8a60bb8b1", size = 222974, upload-time = "2025-01-16T21:50:17.969Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/ce016bb0c66a4776345fac7508fddec3b739b9dd4363094ac89cce048832/cymem-2.0.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3385a47285435848e0ed66cfd29b35f3ed8703218e2b17bd7a0c053822f26bf", size = 213426, upload-time = "2025-01-16T21:50:19.349Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c8/accf7cc768f751447a5050b14a195af46798bc22767ac25f49b02861b1eb/cymem-2.0.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5461e65340d6572eb64deadce79242a446a1d39cb7bf70fe7b7e007eb0d799b0", size = 219195, upload-time = "2025-01-16T21:50:21.407Z" }, + { url = "https://files.pythonhosted.org/packages/74/65/c162fbac63e867a055240b6600b92ef96c0eb7a1895312ac53c4be93d056/cymem-2.0.11-cp313-cp313-win_amd64.whl", hash = "sha256:25da111adf425c29af0cfd9fecfec1c71c8d82e2244a85166830a0817a66ada7", size = 39090, upload-time = "2025-01-16T21:50:24.239Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "django" +version = "5.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/af/77b403926025dc6f7fd7b31256394d643469418965eb528eab45d0505358/django-5.2.3.tar.gz", hash = "sha256:335213277666ab2c5cac44a792a6d2f3d58eb79a80c14b6b160cd4afc3b75684", size = 10850303, upload-time = "2025-06-10T10:14:05.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/11/7aff961db37e1ea501a2bb663d27a8ce97f3683b9e5b83d3bfead8b86fa4/django-5.2.3-py3-none-any.whl", hash = "sha256:c517a6334e0fd940066aa9467b29401b93c37cec2e61365d663b80922542069d", size = 8301935, upload-time = "2025-06-10T10:13:58.993Z" }, +] + +[[package]] +name = "executing" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693, upload-time = "2025-01-22T15:41:29.403Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702, upload-time = "2025-01-22T15:41:25.929Z" }, +] + +[[package]] +name = "flexcache" +version = "0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/b0/8a21e330561c65653d010ef112bf38f60890051d244ede197ddaa08e50c1/flexcache-0.3.tar.gz", hash = "sha256:18743bd5a0621bfe2cf8d519e4c3bfdf57a269c15d1ced3fb4b64e0ff4600656", size = 15816, upload-time = "2024-03-09T03:21:07.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/cd/c883e1a7c447479d6e13985565080e3fea88ab5a107c21684c813dba1875/flexcache-0.3-py3-none-any.whl", hash = "sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32", size = 13263, upload-time = "2024-03-09T03:21:05.635Z" }, +] + +[[package]] +name = "flexparser" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/99/b4de7e39e8eaf8207ba1a8fa2241dd98b2ba72ae6e16960d8351736d8702/flexparser-0.4.tar.gz", hash = "sha256:266d98905595be2ccc5da964fe0a2c3526fbbffdc45b65b3146d75db992ef6b2", size = 31799, upload-time = "2024-11-07T02:00:56.249Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/5e/3be305568fe5f34448807976dc82fc151d76c3e0e03958f34770286278c1/flexparser-0.4-py3-none-any.whl", hash = "sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846", size = 27625, upload-time = "2024-11-07T02:00:54.523Z" }, +] + +[[package]] +name = "fonttools" +version = "4.58.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/5a/1124b2c8cb3a8015faf552e92714040bcdbc145dfa29928891b02d147a18/fonttools-4.58.4.tar.gz", hash = "sha256:928a8009b9884ed3aae17724b960987575155ca23c6f0b8146e400cc9e0d44ba", size = 3525026, upload-time = "2025-06-13T17:25:15.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/3c/1d1792bfe91ef46f22a3d23b4deb514c325e73c17d4f196b385b5e2faf1c/fonttools-4.58.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:462211c0f37a278494e74267a994f6be9a2023d0557aaa9ecbcbfce0f403b5a6", size = 2754082, upload-time = "2025-06-13T17:24:24.862Z" }, + { url = "https://files.pythonhosted.org/packages/2a/1f/2b261689c901a1c3bc57a6690b0b9fc21a9a93a8b0c83aae911d3149f34e/fonttools-4.58.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0c7a12fb6f769165547f00fcaa8d0df9517603ae7e04b625e5acb8639809b82d", size = 2321677, upload-time = "2025-06-13T17:24:26.815Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6b/4607add1755a1e6581ae1fc0c9a640648e0d9cdd6591cc2d581c2e07b8c3/fonttools-4.58.4-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d42c63020a922154add0a326388a60a55504629edc3274bc273cd3806b4659f", size = 4896354, upload-time = "2025-06-13T17:24:28.428Z" }, + { url = "https://files.pythonhosted.org/packages/cd/95/34b4f483643d0cb11a1f830b72c03fdd18dbd3792d77a2eb2e130a96fada/fonttools-4.58.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f2b4e6fd45edc6805f5f2c355590b092ffc7e10a945bd6a569fc66c1d2ae7aa", size = 4941633, upload-time = "2025-06-13T17:24:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/81/ac/9bafbdb7694059c960de523e643fa5a61dd2f698f3f72c0ca18ae99257c7/fonttools-4.58.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f155b927f6efb1213a79334e4cb9904d1e18973376ffc17a0d7cd43d31981f1e", size = 4886170, upload-time = "2025-06-13T17:24:32.724Z" }, + { url = "https://files.pythonhosted.org/packages/ae/44/a3a3b70d5709405f7525bb7cb497b4e46151e0c02e3c8a0e40e5e9fe030b/fonttools-4.58.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e38f687d5de97c7fb7da3e58169fb5ba349e464e141f83c3c2e2beb91d317816", size = 5037851, upload-time = "2025-06-13T17:24:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/21/cb/e8923d197c78969454eb876a4a55a07b59c9c4c46598f02b02411dc3b45c/fonttools-4.58.4-cp312-cp312-win32.whl", hash = "sha256:636c073b4da9db053aa683db99580cac0f7c213a953b678f69acbca3443c12cc", size = 2187428, upload-time = "2025-06-13T17:24:36.996Z" }, + { url = "https://files.pythonhosted.org/packages/46/e6/fe50183b1a0e1018e7487ee740fa8bb127b9f5075a41e20d017201e8ab14/fonttools-4.58.4-cp312-cp312-win_amd64.whl", hash = "sha256:82e8470535743409b30913ba2822e20077acf9ea70acec40b10fcf5671dceb58", size = 2236649, upload-time = "2025-06-13T17:24:38.985Z" }, + { url = "https://files.pythonhosted.org/packages/d4/4f/c05cab5fc1a4293e6bc535c6cb272607155a0517700f5418a4165b7f9ec8/fonttools-4.58.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5f4a64846495c543796fa59b90b7a7a9dff6839bd852741ab35a71994d685c6d", size = 2745197, upload-time = "2025-06-13T17:24:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d3/49211b1f96ae49308f4f78ca7664742377a6867f00f704cdb31b57e4b432/fonttools-4.58.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e80661793a5d4d7ad132a2aa1eae2e160fbdbb50831a0edf37c7c63b2ed36574", size = 2317272, upload-time = "2025-06-13T17:24:43.428Z" }, + { url = "https://files.pythonhosted.org/packages/b2/11/c9972e46a6abd752a40a46960e431c795ad1f306775fc1f9e8c3081a1274/fonttools-4.58.4-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fe5807fc64e4ba5130f1974c045a6e8d795f3b7fb6debfa511d1773290dbb76b", size = 4877184, upload-time = "2025-06-13T17:24:45.527Z" }, + { url = "https://files.pythonhosted.org/packages/ea/24/5017c01c9ef8df572cc9eaf9f12be83ad8ed722ff6dc67991d3d752956e4/fonttools-4.58.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b610b9bef841cb8f4b50472494158b1e347d15cad56eac414c722eda695a6cfd", size = 4939445, upload-time = "2025-06-13T17:24:47.647Z" }, + { url = "https://files.pythonhosted.org/packages/79/b0/538cc4d0284b5a8826b4abed93a69db52e358525d4b55c47c8cef3669767/fonttools-4.58.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2daa7f0e213c38f05f054eb5e1730bd0424aebddbeac094489ea1585807dd187", size = 4878800, upload-time = "2025-06-13T17:24:49.766Z" }, + { url = "https://files.pythonhosted.org/packages/5a/9b/a891446b7a8250e65bffceb248508587958a94db467ffd33972723ab86c9/fonttools-4.58.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:66cccb6c0b944496b7f26450e9a66e997739c513ffaac728d24930df2fd9d35b", size = 5021259, upload-time = "2025-06-13T17:24:51.754Z" }, + { url = "https://files.pythonhosted.org/packages/17/b2/c4d2872cff3ace3ddd1388bf15b76a1d8d5313f0a61f234e9aed287e674d/fonttools-4.58.4-cp313-cp313-win32.whl", hash = "sha256:94d2aebb5ca59a5107825520fde596e344652c1f18170ef01dacbe48fa60c889", size = 2185824, upload-time = "2025-06-13T17:24:54.324Z" }, + { url = "https://files.pythonhosted.org/packages/98/57/cddf8bcc911d4f47dfca1956c1e3aeeb9f7c9b8e88b2a312fe8c22714e0b/fonttools-4.58.4-cp313-cp313-win_amd64.whl", hash = "sha256:b554bd6e80bba582fd326ddab296e563c20c64dca816d5e30489760e0c41529f", size = 2236382, upload-time = "2025-06-13T17:24:56.291Z" }, + { url = "https://files.pythonhosted.org/packages/0b/2f/c536b5b9bb3c071e91d536a4d11f969e911dbb6b227939f4c5b0bca090df/fonttools-4.58.4-py3-none-any.whl", hash = "sha256:a10ce13a13f26cbb9f37512a4346bb437ad7e002ff6fa966a7ce7ff5ac3528bd", size = 1114660, upload-time = "2025-06-13T17:25:13.321Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "ipython" +version = "9.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/09/4c7e06b96fbd203e06567b60fb41b06db606b6a82db6db7b2c85bb72a15c/ipython-9.3.0.tar.gz", hash = "sha256:79eb896f9f23f50ad16c3bc205f686f6e030ad246cc309c6279a242b14afe9d8", size = 4426460, upload-time = "2025-05-31T16:34:55.678Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/99/9ed3d52d00f1846679e3aa12e2326ac7044b5e7f90dc822b60115fa533ca/ipython-9.3.0-py3-none-any.whl", hash = "sha256:1a0b6dd9221a1f5dddf725b57ac0cb6fddc7b5f470576231ae9162b9b3455a04", size = 605320, upload-time = "2025-05-31T16:34:52.154Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475, upload-time = "2025-05-23T12:04:37.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746, upload-time = "2025-05-23T12:04:35.124Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538, upload-time = "2024-12-24T18:30:51.519Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/aa/cea685c4ab647f349c3bc92d2daf7ae34c8e8cf405a6dcd3a497f58a2ac3/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", size = 124152, upload-time = "2024-12-24T18:29:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/c5/0b/8db6d2e2452d60d5ebc4ce4b204feeb16176a851fd42462f66ade6808084/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", size = 66555, upload-time = "2024-12-24T18:29:19.146Z" }, + { url = "https://files.pythonhosted.org/packages/60/26/d6a0db6785dd35d3ba5bf2b2df0aedc5af089962c6eb2cbf67a15b81369e/kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", size = 65067, upload-time = "2024-12-24T18:29:20.096Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ed/1d97f7e3561e09757a196231edccc1bcf59d55ddccefa2afc9c615abd8e0/kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", size = 1378443, upload-time = "2024-12-24T18:29:22.843Z" }, + { url = "https://files.pythonhosted.org/packages/29/61/39d30b99954e6b46f760e6289c12fede2ab96a254c443639052d1b573fbc/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", size = 1472728, upload-time = "2024-12-24T18:29:24.463Z" }, + { url = "https://files.pythonhosted.org/packages/0c/3e/804163b932f7603ef256e4a715e5843a9600802bb23a68b4e08c8c0ff61d/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", size = 1478388, upload-time = "2024-12-24T18:29:25.776Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/60eaa75169a154700be74f875a4d9961b11ba048bef315fbe89cb6999056/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", size = 1413849, upload-time = "2024-12-24T18:29:27.202Z" }, + { url = "https://files.pythonhosted.org/packages/bc/b3/9458adb9472e61a998c8c4d95cfdfec91c73c53a375b30b1428310f923e4/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", size = 1475533, upload-time = "2024-12-24T18:29:28.638Z" }, + { url = "https://files.pythonhosted.org/packages/e4/7a/0a42d9571e35798de80aef4bb43a9b672aa7f8e58643d7bd1950398ffb0a/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", size = 2268898, upload-time = "2024-12-24T18:29:30.368Z" }, + { url = "https://files.pythonhosted.org/packages/d9/07/1255dc8d80271400126ed8db35a1795b1a2c098ac3a72645075d06fe5c5d/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", size = 2425605, upload-time = "2024-12-24T18:29:33.151Z" }, + { url = "https://files.pythonhosted.org/packages/84/df/5a3b4cf13780ef6f6942df67b138b03b7e79e9f1f08f57c49957d5867f6e/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", size = 2375801, upload-time = "2024-12-24T18:29:34.584Z" }, + { url = "https://files.pythonhosted.org/packages/8f/10/2348d068e8b0f635c8c86892788dac7a6b5c0cb12356620ab575775aad89/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", size = 2520077, upload-time = "2024-12-24T18:29:36.138Z" }, + { url = "https://files.pythonhosted.org/packages/32/d8/014b89fee5d4dce157d814303b0fce4d31385a2af4c41fed194b173b81ac/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", size = 2338410, upload-time = "2024-12-24T18:29:39.991Z" }, + { url = "https://files.pythonhosted.org/packages/bd/72/dfff0cc97f2a0776e1c9eb5bef1ddfd45f46246c6533b0191887a427bca5/kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", size = 71853, upload-time = "2024-12-24T18:29:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/dc/85/220d13d914485c0948a00f0b9eb419efaf6da81b7d72e88ce2391f7aed8d/kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", size = 65424, upload-time = "2024-12-24T18:29:44.38Z" }, + { url = "https://files.pythonhosted.org/packages/79/b3/e62464a652f4f8cd9006e13d07abad844a47df1e6537f73ddfbf1bc997ec/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", size = 124156, upload-time = "2024-12-24T18:29:45.368Z" }, + { url = "https://files.pythonhosted.org/packages/8d/2d/f13d06998b546a2ad4f48607a146e045bbe48030774de29f90bdc573df15/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", size = 66555, upload-time = "2024-12-24T18:29:46.37Z" }, + { url = "https://files.pythonhosted.org/packages/59/e3/b8bd14b0a54998a9fd1e8da591c60998dc003618cb19a3f94cb233ec1511/kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", size = 65071, upload-time = "2024-12-24T18:29:47.333Z" }, + { url = "https://files.pythonhosted.org/packages/f0/1c/6c86f6d85ffe4d0ce04228d976f00674f1df5dc893bf2dd4f1928748f187/kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", size = 1378053, upload-time = "2024-12-24T18:29:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b9/1c6e9f6dcb103ac5cf87cb695845f5fa71379021500153566d8a8a9fc291/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", size = 1472278, upload-time = "2024-12-24T18:29:51.164Z" }, + { url = "https://files.pythonhosted.org/packages/ee/81/aca1eb176de671f8bda479b11acdc42c132b61a2ac861c883907dde6debb/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", size = 1478139, upload-time = "2024-12-24T18:29:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/49/f4/e081522473671c97b2687d380e9e4c26f748a86363ce5af48b4a28e48d06/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", size = 1413517, upload-time = "2024-12-24T18:29:53.941Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/6a7d025d8da8c4931522922cd706105aa32b3291d1add8c5427cdcd66e63/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", size = 1474952, upload-time = "2024-12-24T18:29:56.523Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/13fa685ae167bee5d94b415991c4fc7bb0a1b6ebea6e753a87044b209678/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794", size = 2269132, upload-time = "2024-12-24T18:29:57.989Z" }, + { url = "https://files.pythonhosted.org/packages/ef/92/bb7c9395489b99a6cb41d502d3686bac692586db2045adc19e45ee64ed23/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", size = 2425997, upload-time = "2024-12-24T18:29:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/ed/12/87f0e9271e2b63d35d0d8524954145837dd1a6c15b62a2d8c1ebe0f182b4/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", size = 2376060, upload-time = "2024-12-24T18:30:01.338Z" }, + { url = "https://files.pythonhosted.org/packages/02/6e/c8af39288edbce8bf0fa35dee427b082758a4b71e9c91ef18fa667782138/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", size = 2520471, upload-time = "2024-12-24T18:30:04.574Z" }, + { url = "https://files.pythonhosted.org/packages/13/78/df381bc7b26e535c91469f77f16adcd073beb3e2dd25042efd064af82323/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", size = 2338793, upload-time = "2024-12-24T18:30:06.25Z" }, + { url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", size = 71855, upload-time = "2024-12-24T18:30:07.535Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b6/21529d595b126ac298fdd90b705d87d4c5693de60023e0efcb4f387ed99e/kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", size = 65430, upload-time = "2024-12-24T18:30:08.504Z" }, + { url = "https://files.pythonhosted.org/packages/34/bd/b89380b7298e3af9b39f49334e3e2a4af0e04819789f04b43d560516c0c8/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", size = 126294, upload-time = "2024-12-24T18:30:09.508Z" }, + { url = "https://files.pythonhosted.org/packages/83/41/5857dc72e5e4148eaac5aa76e0703e594e4465f8ab7ec0fc60e3a9bb8fea/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", size = 67736, upload-time = "2024-12-24T18:30:11.039Z" }, + { url = "https://files.pythonhosted.org/packages/e1/d1/be059b8db56ac270489fb0b3297fd1e53d195ba76e9bbb30e5401fa6b759/kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", size = 66194, upload-time = "2024-12-24T18:30:14.886Z" }, + { url = "https://files.pythonhosted.org/packages/e1/83/4b73975f149819eb7dcf9299ed467eba068ecb16439a98990dcb12e63fdd/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", size = 1465942, upload-time = "2024-12-24T18:30:18.927Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2c/30a5cdde5102958e602c07466bce058b9d7cb48734aa7a4327261ac8e002/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", size = 1595341, upload-time = "2024-12-24T18:30:22.102Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9b/1e71db1c000385aa069704f5990574b8244cce854ecd83119c19e83c9586/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", size = 1598455, upload-time = "2024-12-24T18:30:24.947Z" }, + { url = "https://files.pythonhosted.org/packages/85/92/c8fec52ddf06231b31cbb779af77e99b8253cd96bd135250b9498144c78b/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", size = 1522138, upload-time = "2024-12-24T18:30:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/0b/51/9eb7e2cd07a15d8bdd976f6190c0164f92ce1904e5c0c79198c4972926b7/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", size = 1582857, upload-time = "2024-12-24T18:30:28.86Z" }, + { url = "https://files.pythonhosted.org/packages/0f/95/c5a00387a5405e68ba32cc64af65ce881a39b98d73cc394b24143bebc5b8/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", size = 2293129, upload-time = "2024-12-24T18:30:30.34Z" }, + { url = "https://files.pythonhosted.org/packages/44/83/eeb7af7d706b8347548313fa3a3a15931f404533cc54fe01f39e830dd231/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", size = 2421538, upload-time = "2024-12-24T18:30:33.334Z" }, + { url = "https://files.pythonhosted.org/packages/05/f9/27e94c1b3eb29e6933b6986ffc5fa1177d2cd1f0c8efc5f02c91c9ac61de/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", size = 2390661, upload-time = "2024-12-24T18:30:34.939Z" }, + { url = "https://files.pythonhosted.org/packages/d9/d4/3c9735faa36ac591a4afcc2980d2691000506050b7a7e80bcfe44048daa7/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", size = 2546710, upload-time = "2024-12-24T18:30:37.281Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fa/be89a49c640930180657482a74970cdcf6f7072c8d2471e1babe17a222dc/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", size = 2349213, upload-time = "2024-12-24T18:30:40.019Z" }, +] + +[[package]] +name = "langcodes" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "language-data" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/7a/5a97e327063409a5caa21541e6d08ae4a0f2da328447e9f2c7b39e179226/langcodes-3.5.0.tar.gz", hash = "sha256:1eef8168d07e51e131a2497ffecad4b663f6208e7c3ae3b8dc15c51734a6f801", size = 191030, upload-time = "2024-11-19T10:23:45.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/6b/068c2ea7a712bf805c62445bd9e9c06d7340358ef2824150eceac027444b/langcodes-3.5.0-py3-none-any.whl", hash = "sha256:853c69d1a35e0e13da2f427bb68fb2fa4a8f4fb899e0c62ad8df8d073dcfed33", size = 182974, upload-time = "2024-11-19T10:23:42.824Z" }, +] + +[[package]] +name = "langid" +version = "1.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/4c/0fb7d900d3b0b9c8703be316fbddffecdab23c64e1b46c7a83561d78bd43/langid-1.1.6.tar.gz", hash = "sha256:044bcae1912dab85c33d8e98f2811b8f4ff1213e5e9a9e9510137b84da2cb293", size = 1925978, upload-time = "2016-04-05T22:34:15.786Z" } + +[[package]] +name = "language-data" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marisa-trie" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/ce/3f144716a9f2cbf42aa86ebc8b085a184be25c80aa453eea17c294d239c1/language_data-1.3.0.tar.gz", hash = "sha256:7600ef8aa39555145d06c89f0c324bf7dab834ea0b0a439d8243762e3ebad7ec", size = 5129310, upload-time = "2024-11-19T10:21:37.912Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/e9/5a5ffd9b286db82be70d677d0a91e4d58f7912bb8dd026ddeeb4abe70679/language_data-1.3.0-py3-none-any.whl", hash = "sha256:e2ee943551b5ae5f89cd0e801d1fc3835bb0ef5b7e9c3a4e8e17b2b214548fbf", size = 5385760, upload-time = "2024-11-19T10:21:36.005Z" }, +] + +[[package]] +name = "llvmlite" +version = "0.44.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/6a/95a3d3610d5c75293d5dbbb2a76480d5d4eeba641557b69fe90af6c5b84e/llvmlite-0.44.0.tar.gz", hash = "sha256:07667d66a5d150abed9157ab6c0b9393c9356f229784a4385c02f99e94fc94d4", size = 171880, upload-time = "2025-01-20T11:14:41.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/86/e3c3195b92e6e492458f16d233e58a1a812aa2bfbef9bdd0fbafcec85c60/llvmlite-0.44.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:1d671a56acf725bf1b531d5ef76b86660a5ab8ef19bb6a46064a705c6ca80aad", size = 28132297, upload-time = "2025-01-20T11:13:32.57Z" }, + { url = "https://files.pythonhosted.org/packages/d6/53/373b6b8be67b9221d12b24125fd0ec56b1078b660eeae266ec388a6ac9a0/llvmlite-0.44.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f79a728e0435493611c9f405168682bb75ffd1fbe6fc360733b850c80a026db", size = 26201105, upload-time = "2025-01-20T11:13:38.744Z" }, + { url = "https://files.pythonhosted.org/packages/cb/da/8341fd3056419441286c8e26bf436923021005ece0bff5f41906476ae514/llvmlite-0.44.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0143a5ef336da14deaa8ec26c5449ad5b6a2b564df82fcef4be040b9cacfea9", size = 42361901, upload-time = "2025-01-20T11:13:46.711Z" }, + { url = "https://files.pythonhosted.org/packages/53/ad/d79349dc07b8a395a99153d7ce8b01d6fcdc9f8231355a5df55ded649b61/llvmlite-0.44.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d752f89e31b66db6f8da06df8b39f9b91e78c5feea1bf9e8c1fba1d1c24c065d", size = 41184247, upload-time = "2025-01-20T11:13:56.159Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3b/a9a17366af80127bd09decbe2a54d8974b6d8b274b39bf47fbaedeec6307/llvmlite-0.44.0-cp312-cp312-win_amd64.whl", hash = "sha256:eae7e2d4ca8f88f89d315b48c6b741dcb925d6a1042da694aa16ab3dd4cbd3a1", size = 30332380, upload-time = "2025-01-20T11:14:02.442Z" }, + { url = "https://files.pythonhosted.org/packages/89/24/4c0ca705a717514c2092b18476e7a12c74d34d875e05e4d742618ebbf449/llvmlite-0.44.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:319bddd44e5f71ae2689859b7203080716448a3cd1128fb144fe5c055219d516", size = 28132306, upload-time = "2025-01-20T11:14:09.035Z" }, + { url = "https://files.pythonhosted.org/packages/01/cf/1dd5a60ba6aee7122ab9243fd614abcf22f36b0437cbbe1ccf1e3391461c/llvmlite-0.44.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c58867118bad04a0bb22a2e0068c693719658105e40009ffe95c7000fcde88e", size = 26201090, upload-time = "2025-01-20T11:14:15.401Z" }, + { url = "https://files.pythonhosted.org/packages/d2/1b/656f5a357de7135a3777bd735cc7c9b8f23b4d37465505bd0eaf4be9befe/llvmlite-0.44.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46224058b13c96af1365290bdfebe9a6264ae62fb79b2b55693deed11657a8bf", size = 42361904, upload-time = "2025-01-20T11:14:22.949Z" }, + { url = "https://files.pythonhosted.org/packages/d8/e1/12c5f20cb9168fb3464a34310411d5ad86e4163c8ff2d14a2b57e5cc6bac/llvmlite-0.44.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0097052c32bf721a4efc03bd109d335dfa57d9bffb3d4c24cc680711b8b4fc", size = 41184245, upload-time = "2025-01-20T11:14:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/d0/81/e66fc86539293282fd9cb7c9417438e897f369e79ffb62e1ae5e5154d4dd/llvmlite-0.44.0-cp313-cp313-win_amd64.whl", hash = "sha256:2fb7c4f2fb86cbae6dca3db9ab203eeea0e22d73b99bc2341cdf9de93612e930", size = 30331193, upload-time = "2025-01-20T11:14:38.578Z" }, +] + +[[package]] +name = "marisa-trie" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/15/9d9743897e4450b2de199ee673b50cb018980c4ced477d41cf91304a85e3/marisa_trie-1.2.1.tar.gz", hash = "sha256:3a27c408e2aefc03e0f1d25b2ff2afb85aac3568f6fa2ae2a53b57a2e87ce29d", size = 416124, upload-time = "2024-10-12T11:30:15.989Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/bf/8bd4ac8436b33fd46c9e1ffe3c2a131cd9744cc1649dbbe13308f744ef2b/marisa_trie-1.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:638506eacf20ca503fff72221a7e66a6eadbf28d6a4a6f949fcf5b1701bb05ec", size = 360041, upload-time = "2024-10-12T11:28:59.436Z" }, + { url = "https://files.pythonhosted.org/packages/ab/dd/4d3151e302e66ae387885f6ec265bd189e096b0c43c1379bfd9a3b9d2543/marisa_trie-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de1665eaafefa48a308e4753786519888021740501a15461c77bdfd57638e6b4", size = 190520, upload-time = "2024-10-12T11:29:01.07Z" }, + { url = "https://files.pythonhosted.org/packages/00/28/ae5991c74fb90b173167a366a634c83445f948ad044d37287b478d6b457e/marisa_trie-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f713af9b8aa66a34cd3a78c7d150a560a75734713abe818a69021fd269e927fa", size = 174175, upload-time = "2024-10-12T11:29:02.516Z" }, + { url = "https://files.pythonhosted.org/packages/5a/6a/fbfa89a8680eaabc6847a6c421e65427c43182db0c4bdb60e1516c81c822/marisa_trie-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2a7d00f53f4945320b551bccb826b3fb26948bde1a10d50bb9802fabb611b10", size = 1354995, upload-time = "2024-10-12T11:29:04.294Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4c/2ba0b385e5f64ca4ddb0c10ec52ddf881bc4521f135948786fc339d1d6c8/marisa_trie-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98042040d1d6085792e8d0f74004fc0f5f9ca6091c298f593dd81a22a4643854", size = 1390989, upload-time = "2024-10-12T11:29:05.576Z" }, + { url = "https://files.pythonhosted.org/packages/6b/22/0791ed3045c91d0938345a86be472fc7c188b894f16c5dfad2ef31e7f882/marisa_trie-1.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6532615111eec2c79e711965ece0bc95adac1ff547a7fff5ffca525463116deb", size = 1328810, upload-time = "2024-10-12T11:29:07.522Z" }, + { url = "https://files.pythonhosted.org/packages/9d/7d/3f566e563abae6efce7fc311c63282a447c611739b3cd66c0e36077c86f8/marisa_trie-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:20948e40ab2038e62b7000ca6b4a913bc16c91a2c2e6da501bd1f917eeb28d51", size = 2230222, upload-time = "2024-10-12T11:29:09.374Z" }, + { url = "https://files.pythonhosted.org/packages/a5/0b/38fbb4611b5d1030242ddc2aa62e524438c8076e26f87395dbbf222dc62d/marisa_trie-1.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66b23e5b35dd547f85bf98db7c749bc0ffc57916ade2534a6bbc32db9a4abc44", size = 2383620, upload-time = "2024-10-12T11:29:10.904Z" }, + { url = "https://files.pythonhosted.org/packages/ae/17/4553c63de29904d5d2521a24cad817bc7883cfa90506ab702ec4dae59a7b/marisa_trie-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6704adf0247d2dda42e876b793be40775dff46624309ad99bc7537098bee106d", size = 2329202, upload-time = "2024-10-12T11:29:12.266Z" }, + { url = "https://files.pythonhosted.org/packages/45/08/6307a630e63cd763fe77ac56516faa67fa9cd342060691e40fabc84be6b0/marisa_trie-1.2.1-cp312-cp312-win32.whl", hash = "sha256:3ad356442c2fea4c2a6f514738ddf213d23930f942299a2b2c05df464a00848a", size = 129652, upload-time = "2024-10-12T11:29:13.454Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fe/67c357bfd92710d95a16b86e1453c663d565415d7f7838781c79ff7e1a7e/marisa_trie-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:f2806f75817392cedcacb24ac5d80b0350dde8d3861d67d045c1d9b109764114", size = 150845, upload-time = "2024-10-12T11:29:15.092Z" }, + { url = "https://files.pythonhosted.org/packages/2a/a4/a110cd9952f0e72da7bafea1f0084b18b9e03952110d9083bfda52279f5c/marisa_trie-1.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b5ea16e69bfda0ac028c921b58de1a4aaf83d43934892977368579cd3c0a2554", size = 354439, upload-time = "2024-10-12T11:29:16.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a5/a6099eb1c3fd8d7e93408c45501e1d08536ac57dfef02ec331f78e1ace18/marisa_trie-1.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9f627f4e41be710b6cb6ed54b0128b229ac9d50e2054d9cde3af0fef277c23cf", size = 188187, upload-time = "2024-10-12T11:29:18.558Z" }, + { url = "https://files.pythonhosted.org/packages/7c/cc/f637127e2beffa920d21f7fc45b4029575bcd1b28a90c0d90cb2b08c2205/marisa_trie-1.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5e649f3dc8ab5476732094f2828cc90cac3be7c79bc0c8318b6fda0c1d248db4", size = 171484, upload-time = "2024-10-12T11:29:19.596Z" }, + { url = "https://files.pythonhosted.org/packages/6d/0f/29f2ad7260b956570f69f25a542efa51ba76eb76ecd53c63ee9d21987c3d/marisa_trie-1.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46e528ee71808c961baf8c3ce1c46a8337ec7a96cc55389d11baafe5b632f8e9", size = 1319770, upload-time = "2024-10-12T11:29:20.661Z" }, + { url = "https://files.pythonhosted.org/packages/f2/12/0b69ed61fba59551a5f3d569af367afae614db7214ce1da12946ba9a433a/marisa_trie-1.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36aa4401a1180615f74d575571a6550081d84fc6461e9aefc0bb7b2427af098e", size = 1356488, upload-time = "2024-10-12T11:29:21.95Z" }, + { url = "https://files.pythonhosted.org/packages/33/23/483b110db7ffe8729d6ebea2bf74258aef51f10fef5775f99e4bac7aef69/marisa_trie-1.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce59bcd2cda9bb52b0e90cc7f36413cd86c3d0ce7224143447424aafb9f4aa48", size = 1302334, upload-time = "2024-10-12T11:29:24.217Z" }, + { url = "https://files.pythonhosted.org/packages/1c/6f/46c2be99ce925985127fdf78900f1673bce8cb72debfebee6dccd11032c6/marisa_trie-1.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f4cd800704a5fc57e53c39c3a6b0c9b1519ebdbcb644ede3ee67a06eb542697d", size = 2202624, upload-time = "2024-10-12T11:29:25.499Z" }, + { url = "https://files.pythonhosted.org/packages/fd/b6/ef642327dbd4ec35be55d5682520b8f70fca98a54024f441ef2732f6b305/marisa_trie-1.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2428b495003c189695fb91ceeb499f9fcced3a2dce853e17fa475519433c67ff", size = 2364206, upload-time = "2024-10-12T11:29:26.771Z" }, + { url = "https://files.pythonhosted.org/packages/69/04/ef8197a79d0ab5043b781cc9b457bd11b81d4204fe78adf7625a67f48c21/marisa_trie-1.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:735c363d9aaac82eaf516a28f7c6b95084c2e176d8231c87328dc80e112a9afa", size = 2304801, upload-time = "2024-10-12T11:29:28.095Z" }, + { url = "https://files.pythonhosted.org/packages/03/72/f87564d653daf31d8f33d9bf0121e99ccc21f18f5c485fb404ba06abc10e/marisa_trie-1.2.1-cp313-cp313-win32.whl", hash = "sha256:eba6ca45500ca1a042466a0684aacc9838e7f20fe2605521ee19f2853062798f", size = 128799, upload-time = "2024-10-12T11:29:30.28Z" }, + { url = "https://files.pythonhosted.org/packages/27/40/5f9eb8b73030cc4b0d6817176e66079a62a2ddd9d5530da54f8011473428/marisa_trie-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:aa7cd17e1c690ce96c538b2f4aae003d9a498e65067dd433c52dd069009951d4", size = 149035, upload-time = "2024-10-12T11:29:31.332Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "mathics-django" +version = "8.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "mathics-scanner" }, + { name = "mathics3" }, + { name = "matplotlib" }, + { name = "networkx" }, + { name = "pygments" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/be/5674ea373ae53eda45505fb4a272c6b462a2a8a9e4f2bb06d1576f27fcb9/Mathics_Django-8.0.1.tar.gz", hash = "sha256:f896fef54e0aa19fe2eb13f650540c49481679843101f912f97b30c3c5a99bb3", size = 24237855, upload-time = "2025-02-08T15:02:08.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/c4/b4a9d20509d2a0c453386b915fb52cc2a5c413ed02635841c6bca11eeb6f/Mathics_Django-8.0.1-py3-none-any.whl", hash = "sha256:f92e439536e4d4bffc4182c1dec454ddabc5e94738edb527fbca303e401221d1", size = 25459733, upload-time = "2025-02-08T15:02:02.636Z" }, +] + +[[package]] +name = "mathics-omnibus" +version = "8.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mathics-django" }, + { name = "mathics3" }, + { name = "mathics3-trepan" }, + { name = "mathicsscript" }, + { name = "pymathics-graph" }, + { name = "pymathics-natlang" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/29/d5343adeb65461829d2d4aa0f29cccefb32d450dfde38653525da857e926/mathics_omnibus-8.0.0.tar.gz", hash = "sha256:f3dc17d483c1d31a4d2957accc5e696de5df23e3528fed05fdb5751983a442cd", size = 21374, upload-time = "2025-01-28T22:43:09.537Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/a8/e639113c20a87c173c902c939c7a09123196a08a0dcb4bcafecb306b983d/Mathics_omnibus-8.0.0-py2.py3-none-any.whl", hash = "sha256:1290edf153ee823b078517f9e4638b91d9f615ee13e26058bbb9c1fcf569f6e5", size = 25454, upload-time = "2025-01-28T22:42:31.295Z" }, +] + +[[package]] +name = "mathics-pygments" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mathics-scanner" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/11/d0c99863e949090a0f167213e3b0e9d8f487f09c215fb9b36a3b06507ebd/mathics_pygments-1.0.4.tar.gz", hash = "sha256:694a2fdaf61eb60068f3dc83385a5eedb2ce9c0444b73603e8d20387586c4fc5", size = 57747, upload-time = "2025-01-28T22:26:21.021Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/57/2423061094e1cffa72c36fb6de951f50a54f47f4023fc368b44897bd53e1/mathics_pygments-1.0.4-py2.py3-none-any.whl", hash = "sha256:bb6af332d387f1983092ebdb9f26d203f2ddc2944a5f6e8ab84ca3e5bfee3ce8", size = 46699, upload-time = "2025-01-28T22:26:19.144Z" }, +] + +[[package]] +name = "mathics-scanner" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "chardet" }, + { name = "click" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b4/a9/8410a1d37a360fcd27735b2bdc1ee20dd29744c21365ad71fe92cf6dddff/mathics_scanner-1.4.1.tar.gz", hash = "sha256:a98a5ee11815bf94edf8a6f665e788915c09b9cd4fd96ed4fc26583973dc6fb1", size = 182389, upload-time = "2025-01-26T17:39:37.681Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/f9/4e20ccd1a51d6078c640f9a420b5e42415f3c1f7f36c68941215a0066ef4/Mathics_Scanner-1.4.1-py3-none-any.whl", hash = "sha256:5955cf75e3e6b71e30107f5d45d046e9cc45926ac96f0a26049be590abac830a", size = 153640, upload-time = "2025-01-26T17:39:36.419Z" }, +] + +[[package]] +name = "mathics3" +version = "8.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mathics-scanner" }, + { name = "mpmath" }, + { name = "numpy" }, + { name = "palettable" }, + { name = "pillow" }, + { name = "pint" }, + { name = "pympler" }, + { name = "python-dateutil" }, + { name = "requests" }, + { name = "scipy" }, + { name = "setuptools" }, + { name = "stopit", marker = "sys_platform != 'emscripten'" }, + { name = "sympy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/a2/8a0e9e6868fd75c1e738e4eb96ed3934b55417a9d82eedc6813c6d06b72c/Mathics3-8.0.1.tar.gz", hash = "sha256:4ce42e4bbb0aec61ab03ccd537f478dc2eabb953ab69073c07515a6e610c22fb", size = 19546895, upload-time = "2025-02-08T14:23:20.995Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/4b/464aa013d4ea19c7cf69fa0d2a8db7c9a273ec2f469bd736bac8ae63f670/Mathics3-8.0.1-py3-none-any.whl", hash = "sha256:9fdb89215ecf149011118a02120de358f4aa90fa9708a95c14055bfebaf9022a", size = 18340878, upload-time = "2025-02-08T14:23:15.899Z" }, +] + +[[package]] +name = "mathics3-trepan" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mathics-pygments" }, + { name = "mathics3" }, + { name = "trepan3k" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/23/dd2e144583d1d71d15ba850acfd3ab4cfa41ffd9b7261116bd8e571b64b8/Mathics3_trepan-1.0.2.tar.gz", hash = "sha256:2c39d3df8347bf3c8a175e08dd8a744723b4986cb1d3fed2fa35436d72e394f6", size = 78013, upload-time = "2025-01-28T12:29:14.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/be/eb40a8ea016368e894937b02bf897e4fb0480ff726d4876353ec1bcc3448/Mathics3_trepan-1.0.2-py3-none-any.whl", hash = "sha256:024fb61c1607bb1b9125109c79fa06c16a9f286907dd768a32444f0e8d8d2c74", size = 118383, upload-time = "2025-01-28T12:29:11.563Z" }, +] + +[[package]] +name = "mathicsscript" +version = "8.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama" }, + { name = "columnize" }, + { name = "mathics-pygments" }, + { name = "mathics-scanner" }, + { name = "mathics3" }, + { name = "networkx" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "term-background" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/87/f6ab24f239821804b9135c4d0da33c7b23a5098bc65ecaa96c48903ca87b/mathicsscript-8.0.0.tar.gz", hash = "sha256:84a9dc55580d07a9616d7549745583086a5de75ee25cb5f68ae5aab44e1a518b", size = 66662, upload-time = "2025-01-26T21:34:13.315Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/dc/818f348aec295ac4cd2c7d3ab7c32b3b011eb84d4ccce60093971594d85f/mathicsscript-8.0.0-py3-none-any.whl", hash = "sha256:44d280d52edb50759de7d06f44eae7d3b5c0646c08e87b4aa505589d6cabd271", size = 68306, upload-time = "2025-01-26T21:34:12.051Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/91/d49359a21893183ed2a5b6c76bec40e0b1dcbf8ca148f864d134897cfc75/matplotlib-3.10.3.tar.gz", hash = "sha256:2f82d2c5bb7ae93aaaa4cd42aca65d76ce6376f83304fa3a630b569aca274df0", size = 34799811, upload-time = "2025-05-08T19:10:54.39Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/43/6b80eb47d1071f234ef0c96ca370c2ca621f91c12045f1401b5c9b28a639/matplotlib-3.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ab1affc11d1f495ab9e6362b8174a25afc19c081ba5b0775ef00533a4236eea", size = 8179689, upload-time = "2025-05-08T19:10:07.602Z" }, + { url = "https://files.pythonhosted.org/packages/0f/70/d61a591958325c357204870b5e7b164f93f2a8cca1dc6ce940f563909a13/matplotlib-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a818d8bdcafa7ed2eed74487fdb071c09c1ae24152d403952adad11fa3c65b4", size = 8050466, upload-time = "2025-05-08T19:10:09.383Z" }, + { url = "https://files.pythonhosted.org/packages/e7/75/70c9d2306203148cc7902a961240c5927dd8728afedf35e6a77e105a2985/matplotlib-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748ebc3470c253e770b17d8b0557f0aa85cf8c63fd52f1a61af5b27ec0b7ffee", size = 8456252, upload-time = "2025-05-08T19:10:11.958Z" }, + { url = "https://files.pythonhosted.org/packages/c4/91/ba0ae1ff4b3f30972ad01cd4a8029e70a0ec3b8ea5be04764b128b66f763/matplotlib-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed70453fd99733293ace1aec568255bc51c6361cb0da94fa5ebf0649fdb2150a", size = 8601321, upload-time = "2025-05-08T19:10:14.47Z" }, + { url = "https://files.pythonhosted.org/packages/d2/88/d636041eb54a84b889e11872d91f7cbf036b3b0e194a70fa064eb8b04f7a/matplotlib-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbed9917b44070e55640bd13419de83b4c918e52d97561544814ba463811cbc7", size = 9406972, upload-time = "2025-05-08T19:10:16.569Z" }, + { url = "https://files.pythonhosted.org/packages/b1/79/0d1c165eac44405a86478082e225fce87874f7198300bbebc55faaf6d28d/matplotlib-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:cf37d8c6ef1a48829443e8ba5227b44236d7fcaf7647caa3178a4ff9f7a5be05", size = 8067954, upload-time = "2025-05-08T19:10:18.663Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c1/23cfb566a74c696a3b338d8955c549900d18fe2b898b6e94d682ca21e7c2/matplotlib-3.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9f2efccc8dcf2b86fc4ee849eea5dcaecedd0773b30f47980dc0cbeabf26ec84", size = 8180318, upload-time = "2025-05-08T19:10:20.426Z" }, + { url = "https://files.pythonhosted.org/packages/6c/0c/02f1c3b66b30da9ee343c343acbb6251bef5b01d34fad732446eaadcd108/matplotlib-3.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3ddbba06a6c126e3301c3d272a99dcbe7f6c24c14024e80307ff03791a5f294e", size = 8051132, upload-time = "2025-05-08T19:10:22.569Z" }, + { url = "https://files.pythonhosted.org/packages/b4/ab/8db1a5ac9b3a7352fb914133001dae889f9fcecb3146541be46bed41339c/matplotlib-3.10.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748302b33ae9326995b238f606e9ed840bf5886ebafcb233775d946aa8107a15", size = 8457633, upload-time = "2025-05-08T19:10:24.749Z" }, + { url = "https://files.pythonhosted.org/packages/f5/64/41c4367bcaecbc03ef0d2a3ecee58a7065d0a36ae1aa817fe573a2da66d4/matplotlib-3.10.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a80fcccbef63302c0efd78042ea3c2436104c5b1a4d3ae20f864593696364ac7", size = 8601031, upload-time = "2025-05-08T19:10:27.03Z" }, + { url = "https://files.pythonhosted.org/packages/12/6f/6cc79e9e5ab89d13ed64da28898e40fe5b105a9ab9c98f83abd24e46d7d7/matplotlib-3.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55e46cbfe1f8586adb34f7587c3e4f7dedc59d5226719faf6cb54fc24f2fd52d", size = 9406988, upload-time = "2025-05-08T19:10:29.056Z" }, + { url = "https://files.pythonhosted.org/packages/b1/0f/eed564407bd4d935ffabf561ed31099ed609e19287409a27b6d336848653/matplotlib-3.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:151d89cb8d33cb23345cd12490c76fd5d18a56581a16d950b48c6ff19bb2ab93", size = 8068034, upload-time = "2025-05-08T19:10:31.221Z" }, + { url = "https://files.pythonhosted.org/packages/3e/e5/2f14791ff69b12b09e9975e1d116d9578ac684460860ce542c2588cb7a1c/matplotlib-3.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c26dd9834e74d164d06433dc7be5d75a1e9890b926b3e57e74fa446e1a62c3e2", size = 8218223, upload-time = "2025-05-08T19:10:33.114Z" }, + { url = "https://files.pythonhosted.org/packages/5c/08/30a94afd828b6e02d0a52cae4a29d6e9ccfcf4c8b56cc28b021d3588873e/matplotlib-3.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:24853dad5b8c84c8c2390fc31ce4858b6df504156893292ce8092d190ef8151d", size = 8094985, upload-time = "2025-05-08T19:10:35.337Z" }, + { url = "https://files.pythonhosted.org/packages/89/44/f3bc6b53066c889d7a1a3ea8094c13af6a667c5ca6220ec60ecceec2dabe/matplotlib-3.10.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f7878214d369d7d4215e2a9075fef743be38fa401d32e6020bab2dfabaa566", size = 8483109, upload-time = "2025-05-08T19:10:37.611Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c7/473bc559beec08ebee9f86ca77a844b65747e1a6c2691e8c92e40b9f42a8/matplotlib-3.10.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6929fc618cb6db9cb75086f73b3219bbb25920cb24cee2ea7a12b04971a4158", size = 8618082, upload-time = "2025-05-08T19:10:39.892Z" }, + { url = "https://files.pythonhosted.org/packages/d8/e9/6ce8edd264c8819e37bbed8172e0ccdc7107fe86999b76ab5752276357a4/matplotlib-3.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c7818292a5cc372a2dc4c795e5c356942eb8350b98ef913f7fda51fe175ac5d", size = 9413699, upload-time = "2025-05-08T19:10:42.376Z" }, + { url = "https://files.pythonhosted.org/packages/1b/92/9a45c91089c3cf690b5badd4be81e392ff086ccca8a1d4e3a08463d8a966/matplotlib-3.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4f23ffe95c5667ef8a2b56eea9b53db7f43910fa4a2d5472ae0f72b64deab4d5", size = 8139044, upload-time = "2025-05-08T19:10:44.551Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "murmurhash" +version = "1.0.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/e9/02efbc6dfc2dd2085da3daacf9a8c17e8356019eceaedbfa21555e32d2af/murmurhash-1.0.13.tar.gz", hash = "sha256:737246d41ee00ff74b07b0bd1f0888be304d203ce668e642c86aa64ede30f8b7", size = 13258, upload-time = "2025-05-22T12:35:57.019Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/53/56ce2d8d4b9ab89557cb1d00ffce346b80a2eb2d8c7944015e5c83eacdec/murmurhash-1.0.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbe882e46cb3f86e092d8a1dd7a5a1c992da1ae3b39f7dd4507b6ce33dae7f92", size = 26859, upload-time = "2025-05-22T12:35:31.815Z" }, + { url = "https://files.pythonhosted.org/packages/f8/85/3a0ad54a61257c31496545ae6861515d640316f93681d1dd917e7be06634/murmurhash-1.0.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:52a33a12ecedc432493692c207c784b06b6427ffaa897fc90b7a76e65846478d", size = 26900, upload-time = "2025-05-22T12:35:34.267Z" }, + { url = "https://files.pythonhosted.org/packages/d0/cd/6651de26744b50ff11c79f0c0d41244db039625de53c0467a7a52876b2d8/murmurhash-1.0.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:950403a7f0dc2d9c8d0710f07c296f2daab66299d9677d6c65d6b6fa2cb30aaa", size = 131367, upload-time = "2025-05-22T12:35:35.258Z" }, + { url = "https://files.pythonhosted.org/packages/50/6c/01ded95ddce33811c9766cae4ce32e0a54288da1d909ee2bcaa6ed13b9f1/murmurhash-1.0.13-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fde9fb5d2c106d86ff3ef2e4a9a69c2a8d23ba46e28c6b30034dc58421bc107b", size = 128943, upload-time = "2025-05-22T12:35:36.358Z" }, + { url = "https://files.pythonhosted.org/packages/ab/27/e539a9622d7bea3ae22706c1eb80d4af80f9dddd93b54d151955c2ae4011/murmurhash-1.0.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3aa55d62773745616e1ab19345dece122f6e6d09224f7be939cc5b4c513c8473", size = 129108, upload-time = "2025-05-22T12:35:37.864Z" }, + { url = "https://files.pythonhosted.org/packages/7a/84/18af5662e07d06839ad4db18ce026e6f8ef850d7b0ba92817b28dad28ba6/murmurhash-1.0.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:060dfef1b405cf02c450f182fb629f76ebe7f79657cced2db5054bc29b34938b", size = 129175, upload-time = "2025-05-22T12:35:38.928Z" }, + { url = "https://files.pythonhosted.org/packages/fe/8d/b01d3ee1f1cf3957250223b7c6ce35454f38fbf4abe236bf04a3f769341d/murmurhash-1.0.13-cp312-cp312-win_amd64.whl", hash = "sha256:a8e79627d44a6e20a6487effc30bfe1c74754c13d179106e68cc6d07941b022c", size = 24869, upload-time = "2025-05-22T12:35:40.035Z" }, + { url = "https://files.pythonhosted.org/packages/00/b4/8919dfdc4a131ad38a57b2c5de69f4bd74538bf546637ee59ebaebe6e5a4/murmurhash-1.0.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8a7f8befd901379b6dc57a9e49c5188454113747ad6aa8cdd951a6048e10790", size = 26852, upload-time = "2025-05-22T12:35:41.061Z" }, + { url = "https://files.pythonhosted.org/packages/b4/32/ce78bef5d6101568bcb12f5bb5103fabcbe23723ec52e76ff66132d5dbb7/murmurhash-1.0.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f741aab86007510199193eee4f87c5ece92bc5a6ca7d0fe0d27335c1203dface", size = 26900, upload-time = "2025-05-22T12:35:42.097Z" }, + { url = "https://files.pythonhosted.org/packages/0c/4c/0f47c0b4f6b31a1de84d65f9573832c78cd47b4b8ce25ab5596a8238d150/murmurhash-1.0.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82614f18fa6d9d83da6bb0918f3789a3e1555d0ce12c2548153e97f79b29cfc9", size = 130033, upload-time = "2025-05-22T12:35:43.113Z" }, + { url = "https://files.pythonhosted.org/packages/e0/cb/e47233e32fb792dcc9fb18a2cf65f795d47179b29c2b4a2034689f14c707/murmurhash-1.0.13-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91f22a48b9454712e0690aa0b76cf0156a5d5a083d23ec7e209cfaeef28f56ff", size = 130619, upload-time = "2025-05-22T12:35:44.229Z" }, + { url = "https://files.pythonhosted.org/packages/8f/f1/f89911bf304ba5d385ccd346cc7fbb1c1450a24f093b592c3bfe87768467/murmurhash-1.0.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c4bc7938627b8fcb3d598fe6657cc96d1e31f4eba6a871b523c1512ab6dacb3e", size = 127643, upload-time = "2025-05-22T12:35:45.369Z" }, + { url = "https://files.pythonhosted.org/packages/a4/24/262229221f6840c1a04a46051075e99675e591571abcca6b9a8b6aa1602b/murmurhash-1.0.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:58a61f1fc840f9ef704e638c39b8517bab1d21f1a9dbb6ba3ec53e41360e44ec", size = 127981, upload-time = "2025-05-22T12:35:46.503Z" }, + { url = "https://files.pythonhosted.org/packages/18/25/addbc1d28f83252732ac3e57334d42f093890b4c2cce483ba01a42bc607c/murmurhash-1.0.13-cp313-cp313-win_amd64.whl", hash = "sha256:c451a22f14c2f40e7abaea521ee24fa0e46fbec480c4304c25c946cdb6e81883", size = 24880, upload-time = "2025-05-22T12:35:47.625Z" }, +] + +[[package]] +name = "networkx" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, +] + +[[package]] +name = "nltk" +version = "3.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "joblib" }, + { name = "regex" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/87/db8be88ad32c2d042420b6fd9ffd4a149f9a0d7f0e86b3f543be2eeeedd2/nltk-3.9.1.tar.gz", hash = "sha256:87d127bd3de4bd89a4f81265e5fa59cb1b199b27440175370f7417d2bc7ae868", size = 2904691, upload-time = "2024-08-18T19:48:37.769Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/66/7d9e26593edda06e8cb531874633f7c2372279c3b0f46235539fe546df8b/nltk-3.9.1-py3-none-any.whl", hash = "sha256:4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1", size = 1505442, upload-time = "2024-08-18T19:48:21.909Z" }, +] + +[[package]] +name = "numpy" +version = "2.2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, + { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, + { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, + { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, + { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, + { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, + { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, + { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, + { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "palettable" +version = "3.3.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/3d/a5854d60850485bff12f28abfe0e17f503e866763bed61aed4990b604530/palettable-3.3.3.tar.gz", hash = "sha256:094dd7d9a5fc1cca4854773e5c1fc6a315b33bd5b3a8f47064928facaf0490a8", size = 106639, upload-time = "2023-04-19T23:13:35.864Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/f7/3367feadd4ab56783b0971c9b7edfbdd68e0c70ce877949a5dd2117ed4a0/palettable-3.3.3-py2.py3-none-any.whl", hash = "sha256:74e9e7d7fe5a9be065e02397558ed1777b2df0b793a6f4ce1a5ee74f74fb0caa", size = 332251, upload-time = "2023-04-19T23:13:33.996Z" }, +] + +[[package]] +name = "parse-literature" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "ipython" }, + { name = "mathics-omnibus" }, +] + +[package.metadata] +requires-dist = [ + { name = "ipython", specifier = ">=9.3.0" }, + { name = "mathics-omnibus", specifier = ">=8.0.0" }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609, upload-time = "2024-04-05T09:43:55.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" }, +] + +[[package]] +name = "patternlite" +version = "3.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nltk" }, + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/65/d872a6269072568f4e812fc071705b5134c6153e05b121ed3234a16eb1ca/PatternLite-3.6.tar.gz", hash = "sha256:bfc890760dd2dfec89f0b01167ef9a460b31ecb9ad8cebcd4b3798a96a62e260", size = 21968361, upload-time = "2019-12-06T12:46:24.911Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/f5/1894eb24102cae0e433c18366ec2a8d945b42cbf128303b67454db8587d8/PatternLite-3.6-py3-none-any.whl", hash = "sha256:c54cd29314635b0e6361861c33f036705c5449f08741c47d834317ba83bd98e0", size = 22072758, upload-time = "2019-12-06T12:46:18.742Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "11.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707, upload-time = "2025-04-12T17:50:03.289Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/40/052610b15a1b8961f52537cc8326ca6a881408bc2bdad0d852edeb6ed33b/pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f", size = 3190185, upload-time = "2025-04-12T17:48:00.417Z" }, + { url = "https://files.pythonhosted.org/packages/e5/7e/b86dbd35a5f938632093dc40d1682874c33dcfe832558fc80ca56bfcb774/pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b", size = 3030306, upload-time = "2025-04-12T17:48:02.391Z" }, + { url = "https://files.pythonhosted.org/packages/a4/5c/467a161f9ed53e5eab51a42923c33051bf8d1a2af4626ac04f5166e58e0c/pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d", size = 4416121, upload-time = "2025-04-12T17:48:04.554Z" }, + { url = "https://files.pythonhosted.org/packages/62/73/972b7742e38ae0e2ac76ab137ca6005dcf877480da0d9d61d93b613065b4/pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4", size = 4501707, upload-time = "2025-04-12T17:48:06.831Z" }, + { url = "https://files.pythonhosted.org/packages/e4/3a/427e4cb0b9e177efbc1a84798ed20498c4f233abde003c06d2650a6d60cb/pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d", size = 4522921, upload-time = "2025-04-12T17:48:09.229Z" }, + { url = "https://files.pythonhosted.org/packages/fe/7c/d8b1330458e4d2f3f45d9508796d7caf0c0d3764c00c823d10f6f1a3b76d/pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4", size = 4612523, upload-time = "2025-04-12T17:48:11.631Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2f/65738384e0b1acf451de5a573d8153fe84103772d139e1e0bdf1596be2ea/pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443", size = 4587836, upload-time = "2025-04-12T17:48:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c5/e795c9f2ddf3debb2dedd0df889f2fe4b053308bb59a3cc02a0cd144d641/pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c", size = 4669390, upload-time = "2025-04-12T17:48:15.938Z" }, + { url = "https://files.pythonhosted.org/packages/96/ae/ca0099a3995976a9fce2f423166f7bff9b12244afdc7520f6ed38911539a/pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3", size = 2332309, upload-time = "2025-04-12T17:48:17.885Z" }, + { url = "https://files.pythonhosted.org/packages/7c/18/24bff2ad716257fc03da964c5e8f05d9790a779a8895d6566e493ccf0189/pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941", size = 2676768, upload-time = "2025-04-12T17:48:19.655Z" }, + { url = "https://files.pythonhosted.org/packages/da/bb/e8d656c9543276517ee40184aaa39dcb41e683bca121022f9323ae11b39d/pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb", size = 2415087, upload-time = "2025-04-12T17:48:21.991Z" }, + { url = "https://files.pythonhosted.org/packages/36/9c/447528ee3776e7ab8897fe33697a7ff3f0475bb490c5ac1456a03dc57956/pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28", size = 3190098, upload-time = "2025-04-12T17:48:23.915Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/29d5cd052f7566a63e5b506fac9c60526e9ecc553825551333e1e18a4858/pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830", size = 3030166, upload-time = "2025-04-12T17:48:25.738Z" }, + { url = "https://files.pythonhosted.org/packages/71/5d/446ee132ad35e7600652133f9c2840b4799bbd8e4adba881284860da0a36/pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0", size = 4408674, upload-time = "2025-04-12T17:48:27.908Z" }, + { url = "https://files.pythonhosted.org/packages/69/5f/cbe509c0ddf91cc3a03bbacf40e5c2339c4912d16458fcb797bb47bcb269/pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1", size = 4496005, upload-time = "2025-04-12T17:48:29.888Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b3/dd4338d8fb8a5f312021f2977fb8198a1184893f9b00b02b75d565c33b51/pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f", size = 4518707, upload-time = "2025-04-12T17:48:31.874Z" }, + { url = "https://files.pythonhosted.org/packages/13/eb/2552ecebc0b887f539111c2cd241f538b8ff5891b8903dfe672e997529be/pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155", size = 4610008, upload-time = "2025-04-12T17:48:34.422Z" }, + { url = "https://files.pythonhosted.org/packages/72/d1/924ce51bea494cb6e7959522d69d7b1c7e74f6821d84c63c3dc430cbbf3b/pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14", size = 4585420, upload-time = "2025-04-12T17:48:37.641Z" }, + { url = "https://files.pythonhosted.org/packages/43/ab/8f81312d255d713b99ca37479a4cb4b0f48195e530cdc1611990eb8fd04b/pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b", size = 4667655, upload-time = "2025-04-12T17:48:39.652Z" }, + { url = "https://files.pythonhosted.org/packages/94/86/8f2e9d2dc3d308dfd137a07fe1cc478df0a23d42a6c4093b087e738e4827/pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2", size = 2332329, upload-time = "2025-04-12T17:48:41.765Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ec/1179083b8d6067a613e4d595359b5fdea65d0a3b7ad623fee906e1b3c4d2/pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691", size = 2676388, upload-time = "2025-04-12T17:48:43.625Z" }, + { url = "https://files.pythonhosted.org/packages/23/f1/2fc1e1e294de897df39fa8622d829b8828ddad938b0eaea256d65b84dd72/pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c", size = 2414950, upload-time = "2025-04-12T17:48:45.475Z" }, + { url = "https://files.pythonhosted.org/packages/c4/3e/c328c48b3f0ead7bab765a84b4977acb29f101d10e4ef57a5e3400447c03/pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22", size = 3192759, upload-time = "2025-04-12T17:48:47.866Z" }, + { url = "https://files.pythonhosted.org/packages/18/0e/1c68532d833fc8b9f404d3a642991441d9058eccd5606eab31617f29b6d4/pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7", size = 3033284, upload-time = "2025-04-12T17:48:50.189Z" }, + { url = "https://files.pythonhosted.org/packages/b7/cb/6faf3fb1e7705fd2db74e070f3bf6f88693601b0ed8e81049a8266de4754/pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16", size = 4445826, upload-time = "2025-04-12T17:48:52.346Z" }, + { url = "https://files.pythonhosted.org/packages/07/94/8be03d50b70ca47fb434a358919d6a8d6580f282bbb7af7e4aa40103461d/pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b", size = 4527329, upload-time = "2025-04-12T17:48:54.403Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a4/bfe78777076dc405e3bd2080bc32da5ab3945b5a25dc5d8acaa9de64a162/pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406", size = 4549049, upload-time = "2025-04-12T17:48:56.383Z" }, + { url = "https://files.pythonhosted.org/packages/65/4d/eaf9068dc687c24979e977ce5677e253624bd8b616b286f543f0c1b91662/pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91", size = 4635408, upload-time = "2025-04-12T17:48:58.782Z" }, + { url = "https://files.pythonhosted.org/packages/1d/26/0fd443365d9c63bc79feb219f97d935cd4b93af28353cba78d8e77b61719/pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751", size = 4614863, upload-time = "2025-04-12T17:49:00.709Z" }, + { url = "https://files.pythonhosted.org/packages/49/65/dca4d2506be482c2c6641cacdba5c602bc76d8ceb618fd37de855653a419/pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9", size = 4692938, upload-time = "2025-04-12T17:49:02.946Z" }, + { url = "https://files.pythonhosted.org/packages/b3/92/1ca0c3f09233bd7decf8f7105a1c4e3162fb9142128c74adad0fb361b7eb/pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd", size = 2335774, upload-time = "2025-04-12T17:49:04.889Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ac/77525347cb43b83ae905ffe257bbe2cc6fd23acb9796639a1f56aa59d191/pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e", size = 2681895, upload-time = "2025-04-12T17:49:06.635Z" }, + { url = "https://files.pythonhosted.org/packages/67/32/32dc030cfa91ca0fc52baebbba2e009bb001122a1daa8b6a79ad830b38d3/pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681", size = 2417234, upload-time = "2025-04-12T17:49:08.399Z" }, +] + +[[package]] +name = "pint" +version = "0.24.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flexcache" }, + { name = "flexparser" }, + { name = "platformdirs" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/bb/52b15ddf7b7706ed591134a895dbf6e41c8348171fb635e655e0a4bbb0ea/pint-0.24.4.tar.gz", hash = "sha256:35275439b574837a6cd3020a5a4a73645eb125ce4152a73a2f126bf164b91b80", size = 342225, upload-time = "2024-11-07T16:29:46.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/16/bd2f5904557265882108dc2e04f18abc05ab0c2b7082ae9430091daf1d5c/Pint-0.24.4-py3-none-any.whl", hash = "sha256:aa54926c8772159fcf65f82cc0d34de6768c151b32ad1deb0331291c38fe7659", size = 302029, upload-time = "2024-11-07T16:29:43.976Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, +] + +[[package]] +name = "preshed" +version = "3.0.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cymem" }, + { name = "murmurhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/3a/db814f67a05b6d7f9c15d38edef5ec9b21415710705b393883de92aee5ef/preshed-3.0.10.tar.gz", hash = "sha256:5a5c8e685e941f4ffec97f1fbf32694b8107858891a4bc34107fac981d8296ff", size = 15039, upload-time = "2025-05-26T15:18:33.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/14/322a4f58bc25991a87f216acb1351800739b0794185d27508ee86c35f382/preshed-3.0.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6e9c46933d55c8898c8f7a6019a8062cd87ef257b075ada2dd5d1e57810189ea", size = 131367, upload-time = "2025-05-26T15:18:02.408Z" }, + { url = "https://files.pythonhosted.org/packages/38/80/67507653c35620cace913f617df6d6f658b87e8da83087b851557d65dd86/preshed-3.0.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c4ebc4f8ef0114d55f2ffdce4965378129c7453d0203664aeeb03055572d9e4", size = 126535, upload-time = "2025-05-26T15:18:03.589Z" }, + { url = "https://files.pythonhosted.org/packages/db/b1/ab4f811aeaf20af0fa47148c1c54b62d7e8120d59025bd0a3f773bb67725/preshed-3.0.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ab5ab4c6dfd3746fb4328e7fbeb2a0544416b872db02903bfac18e6f5cd412f", size = 864907, upload-time = "2025-05-26T15:18:04.794Z" }, + { url = "https://files.pythonhosted.org/packages/fb/db/fe37c1f99cfb26805dd89381ddd54901307feceb267332eaaca228e9f9c1/preshed-3.0.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40586fd96ae3974c552a7cd78781b6844ecb1559ee7556586f487058cf13dd96", size = 869329, upload-time = "2025-05-26T15:18:06.353Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fd/efb6a6233d1cd969966f3f65bdd8e662579c3d83114e5c356cec1927b1f7/preshed-3.0.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a606c24cda931306b98e0edfafed3309bffcf8d6ecfe07804db26024c4f03cd6", size = 846829, upload-time = "2025-05-26T15:18:07.716Z" }, + { url = "https://files.pythonhosted.org/packages/14/49/0e4ce5db3bf86b081abb08a404fb37b7c2dbfd7a73ec6c0bc71b650307eb/preshed-3.0.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:394015566f9354738be903447039e8dbc6d93ba5adf091af694eb03c4e726b1e", size = 874008, upload-time = "2025-05-26T15:18:09.364Z" }, + { url = "https://files.pythonhosted.org/packages/6f/17/76d6593fc2d055d4e413b68a8c87b70aa9b7697d4972cb8062559edcf6e9/preshed-3.0.10-cp312-cp312-win_amd64.whl", hash = "sha256:fd7e38225937e580420c84d1996dde9b4f726aacd9405093455c3a2fa60fede5", size = 116701, upload-time = "2025-05-26T15:18:11.905Z" }, + { url = "https://files.pythonhosted.org/packages/bf/5e/87671bc58c4f6c8cf0a5601ccd74b8bb50281ff28aa4ab3e3cad5cd9d06a/preshed-3.0.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:23e6e0581a517597f3f76bc24a4cdb0ba5509933d4f61c34fca49649dd71edf9", size = 129184, upload-time = "2025-05-26T15:18:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/92/69/b3969a3c95778def5bf5126484a1f7d2ad324d1040077f55f56e027d8ea4/preshed-3.0.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:574e6d6056981540310ff181b47a2912f4bddc91bcace3c7a9c6726eafda24ca", size = 124258, upload-time = "2025-05-26T15:18:14.497Z" }, + { url = "https://files.pythonhosted.org/packages/32/df/6e828ec4565bf33bd4803a3eb3b1102830b739143e5d6c132bf7181a58ec/preshed-3.0.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd658dd73e853d1bb5597976a407feafa681b9d6155bc9bc7b4c2acc2a6ee96", size = 825445, upload-time = "2025-05-26T15:18:15.71Z" }, + { url = "https://files.pythonhosted.org/packages/05/3d/478b585f304920e51f328c9231e22f30dc64baa68e079e08a46ab72be738/preshed-3.0.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b95396046328ffb461a68859ce2141aca4815b8624167832d28ced70d541626", size = 831690, upload-time = "2025-05-26T15:18:17.08Z" }, + { url = "https://files.pythonhosted.org/packages/c3/65/938f21f77227e8d398d46fb10b9d1b3467be859468ce8db138fc3d50589c/preshed-3.0.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3e6728b2028bbe79565eb6cf676b5bae5ce1f9cc56e4bf99bb28ce576f88054d", size = 808593, upload-time = "2025-05-26T15:18:18.535Z" }, + { url = "https://files.pythonhosted.org/packages/6c/1c/2a3961fc88bc72300ff7e4ca54689bda90d2d77cc994167cc09a310480b6/preshed-3.0.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c4ef96cb28bf5f08de9c070143113e168efccbb68fd4961e7d445f734c051a97", size = 837333, upload-time = "2025-05-26T15:18:19.937Z" }, + { url = "https://files.pythonhosted.org/packages/fa/8c/d3e30f80b2ef21f267f09f0b7d18995adccc928ede5b73ea3fe54e1303f4/preshed-3.0.10-cp313-cp313-win_amd64.whl", hash = "sha256:97e0e2edfd25a7dfba799b49b3c5cc248ad0318a76edd9d5fd2c82aa3d5c64ed", size = 115769, upload-time = "2025-05-26T15:18:21.842Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.51" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pycountry" +version = "24.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/57/c389fa68c50590881a75b7883eeb3dc15e9e73a0fdc001cdd45c13290c92/pycountry-24.6.1.tar.gz", hash = "sha256:b61b3faccea67f87d10c1f2b0fc0be714409e8fcdcc1315613174f6466c10221", size = 6043910, upload-time = "2024-06-01T04:12:15.05Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/ec/1fb891d8a2660716aadb2143235481d15ed1cbfe3ad669194690b0604492/pycountry-24.6.1-py3-none-any.whl", hash = "sha256:f1a4fb391cd7214f8eefd39556d740adcc233c778a27f8942c8dca351d6ce06f", size = 6335189, upload-time = "2024-06-01T04:11:49.711Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, +] + +[[package]] +name = "pydot" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyparsing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/c3/6034ed1ebf2e3ba95a0e35fa7c43104e40444c0ed2b5325702c63e824dbf/pydot-4.0.0.tar.gz", hash = "sha256:12f16493337cade2f7631b87c8ccd299ba2e251f3ee5d0732a058df2887afe97", size = 161793, upload-time = "2025-05-04T11:13:03.214Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/16/984c0cf5073a23154b1f95c9d131b14c9fea83bfadae4ba8fc169daded11/pydot-4.0.0-py3-none-any.whl", hash = "sha256:cf86e13a6cfe2a96758a9702537f77e0ac1368db8ef277b4d3b34473ea425c97", size = 37535, upload-time = "2025-05-04T11:13:01.458Z" }, +] + +[[package]] +name = "pyenchant" +version = "3.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/a3/86763b6350727ca81c8fcc5bb5bccee416e902e0085dc7a902c81233717e/pyenchant-3.2.2.tar.gz", hash = "sha256:1cf830c6614362a78aab78d50eaf7c6c93831369c52e1bb64ffae1df0341e637", size = 49580, upload-time = "2021-10-05T17:25:25.553Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/4c/a741dddab6ad96f257d90cb4d23067ffadac526c9cab3a99ca6ce3c05477/pyenchant-3.2.2-py3-none-any.whl", hash = "sha256:5facc821ece957208a81423af7d6ec7810dad29697cb0d77aae81e4e11c8e5a6", size = 55660, upload-time = "2021-10-05T17:25:19.548Z" }, + { url = "https://files.pythonhosted.org/packages/01/44/1e9a273d230abf5c961750a75e42b449adfb61eb446f80b6523955d2a4a2/pyenchant-3.2.2-py3-none-win32.whl", hash = "sha256:5a636832987eaf26efe971968f4d1b78e81f62bca2bde0a9da210c7de43c3bce", size = 11884084, upload-time = "2021-10-05T17:25:23.844Z" }, + { url = "https://files.pythonhosted.org/packages/49/96/2087455de16b08e86fa7ce70b53ddac5fcc040c899d9ebad507a0efec52d/pyenchant-3.2.2-py3-none-win_amd64.whl", hash = "sha256:6153f521852e23a5add923dbacfbf4bebbb8d70c4e4bad609a8e0f9faeb915d1", size = 11890882, upload-time = "2021-10-05T17:25:17.013Z" }, +] + +[[package]] +name = "pyficache" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, + { name = "term-background" }, + { name = "xdis" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/97/72159ece19a5feec21a2629ad7e02bace110113d832fcd1c754cf24e72f8/pyficache-2.4.0.tar.gz", hash = "sha256:c3ce7b49b9d26a34c255a8b6a361e234f1ebb20d37eecc41de1e9ba58ba553d8", size = 33583, upload-time = "2025-01-16T00:31:02.225Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/b6/acdbc40cdfc6f60e4ddabc6f78ee0d2077b5f7534fbbd00816fa854e3b33/pyficache-2.4.0-py3-none-any.whl", hash = "sha256:6074ef4b004cd0474b3bed34480b3632d4415b5ed6ba2e3e400792858a87b55d", size = 27325, upload-time = "2025-01-16T00:30:32.605Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, +] + +[[package]] +name = "pymathics-graph" +version = "8.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mathics3" }, + { name = "matplotlib" }, + { name = "networkx" }, + { name = "pydot" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/f6/35dd01c1ce39d228ec579c093b6dcea98cf835145ac7f944b3be7e9a3ab4/pymathics_graph-8.0.1.tar.gz", hash = "sha256:9b773cbe27dfb97c9767f8d182b573f65011002d40a98726cc8e5632d63f6413", size = 59844, upload-time = "2025-02-08T15:40:55.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/4d/9873c74d4b5c8448b1eac3e6639bb084fb66c48cef97f561da4fdad4c86d/pymathics_graph-8.0.1-py3-none-any.whl", hash = "sha256:6c1c97a2df827eb6afa5550fba4fff2b806c0bce98ba6bb91097433d8a60ccb7", size = 53730, upload-time = "2025-02-08T15:40:53.737Z" }, +] + +[[package]] +name = "pymathics-natlang" +version = "8.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "joblib" }, + { name = "langid" }, + { name = "llvmlite" }, + { name = "mathics3" }, + { name = "nltk" }, + { name = "patternlite" }, + { name = "pycountry" }, + { name = "pyenchant" }, + { name = "spacy" }, + { name = "wasabi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/a3/d60ef3d51218eb77ab4696392b1c765ebd6e147851aeea39055bb64a65df/pymathics_natlang-8.0.1.tar.gz", hash = "sha256:d31da297592a10dae07529b891cad01e32ccd11d0c144c6e9f8675e61d082a23", size = 41528, upload-time = "2025-02-08T18:01:21.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/14/758adfa8520cef6d1bb7d315780e829468266eac8289bbcad13f29fe9087/pymathics_natlang-8.0.1-py3-none-any.whl", hash = "sha256:2ae2a2781c234eea9fb89270ca7e968094b6559ddecbfc86359bcc965d486441", size = 33636, upload-time = "2025-02-08T18:01:19.426Z" }, +] + +[[package]] +name = "pympler" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/37/c384631908029676d8e7213dd956bb686af303a80db7afbc9be36bc49495/pympler-1.1.tar.gz", hash = "sha256:1eaa867cb8992c218430f1708fdaccda53df064144d1c5656b1e6f1ee6000424", size = 179954, upload-time = "2024-06-28T19:56:06.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/4f/a6a2e2b202d7fd97eadfe90979845b8706676b41cbd3b42ba75adf329d1f/Pympler-1.1-py3-none-any.whl", hash = "sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506", size = 165766, upload-time = "2024-06-28T19:56:05.087Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload-time = "2025-03-25T05:01:28.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload-time = "2025-03-25T05:01:24.908Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pywin32" +version = "310" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, + { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, + { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, + { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, + { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "regex" +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, + { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, + { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, + { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, + { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, + { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, + { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, + { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, + { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, + { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, + { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, + { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, + { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, + { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, + { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, +] + +[[package]] +name = "requests" +version = "2.32.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, +] + +[[package]] +name = "rich" +version = "14.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, +] + +[[package]] +name = "scipy" +version = "1.15.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, + { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, + { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, + { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, + { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, + { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, + { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, + { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, + { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, + { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, + { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, + { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, + { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, + { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, + { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, + { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, + { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, + { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, + { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, + { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, +] + +[[package]] +name = "setuptools" +version = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "smart-open" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/30/1f41c3d3b8cec82024b4b277bfd4e5b18b765ae7279eb9871fa25c503778/smart_open-7.1.0.tar.gz", hash = "sha256:a4f09f84f0f6d3637c6543aca7b5487438877a21360e7368ccf1f704789752ba", size = 72044, upload-time = "2024-12-17T13:19:17.71Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/18/9a8d9f01957aa1f8bbc5676d54c2e33102d247e146c1a3679d3bd5cc2e3a/smart_open-7.1.0-py3-none-any.whl", hash = "sha256:4b8489bb6058196258bafe901730c7db0dcf4f083f316e97269c66f45502055b", size = 61746, upload-time = "2024-12-17T13:19:21.076Z" }, +] + +[[package]] +name = "spacy" +version = "3.8.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "catalogue" }, + { name = "cymem" }, + { name = "jinja2" }, + { name = "langcodes" }, + { name = "murmurhash" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "preshed" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "spacy-legacy" }, + { name = "spacy-loggers" }, + { name = "srsly" }, + { name = "thinc" }, + { name = "tqdm" }, + { name = "typer" }, + { name = "wasabi" }, + { name = "weasel" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1e/9e/fb4e1cefe3fbd51ea6a243e5a3d2bc629baa9a28930bf4be6fe5672fa1ca/spacy-3.8.7.tar.gz", hash = "sha256:700fd174c6c552276be142c48e70bb53cae24c4dd86003c4432af9cb93e4c908", size = 1316143, upload-time = "2025-05-23T08:55:39.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/10/89852f40f926e0902c11c34454493ba0d15530b322711e754b89a6d7dfe6/spacy-3.8.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:88b397e37793cea51df298e6c651a763e49877a25bead5ba349761531a456687", size = 6265335, upload-time = "2025-05-23T08:54:42.876Z" }, + { url = "https://files.pythonhosted.org/packages/16/fb/b5d54522969a632c06f4af354763467553b66d5bf0671ac39f3cceb3fd54/spacy-3.8.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f70b676955fa6959347ca86ed6edd8ff0d6eb2ba20561fdfec76924bd3e540f9", size = 5906035, upload-time = "2025-05-23T08:54:44.824Z" }, + { url = "https://files.pythonhosted.org/packages/3a/03/70f06753fd65081404ade30408535eb69f627a36ffce2107116d1aa16239/spacy-3.8.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4b5a624797ade30c25b5b69daa35a93ee24bcc56bd79b0884b2565f76f35d6", size = 33420084, upload-time = "2025-05-23T08:54:46.889Z" }, + { url = "https://files.pythonhosted.org/packages/f9/19/b60e1ebf4985ee2b33d85705b89a5024942b65dad04dbdc3fb46f168b410/spacy-3.8.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9d83e006df66decccefa3872fa958b3756228fb216d83783595444cf42ca10c", size = 33922188, upload-time = "2025-05-23T08:54:49.781Z" }, + { url = "https://files.pythonhosted.org/packages/8f/a3/1fb1a49dc6d982d96fffc30c3a31bb431526008eea72ac3773f6518720a6/spacy-3.8.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dca25deba54f3eb5dcfbf63bf16e613e6c601da56f91c4a902d38533c098941", size = 31939285, upload-time = "2025-05-23T08:54:53.162Z" }, + { url = "https://files.pythonhosted.org/packages/2d/55/6cf1aff8e5c01ee683e828f3ccd9282d2aff7ca1143a9349ee3d0c1291ff/spacy-3.8.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5eef3f805a1c118d9b709a23e2d378f5f20da5a0d6258c9cfdc87c4cb234b4fc", size = 32988845, upload-time = "2025-05-23T08:54:57.776Z" }, + { url = "https://files.pythonhosted.org/packages/8c/47/c17ee61b51aa8497d8af0999224b4b62485111a55ec105a06886685b2c68/spacy-3.8.7-cp312-cp312-win_amd64.whl", hash = "sha256:25d7a68e445200c9e9dc0044f8b7278ec0ef01ccc7cb5a95d1de2bd8e3ed6be2", size = 13918682, upload-time = "2025-05-23T08:55:00.387Z" }, + { url = "https://files.pythonhosted.org/packages/2a/95/7125bea6d432c601478bf922f7a568762c8be425bbde5b66698260ab0358/spacy-3.8.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dda7d57f42ec57c19fbef348095a9c82504e4777bca7b8db4b0d8318ba280fc7", size = 6235950, upload-time = "2025-05-23T08:55:02.92Z" }, + { url = "https://files.pythonhosted.org/packages/96/c3/d2362846154d4d341136774831605df02d61f49ac637524a15f4f2794874/spacy-3.8.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:de0e0bddb810ed05bce44bcb91460eabe52bc56323da398d2ca74288a906da35", size = 5878106, upload-time = "2025-05-23T08:55:04.496Z" }, + { url = "https://files.pythonhosted.org/packages/50/b6/b2943acfbfc4fc12642dac9feb571e712dd1569ab481db8f3daedee045fe/spacy-3.8.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a2e58f92b684465777a7c1a65d5578b1dc36fe55c48d9964fb6d46cc9449768", size = 33085866, upload-time = "2025-05-23T08:55:06.65Z" }, + { url = "https://files.pythonhosted.org/packages/65/98/c4415cbb217ac0b502dbb3372136015c699dd16a0c47cd6d338cd15f4bed/spacy-3.8.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46330da2eb357d6979f40ea8fc16ee5776ee75cd0c70aac2a4ea10c80364b8f3", size = 33398424, upload-time = "2025-05-23T08:55:10.477Z" }, + { url = "https://files.pythonhosted.org/packages/12/45/12a198858f1f11c21844876e039ba90df59d550527c72996d418c1faf78d/spacy-3.8.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:86b6a6ad23ca5440ef9d29c2b1e3125e28722c927db612ae99e564d49202861c", size = 31530066, upload-time = "2025-05-23T08:55:13.329Z" }, + { url = "https://files.pythonhosted.org/packages/9c/df/80524f99822eb96c9649200042ec5912357eec100cf0cd678a2e9ef0ecb3/spacy-3.8.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ccfe468cbb370888153df145ce3693af8e54dae551940df49057258081b2112f", size = 32613343, upload-time = "2025-05-23T08:55:16.711Z" }, + { url = "https://files.pythonhosted.org/packages/02/99/881f6f24c279a5a70b8d69aaf8266fd411a0a58fd1c8848112aaa348f6f6/spacy-3.8.7-cp313-cp313-win_amd64.whl", hash = "sha256:ca81e416ff35209769e8b5dd5d13acc52e4f57dd9d028364bccbbe157c2ae86b", size = 13911250, upload-time = "2025-05-23T08:55:19.606Z" }, +] + +[[package]] +name = "spacy-legacy" +version = "3.0.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/79/91f9d7cc8db5642acad830dcc4b49ba65a7790152832c4eceb305e46d681/spacy-legacy-3.0.12.tar.gz", hash = "sha256:b37d6e0c9b6e1d7ca1cf5bc7152ab64a4c4671f59c85adaf7a3fcb870357a774", size = 23806, upload-time = "2023-01-23T09:04:15.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/55/12e842c70ff8828e34e543a2c7176dac4da006ca6901c9e8b43efab8bc6b/spacy_legacy-3.0.12-py2.py3-none-any.whl", hash = "sha256:476e3bd0d05f8c339ed60f40986c07387c0a71479245d6d0f4298dbd52cda55f", size = 29971, upload-time = "2023-01-23T09:04:13.45Z" }, +] + +[[package]] +name = "spacy-loggers" +version = "1.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/67/3d/926db774c9c98acf66cb4ed7faf6c377746f3e00b84b700d0868b95d0712/spacy-loggers-1.0.5.tar.gz", hash = "sha256:d60b0bdbf915a60e516cc2e653baeff946f0cfc461b452d11a4d5458c6fe5f24", size = 20811, upload-time = "2023-09-11T12:26:52.323Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/78/d1a1a026ef3af911159398c939b1509d5c36fe524c7b644f34a5146c4e16/spacy_loggers-1.0.5-py3-none-any.whl", hash = "sha256:196284c9c446cc0cdb944005384270d775fdeaf4f494d8e269466cfa497ef645", size = 22343, upload-time = "2023-09-11T12:26:50.586Z" }, +] + +[[package]] +name = "spark-parser" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/e1/a443990c6c32cb7fa7d3896405d2924c4921c74c1ffd5b90ffaeb42f778a/spark_parser-1.9.0.tar.gz", hash = "sha256:dc66d48c4265c4133db41a9c5fe9c1c502b3b20167df158a0f234cd31712cf64", size = 80108, upload-time = "2024-10-08T13:51:02.148Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/c6/9d34faf67c92e14f1feaa036f6bc8beed0af71af1287060060af1b47bf9c/spark_parser-1.9.0-py310-none-any.whl", hash = "sha256:a1ab71c2df145b21c2c1c8aa5f001e36206bec259ec836504263ab7450881ad1", size = 45955, upload-time = "2024-10-08T13:45:04.437Z" }, + { url = "https://files.pythonhosted.org/packages/4b/bb/a13ae1bd3d257720e19d5d8a3dfa34cee38c5d9dd59dcb2c001bd0c6c310/spark_parser-1.9.0-py311-none-any.whl", hash = "sha256:30ab1a6005a783ca39f73ad477efb1e12a1cb0123607543e71690d9fd6fecf49", size = 63422, upload-time = "2024-10-08T13:45:05.451Z" }, + { url = "https://files.pythonhosted.org/packages/f1/9f/771e5add2467b6cadbcb560290bb6d9a4b069c3ca8483181245f5ea2d83e/spark_parser-1.9.0-py312-none-any.whl", hash = "sha256:036b8227c5b09a919a7eae50576f91d533124de1dbf9a9c654a2be5864f1c947", size = 63423, upload-time = "2024-10-08T13:45:07.059Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3d/074fef587d8c392e4e5d3599670fec88e01ebb5a5ddc1ada05b80f01a921/spark_parser-1.9.0-py313-none-any.whl", hash = "sha256:fc2e188601a6c8f7a68e2d7bd97ca377f6dc271a67607ff11e6beef39d0e9d1d", size = 63427, upload-time = "2024-10-14T10:49:03.625Z" }, +] + +[[package]] +name = "sqlparse" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/40/edede8dd6977b0d3da179a342c198ed100dd2aba4be081861ee5911e4da4/sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", size = 84999, upload-time = "2024-12-10T12:05:30.728Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415, upload-time = "2024-12-10T12:05:27.824Z" }, +] + +[[package]] +name = "srsly" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "catalogue" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/e8/eb51b1349f50bac0222398af0942613fdc9d1453ae67cbe4bf9936a1a54b/srsly-2.5.1.tar.gz", hash = "sha256:ab1b4bf6cf3e29da23dae0493dd1517fb787075206512351421b89b4fc27c77e", size = 466464, upload-time = "2025-01-17T09:26:26.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/f6/bebc20d75bd02121fc0f65ad8c92a5dd2570e870005e940faa55a263e61a/srsly-2.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:683b54ed63d7dfee03bc2abc4b4a5f2152f81ec217bbadbac01ef1aaf2a75790", size = 636717, upload-time = "2025-01-17T09:25:40.236Z" }, + { url = "https://files.pythonhosted.org/packages/b6/e8/9372317a4742c70b87b413335adfcdfb2bee4f88f3faba89fabb9e6abf21/srsly-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:459d987130e57e83ce9e160899afbeb871d975f811e6958158763dd9a8a20f23", size = 634697, upload-time = "2025-01-17T09:25:43.605Z" }, + { url = "https://files.pythonhosted.org/packages/d5/00/c6a7b99ab27b051a27bd26fe1a8c1885225bb8980282bf9cb99f70610368/srsly-2.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:184e3c98389aab68ff04aab9095bd5f1a8e5a72cc5edcba9d733bac928f5cf9f", size = 1134655, upload-time = "2025-01-17T09:25:45.238Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e6/861459e8241ec3b78c111081bd5efa414ef85867e17c45b6882954468d6e/srsly-2.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c2a3e4856e63b7efd47591d049aaee8e5a250e098917f50d93ea68853fab78", size = 1143544, upload-time = "2025-01-17T09:25:47.485Z" }, + { url = "https://files.pythonhosted.org/packages/2d/85/8448fe874dd2042a4eceea5315cfff3af03ac77ff5073812071852c4e7e2/srsly-2.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:366b4708933cd8d6025c13c2cea3331f079c7bb5c25ec76fca392b6fc09818a0", size = 1098330, upload-time = "2025-01-17T09:25:52.55Z" }, + { url = "https://files.pythonhosted.org/packages/ef/7e/04d0e1417da140b2ac4053a3d4fcfc86cd59bf4829f69d370bb899f74d5d/srsly-2.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c8a0b03c64eb6e150d772c5149befbadd981cc734ab13184b0561c17c8cef9b1", size = 1110670, upload-time = "2025-01-17T09:25:54.02Z" }, + { url = "https://files.pythonhosted.org/packages/96/1a/a8cd627eaa81a91feb6ceab50155f4ceff3eef6107916cb87ef796958427/srsly-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:7952538f6bba91b9d8bf31a642ac9e8b9ccc0ccbb309feb88518bfb84bb0dc0d", size = 632598, upload-time = "2025-01-17T09:25:55.499Z" }, + { url = "https://files.pythonhosted.org/packages/42/94/cab36845aad6e2c22ecee1178accaa365657296ff87305b805648fd41118/srsly-2.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84b372f7ef1604b4a5b3cee1571993931f845a5b58652ac01bcb32c52586d2a8", size = 634883, upload-time = "2025-01-17T09:25:58.363Z" }, + { url = "https://files.pythonhosted.org/packages/67/8b/501f51f4eaee7e1fd7327764799cb0a42f5d0de042a97916d30dbff770fc/srsly-2.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6ac3944c112acb3347a39bfdc2ebfc9e2d4bace20fe1c0b764374ac5b83519f2", size = 632842, upload-time = "2025-01-17T09:25:59.777Z" }, + { url = "https://files.pythonhosted.org/packages/07/be/5b8fce4829661e070a7d3e262d2e533f0e297b11b8993d57240da67d7330/srsly-2.5.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6118f9c4b221cde0a990d06a42c8a4845218d55b425d8550746fe790acf267e9", size = 1118516, upload-time = "2025-01-17T09:26:01.234Z" }, + { url = "https://files.pythonhosted.org/packages/91/60/a34e97564eac352c0e916c98f44b6f566b7eb6a9fb60bcd60ffa98530762/srsly-2.5.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7481460110d9986781d9e4ac0f5f991f1d6839284a80ad268625f9a23f686950", size = 1127974, upload-time = "2025-01-17T09:26:04.007Z" }, + { url = "https://files.pythonhosted.org/packages/70/a2/f642334db0cabd187fa86b8773257ee6993c6009338a6831d4804e2c5b3c/srsly-2.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e57b8138082f09e35db60f99757e16652489e9e3692471d8e0c39aa95180688", size = 1086098, upload-time = "2025-01-17T09:26:05.612Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9b/be48e185c5a010e71b5135e4cdf317ff56b8ac4bc08f394bbf882ac13b05/srsly-2.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bab90b85a63a1fe0bbc74d373c8bb9bb0499ddfa89075e0ebe8d670f12d04691", size = 1100354, upload-time = "2025-01-17T09:26:07.215Z" }, + { url = "https://files.pythonhosted.org/packages/3a/e2/745aeba88a8513017fbac2fd2f9f07b8a36065e51695f818541eb795ec0c/srsly-2.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:e73712be1634b5e1de6f81c273a7d47fe091ad3c79dc779c03d3416a5c117cee", size = 630634, upload-time = "2025-01-17T09:26:10.018Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "stopit" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/58/e8bb0b0fb05baf07bbac1450c447d753da65f9701f551dca79823ce15d50/stopit-1.1.2.tar.gz", hash = "sha256:f7f39c583fd92027bd9d06127b259aee7a5b7945c1f1fa56263811e1e766996d", size = 18281, upload-time = "2018-02-09T00:32:14.204Z" } + +[[package]] +name = "sympy" +version = "1.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/11/8a/5a7fd6284fa8caac23a26c9ddf9c30485a48169344b4bd3b0f02fef1890f/sympy-1.13.3.tar.gz", hash = "sha256:b27fd2c6530e0ab39e275fc9b683895367e51d5da91baa8d3d64db2565fec4d9", size = 7533196, upload-time = "2024-09-18T21:54:25.591Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/ff/c87e0622b1dadea79d2fb0b25ade9ed98954c9033722eb707053d310d4f3/sympy-1.13.3-py3-none-any.whl", hash = "sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73", size = 6189483, upload-time = "2024-09-18T21:54:23.097Z" }, +] + +[[package]] +name = "term-background" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/18/7dc8c71e6fac31a34a94225cb4f5f912439b1ef825f2332b34d7119d83ee/term_background-1.0.2.tar.gz", hash = "sha256:96dcba8b664f272c7f1db183be70c1825e936990b65566999583f14ca326c75c", size = 12320, upload-time = "2024-10-10T16:52:32.949Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/37/641ddef6347f9fd42638743dc745857ff1fb682dd7d1a7262de494dda259/term_background-1.0.2-py310-none-any.whl", hash = "sha256:e894ac4af47cdf2b5d5fab64470f912972f306af011f21687644d70d28698cc5", size = 12194, upload-time = "2024-10-10T16:50:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/1a/36/e0ccd50bdc44a68ea04233a3bec64238ebcdd9e1e0158e31adf141c84496/term_background-1.0.2-py311-none-any.whl", hash = "sha256:c80af48eea39bc19d134e52923264d3c3ad0b14fb33cd6b9ba9ad1eb45cea754", size = 5335, upload-time = "2024-10-10T16:50:13.426Z" }, + { url = "https://files.pythonhosted.org/packages/14/b6/b5b5b397fe5e302176cdaa8b446e7d387272f0962c55ab4f4404cc12b7bc/term_background-1.0.2-py312-none-any.whl", hash = "sha256:6b1f07bd95600786a671753a179e1ab38d971cac1a31758ab39968262fd4f259", size = 12375, upload-time = "2024-10-10T16:50:14.67Z" }, + { url = "https://files.pythonhosted.org/packages/ca/7b/515211e4f4ea8c5380b2139c2eda5088d38dd0b8e3cab8a60c3ec7674c25/term_background-1.0.2-py313-none-any.whl", hash = "sha256:61b8dee21ea1496e15eebd71a1f1727459920c19e0c52a183b4ca0143fa5adb7", size = 12380, upload-time = "2024-10-14T11:06:41.992Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ee/42b93f7120f1fbf30136deec18296db119f03eb2b5d7a93bba936b10f023/term_background-1.0.2-py34-none-any.whl", hash = "sha256:ff955ca76b72d3928598149aa8b5db942204904c6b45f3cc3c050ba4996db4b7", size = 12179, upload-time = "2024-10-10T16:51:24.423Z" }, + { url = "https://files.pythonhosted.org/packages/31/ce/9525eab178887653ed08568ef45d852ee8a7fc7103aa674b69ed59d63a7c/term_background-1.0.2-py35-none-any.whl", hash = "sha256:8b9836d90dd98f25f46afd24ed6e286ccd16d56f5dbb5d300d1d969fa2aceb2a", size = 12176, upload-time = "2024-10-10T16:51:25.868Z" }, + { url = "https://files.pythonhosted.org/packages/59/f8/73b31fb3ec42d3b8f4f0ee27e86fac140171620f9f05420654e8cc86bb42/term_background-1.0.2-py36-none-any.whl", hash = "sha256:540e48ec34fea7edf2482d23ede5ad359c1587f1c49bb7a23a35a5d47455c99d", size = 12213, upload-time = "2024-10-10T16:51:26.983Z" }, + { url = "https://files.pythonhosted.org/packages/2f/77/db99756367b5ef00418fdc14e3e5fc521266203ee89d8d3bdcc3bfc1b892/term_background-1.0.2-py37-none-any.whl", hash = "sha256:71d029eceb97313586324b16cfecf313478fa9cb8ed1379bbd3d2c81f3a8a64d", size = 12193, upload-time = "2024-10-10T16:51:28.601Z" }, + { url = "https://files.pythonhosted.org/packages/b4/91/9898424d425d8b6a51d64419a260b48cb8767ae374d90ebf8fd32b117b48/term_background-1.0.2-py38-none-any.whl", hash = "sha256:3f4c2c4f84398d091329142d6b16e139a8c136c8c66af1c554fabcafadc7738a", size = 12198, upload-time = "2024-10-10T16:51:29.795Z" }, + { url = "https://files.pythonhosted.org/packages/03/e2/0b7a43b2f0c87807de51045093424297172e1644faca3ccb7ecf79fb3ac0/term_background-1.0.2-py39-none-any.whl", hash = "sha256:029291ba62573c637227801ecd43cb7388355610ffb7710d68a9406be210be80", size = 12214, upload-time = "2024-10-10T16:51:30.518Z" }, +] + +[[package]] +name = "thinc" +version = "8.3.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "blis" }, + { name = "catalogue" }, + { name = "confection" }, + { name = "cymem" }, + { name = "murmurhash" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "preshed" }, + { name = "pydantic" }, + { name = "setuptools" }, + { name = "srsly" }, + { name = "wasabi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/f4/7607f76c2e156a34b1961a941eb8407b84da4f515cc0903b44d44edf4f45/thinc-8.3.6.tar.gz", hash = "sha256:49983f9b7ddc4343a9532694a9118dd216d7a600520a21849a43b6c268ec6cad", size = 194218, upload-time = "2025-04-04T11:50:45.751Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/c8/a9250944fb9a0a4c65b5d456f3a87ee6c249b53962757d77c28df8fadb46/thinc-8.3.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c54705e45a710e49758192592a3e0a80482edfdf5c61fc99f5d27ae822f652c5", size = 890177, upload-time = "2025-04-04T11:50:07.543Z" }, + { url = "https://files.pythonhosted.org/packages/3b/89/1ac54b18d4de79872c633302a10825695a36cd2e552cb8d4fea820b7a357/thinc-8.3.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:91acdbf3041c0ac1775ede570535a779cdf1312c317cd054d7b9d200da685c23", size = 839410, upload-time = "2025-04-04T11:50:09.26Z" }, + { url = "https://files.pythonhosted.org/packages/37/76/e1a76ab42e4637c4b8988d59784cdc1169a532d3043c36d2faf1a8d95228/thinc-8.3.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5a1db861614f91ff127feecce681c2213777b2d3d1ee6644bcc8a886acf0595", size = 4195748, upload-time = "2025-04-04T11:50:10.92Z" }, + { url = "https://files.pythonhosted.org/packages/00/a9/c59ac3260e7aff6b9dc80f495f1846a80b490595db06d040b05205d1f7f8/thinc-8.3.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:512e461989df8a30558367061d63ae6f1a6b4abe3c016a3360ee827e824254e0", size = 4261270, upload-time = "2025-04-04T11:50:12.953Z" }, + { url = "https://files.pythonhosted.org/packages/e0/8e/e86c5cbc6ebe238aa747ef9e20a969f6faba9ebbe1cbce059119f9614dd6/thinc-8.3.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a087aea2a63e6b9ccde61163d5922553b58908e96f8ad49cd0fd2edeb43e063f", size = 5067567, upload-time = "2025-04-04T11:50:18.317Z" }, + { url = "https://files.pythonhosted.org/packages/fe/8a/16670e4de36231aab5b052c734ad716be29aab2c0d2f3d8dd9c8dd27fafc/thinc-8.3.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b1d85dd5d94bb75006864c7d99fd5b75d05b1602d571e7fcdb42d4521f962048", size = 5309405, upload-time = "2025-04-04T11:50:20.075Z" }, + { url = "https://files.pythonhosted.org/packages/58/08/5439dd15b661610d8a3b919f18065ebf0d664b6a54a3794206622a74c910/thinc-8.3.6-cp312-cp312-win_amd64.whl", hash = "sha256:1170d85294366127d97a27dd5896f4abe90e2a5ea2b7988de9a5bb8e1128d222", size = 1749275, upload-time = "2025-04-04T11:50:21.769Z" }, + { url = "https://files.pythonhosted.org/packages/a6/03/0ba9bec3057f4a9c0b7ba53839aebcbbbc28de3b91330cb8de74a885b8f6/thinc-8.3.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d8743ee8ad2d59fda018b57e5da102d6098bbeb0f70476f3fd8ceb9d215d88b9", size = 883375, upload-time = "2025-04-04T11:50:23.273Z" }, + { url = "https://files.pythonhosted.org/packages/ae/79/ac31cd25d1d973b824de10ebbc56788688aecdd8f56800daf8edfff45097/thinc-8.3.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:89dbeb2ca94f1033e90999a70e2bc9dd5390d5341dc1a3a4b8793d03855265c3", size = 832654, upload-time = "2025-04-04T11:50:24.871Z" }, + { url = "https://files.pythonhosted.org/packages/f8/0d/fb5e8e49dfb53cc02ce907f81002031c6f4fe7e7aa44b1004ea695630017/thinc-8.3.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89a5460695067aa6e4182515cfd2018263db77cc17b7031d50ed696e990797a8", size = 4158592, upload-time = "2025-04-04T11:50:26.403Z" }, + { url = "https://files.pythonhosted.org/packages/e5/42/c87990ca214b9910f33b110d3b1ac213407388d35376bc955ad45e5de764/thinc-8.3.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0aa8e32f49234569fd10c35b562ee2f9c0d51225365a6e604a5a67396a49f2c1", size = 4236211, upload-time = "2025-04-04T11:50:27.943Z" }, + { url = "https://files.pythonhosted.org/packages/fa/10/9975bcee4dd4634bfb87df0447d7fa86d6c9b2d9228e56d4adb98cc19cbc/thinc-8.3.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f432158b80cf75a096980470b790b51d81daf9c2822598adebfc3cb58588fd6c", size = 5049197, upload-time = "2025-04-04T11:50:29.583Z" }, + { url = "https://files.pythonhosted.org/packages/9b/34/e1b384009eb8ad2192770157961cd0c2e2712fedf49e1dfd902e3d9b9973/thinc-8.3.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:61fb33a22aba40366fa9018ab34580f74fc40be821ab8af77ac1fdbeac17243b", size = 5278543, upload-time = "2025-04-04T11:50:31.524Z" }, + { url = "https://files.pythonhosted.org/packages/f0/26/f77ef4bd174bfeac491237a4ca3f74ba2ee2f672004f76cff90f8407a489/thinc-8.3.6-cp313-cp313-win_amd64.whl", hash = "sha256:ddd7041946a427f6a9b0b49419353d02ad7eb43fe16724bfcc3bdeb9562040b1", size = 1746883, upload-time = "2025-04-04T11:50:33.038Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[package]] +name = "tracer" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/a8/9f47e80c5fb2a908dd6f23f3eb22a182956425a75ca70f88be0384315361/tracer-2.0.0.tar.gz", hash = "sha256:baec4888666191ed7fb25c38c526a81d6c748787cacb649d6f67fd75da17687a", size = 26255, upload-time = "2024-10-14T16:42:07.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/97/2c0a11e1175b7473b4dfb743fe5c3b59455c002c25f8582ed2e17f4d48f9/tracer-2.0.0-py311-none-any.whl", hash = "sha256:3cf6876ab71c83e4bd361883b306dd1b536486ecdaec2e508b73e1a09d64bff7", size = 9772, upload-time = "2024-10-14T16:41:02.087Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/4a09e896e3208060cfa0aebd3d48d70494186967779980dccf0145f8bf48/tracer-2.0.0-py312-none-any.whl", hash = "sha256:8cf13a8305b9491d355c9f39a767c8bb069481f4bf4ac8d99c56a797f61dcc8a", size = 22087, upload-time = "2024-10-14T16:41:03.434Z" }, + { url = "https://files.pythonhosted.org/packages/40/c9/a1df0f756378dc8a54c3ebe43aa9d7ab18b4fd8be3d43622f218edf9f1f8/tracer-2.0.0-py313-none-any.whl", hash = "sha256:146e5f8d33a3c22dc1d274c956dd7c40f9763aada3e310e3b2beae0fb228bfa6", size = 22090, upload-time = "2024-10-14T16:41:04.357Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "trepan3k" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "columnize" }, + { name = "pyficache" }, + { name = "pygments" }, + { name = "spark-parser" }, + { name = "term-background" }, + { name = "tracer" }, + { name = "xdis" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/33/7a/ee387cfc09857785e6926a0809a372655cd47003fee6626ebe11c639c8c0/trepan3k-1.3.1.tar.gz", hash = "sha256:26d9adc7e618848f749654c2541c132c6572489af232045ec72df3080b0dc610", size = 427621, upload-time = "2025-01-16T23:06:11.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/bf/097a53738f3d825289ea1b1b1f8943a73e7432c15db94710340427c76990/trepan3k-1.3.1-py3-none-any.whl", hash = "sha256:e2036d216b649b550f63ff47358b48f3cecedf61ef5870e2e59864acaa24fbdd", size = 586588, upload-time = "2025-01-16T23:06:43.062Z" }, +] + +[[package]] +name = "typer" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, +] + +[[package]] +name = "urllib3" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, +] + +[[package]] +name = "wasabi" +version = "0.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/41/0c31737ee1a29c8b829690ebb4ab988b1f489aa2c3efa115a732a9dd7997/wasabi-0.10.1.tar.gz", hash = "sha256:c8e372781be19272942382b14d99314d175518d7822057cb7a97010c4259d249", size = 28380, upload-time = "2022-07-28T08:17:54.968Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/74/bd566f876c2de097e75d525c2696fb9829009987a0d93a4fb3576778a0a8/wasabi-0.10.1-py3-none-any.whl", hash = "sha256:fe862cc24034fbc9f04717cd312ab884f71f51a8ecabebc3449b751c2a649d83", size = 26075, upload-time = "2022-07-28T08:17:53.504Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, +] + +[[package]] +name = "weasel" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cloudpathlib" }, + { name = "confection" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "smart-open" }, + { name = "srsly" }, + { name = "typer" }, + { name = "wasabi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/1a/9c522dd61b52939c217925d3e55c95f9348b73a66a956f52608e1e59a2c0/weasel-0.4.1.tar.gz", hash = "sha256:aabc210f072e13f6744e5c3a28037f93702433405cd35673f7c6279147085aa9", size = 38417, upload-time = "2024-05-15T08:52:54.765Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/87/abd57374044e1f627f0a905ac33c1a7daab35a3a815abfea4e1bafd3fdb1/weasel-0.4.1-py3-none-any.whl", hash = "sha256:24140a090ea1ac512a2b2f479cc64192fd1d527a7f3627671268d08ed5ac418c", size = 50270, upload-time = "2024-05-15T08:52:52.977Z" }, +] + +[[package]] +name = "wrapt" +version = "1.17.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531, upload-time = "2025-01-14T10:35:45.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/bd/ab55f849fd1f9a58ed7ea47f5559ff09741b25f00c191231f9f059c83949/wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", size = 53799, upload-time = "2025-01-14T10:33:57.4Z" }, + { url = "https://files.pythonhosted.org/packages/53/18/75ddc64c3f63988f5a1d7e10fb204ffe5762bc663f8023f18ecaf31a332e/wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", size = 38821, upload-time = "2025-01-14T10:33:59.334Z" }, + { url = "https://files.pythonhosted.org/packages/48/2a/97928387d6ed1c1ebbfd4efc4133a0633546bec8481a2dd5ec961313a1c7/wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", size = 38919, upload-time = "2025-01-14T10:34:04.093Z" }, + { url = "https://files.pythonhosted.org/packages/73/54/3bfe5a1febbbccb7a2f77de47b989c0b85ed3a6a41614b104204a788c20e/wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", size = 88721, upload-time = "2025-01-14T10:34:07.163Z" }, + { url = "https://files.pythonhosted.org/packages/25/cb/7262bc1b0300b4b64af50c2720ef958c2c1917525238d661c3e9a2b71b7b/wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", size = 80899, upload-time = "2025-01-14T10:34:09.82Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5a/04cde32b07a7431d4ed0553a76fdb7a61270e78c5fd5a603e190ac389f14/wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", size = 89222, upload-time = "2025-01-14T10:34:11.258Z" }, + { url = "https://files.pythonhosted.org/packages/09/28/2e45a4f4771fcfb109e244d5dbe54259e970362a311b67a965555ba65026/wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", size = 86707, upload-time = "2025-01-14T10:34:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d2/dcb56bf5f32fcd4bd9aacc77b50a539abdd5b6536872413fd3f428b21bed/wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", size = 79685, upload-time = "2025-01-14T10:34:15.043Z" }, + { url = "https://files.pythonhosted.org/packages/80/4e/eb8b353e36711347893f502ce91c770b0b0929f8f0bed2670a6856e667a9/wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", size = 87567, upload-time = "2025-01-14T10:34:16.563Z" }, + { url = "https://files.pythonhosted.org/packages/17/27/4fe749a54e7fae6e7146f1c7d914d28ef599dacd4416566c055564080fe2/wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", size = 36672, upload-time = "2025-01-14T10:34:17.727Z" }, + { url = "https://files.pythonhosted.org/packages/15/06/1dbf478ea45c03e78a6a8c4be4fdc3c3bddea5c8de8a93bc971415e47f0f/wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", size = 38865, upload-time = "2025-01-14T10:34:19.577Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b9/0ffd557a92f3b11d4c5d5e0c5e4ad057bd9eb8586615cdaf901409920b14/wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125", size = 53800, upload-time = "2025-01-14T10:34:21.571Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ef/8be90a0b7e73c32e550c73cfb2fa09db62234227ece47b0e80a05073b375/wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998", size = 38824, upload-time = "2025-01-14T10:34:22.999Z" }, + { url = "https://files.pythonhosted.org/packages/36/89/0aae34c10fe524cce30fe5fc433210376bce94cf74d05b0d68344c8ba46e/wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5", size = 38920, upload-time = "2025-01-14T10:34:25.386Z" }, + { url = "https://files.pythonhosted.org/packages/3b/24/11c4510de906d77e0cfb5197f1b1445d4fec42c9a39ea853d482698ac681/wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8", size = 88690, upload-time = "2025-01-14T10:34:28.058Z" }, + { url = "https://files.pythonhosted.org/packages/71/d7/cfcf842291267bf455b3e266c0c29dcb675b5540ee8b50ba1699abf3af45/wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6", size = 80861, upload-time = "2025-01-14T10:34:29.167Z" }, + { url = "https://files.pythonhosted.org/packages/d5/66/5d973e9f3e7370fd686fb47a9af3319418ed925c27d72ce16b791231576d/wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc", size = 89174, upload-time = "2025-01-14T10:34:31.702Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d3/8e17bb70f6ae25dabc1aaf990f86824e4fd98ee9cadf197054e068500d27/wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2", size = 86721, upload-time = "2025-01-14T10:34:32.91Z" }, + { url = "https://files.pythonhosted.org/packages/6f/54/f170dfb278fe1c30d0ff864513cff526d624ab8de3254b20abb9cffedc24/wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b", size = 79763, upload-time = "2025-01-14T10:34:34.903Z" }, + { url = "https://files.pythonhosted.org/packages/4a/98/de07243751f1c4a9b15c76019250210dd3486ce098c3d80d5f729cba029c/wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504", size = 87585, upload-time = "2025-01-14T10:34:36.13Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f0/13925f4bd6548013038cdeb11ee2cbd4e37c30f8bfd5db9e5a2a370d6e20/wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a", size = 36676, upload-time = "2025-01-14T10:34:37.962Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ae/743f16ef8c2e3628df3ddfd652b7d4c555d12c84b53f3d8218498f4ade9b/wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845", size = 38871, upload-time = "2025-01-14T10:34:39.13Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bc/30f903f891a82d402ffb5fda27ec1d621cc97cb74c16fea0b6141f1d4e87/wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192", size = 56312, upload-time = "2025-01-14T10:34:40.604Z" }, + { url = "https://files.pythonhosted.org/packages/8a/04/c97273eb491b5f1c918857cd26f314b74fc9b29224521f5b83f872253725/wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b", size = 40062, upload-time = "2025-01-14T10:34:45.011Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ca/3b7afa1eae3a9e7fefe499db9b96813f41828b9fdb016ee836c4c379dadb/wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0", size = 40155, upload-time = "2025-01-14T10:34:47.25Z" }, + { url = "https://files.pythonhosted.org/packages/89/be/7c1baed43290775cb9030c774bc53c860db140397047cc49aedaf0a15477/wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306", size = 113471, upload-time = "2025-01-14T10:34:50.934Z" }, + { url = "https://files.pythonhosted.org/packages/32/98/4ed894cf012b6d6aae5f5cc974006bdeb92f0241775addad3f8cd6ab71c8/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb", size = 101208, upload-time = "2025-01-14T10:34:52.297Z" }, + { url = "https://files.pythonhosted.org/packages/ea/fd/0c30f2301ca94e655e5e057012e83284ce8c545df7661a78d8bfca2fac7a/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681", size = 109339, upload-time = "2025-01-14T10:34:53.489Z" }, + { url = "https://files.pythonhosted.org/packages/75/56/05d000de894c4cfcb84bcd6b1df6214297b8089a7bd324c21a4765e49b14/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6", size = 110232, upload-time = "2025-01-14T10:34:55.327Z" }, + { url = "https://files.pythonhosted.org/packages/53/f8/c3f6b2cf9b9277fb0813418e1503e68414cd036b3b099c823379c9575e6d/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6", size = 100476, upload-time = "2025-01-14T10:34:58.055Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b1/0bb11e29aa5139d90b770ebbfa167267b1fc548d2302c30c8f7572851738/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f", size = 106377, upload-time = "2025-01-14T10:34:59.3Z" }, + { url = "https://files.pythonhosted.org/packages/6a/e1/0122853035b40b3f333bbb25f1939fc1045e21dd518f7f0922b60c156f7c/wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555", size = 37986, upload-time = "2025-01-14T10:35:00.498Z" }, + { url = "https://files.pythonhosted.org/packages/09/5e/1655cf481e079c1f22d0cabdd4e51733679932718dc23bf2db175f329b76/wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c", size = 40750, upload-time = "2025-01-14T10:35:03.378Z" }, + { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594, upload-time = "2025-01-14T10:35:44.018Z" }, +] + +[[package]] +name = "xdis" +version = "6.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/94/de880a3be7219203bcc81769613d950614e446990ab48dea9d33477f7848/xdis-6.1.4.tar.gz", hash = "sha256:6e749661ac114c7b66edf4bd200e95066963c14ea039119651eb081a8da08ce6", size = 437460, upload-time = "2025-05-26T15:27:46.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/8e/5988895297d6bf0464fd8fbe9eeeba9feb486cd633005100bd2cb9cbd8fe/xdis-6.1.4-py310-none-any.whl", hash = "sha256:fe0c07b82d4e2b9cbc28b19aa3d74ecfed8e3c9448d08fe91495d756350668f6", size = 224058, upload-time = "2025-05-26T15:26:35.391Z" }, + { url = "https://files.pythonhosted.org/packages/f9/2c/449ddd0499da041edf6b2ebcf1388b0ece46630819e94b2fa5710fce7ca9/xdis-6.1.4-py311-none-any.whl", hash = "sha256:b767726edb151ea60a081ad4acf673f5ac171882bf28dadf829110259b7646f7", size = 181268, upload-time = "2025-05-26T15:26:37.237Z" }, + { url = "https://files.pythonhosted.org/packages/5c/61/d6ce5daf33ac21c8a9809d6ca5cf63acca5c2f3bd0bba56f90c76f2b538f/xdis-6.1.4-py312-none-any.whl", hash = "sha256:b58ddf1698d9c22e573c7c97b7d1917162ceddc5c14b5a12c8d5042b3d3fb803", size = 188308, upload-time = "2025-05-26T15:26:38.181Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f5/b6933dbd5da1f8e42c6cc704dff4551e458fd7075649bd503267f5c20a96/xdis-6.1.4-py313-none-any.whl", hash = "sha256:fac7b8e67c070102ba534f2630a39498afefe5bfc7d27741518f2b2b27c0d207", size = 188308, upload-time = "2025-05-26T15:26:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/47/43/63578140a59229c4a1d7439049d37e02863a7a0475be71041aa10e368988/xdis-6.1.4-py34-none-any.whl", hash = "sha256:0a6e393aa659f4003a9455a4d32c3b8a24cc02ab87863bfe17dbe43f0c29e354", size = 222948, upload-time = "2025-05-26T15:26:40.329Z" }, + { url = "https://files.pythonhosted.org/packages/ca/cc/3bf31c1a3e1bccf061296431c1a45b8cfbd1c66840ee86d0f7110a237656/xdis-6.1.4-py35-none-any.whl", hash = "sha256:2b030cbda54107a2b379f0ee76ad656b8799ebec72a3118d2d0b006c577e16f1", size = 222949, upload-time = "2025-05-26T15:26:41.378Z" }, + { url = "https://files.pythonhosted.org/packages/db/f9/35bb4a914439ea39392e55e2ef1825b51c78a54b89bb7375cc3ad81a4e05/xdis-6.1.4-py36-none-any.whl", hash = "sha256:64980c9e92e8134fc6d912af106249da2ae1209ee0cb4e127e0a6a74ee508b8f", size = 224080, upload-time = "2025-05-26T15:26:42.866Z" }, + { url = "https://files.pythonhosted.org/packages/f2/be/2a63f96542f5603a513bbb8f975afce9e87c184d426471a30d02e20a7324/xdis-6.1.4-py37-none-any.whl", hash = "sha256:fc929a900ba5806cbc5efa0d50b33be4b906fa03301bf5e6e2f06c8b11347d17", size = 224059, upload-time = "2025-05-26T15:26:44.6Z" }, + { url = "https://files.pythonhosted.org/packages/97/cf/8a46db3c71950aa7fa353203f78b9ab35870a2b2be19e2f025db31394f5a/xdis-6.1.4-py38-none-any.whl", hash = "sha256:b36dd09186eefe955347ba546735163b8e56f878c5702ec73ead4b6b45c5a309", size = 224062, upload-time = "2025-05-26T15:26:46.076Z" }, + { url = "https://files.pythonhosted.org/packages/a9/e9/dec1970a136784ebb1cf7f1381ab3cf3d2c4ae6ab0ad0f0d8bcc1e2787c7/xdis-6.1.4-py39-none-any.whl", hash = "sha256:b98fc10371a7ba3036ae5f8958ec8da3ec8c45115da2404e1fb561abeec323ac", size = 224077, upload-time = "2025-05-26T15:26:47.11Z" }, +] diff --git a/src/PostNewtonian.jl b/src/PostNewtonian.jl index d4859708..de5c3d74 100644 --- a/src/PostNewtonian.jl +++ b/src/PostNewtonian.jl @@ -1,214 +1,37 @@ module PostNewtonian -# Always explicitly address functions similar to functions defined in this package, -# which come from these packages: +using Base: @propagate_inbounds +using FastDifferentiation: FastDifferentiation, Node as FDNode +#using InlineExports: @public, @export # See below +using IrrationalConstants: @irrational using MacroTools: MacroTools -using FastDifferentiation: FastDifferentiation -using RuntimeGeneratedFunctions: RuntimeGeneratedFunctions - -# Otherwise, we just explicitly import specific functions: -using DataInterpolations: CubicSpline -using InteractiveUtils: methodswith -using LinearAlgebra: mul! -using Random: AbstractRNG, default_rng -using Quaternionic: QuatVec, Rotor, abs2vec, components, normalize, ⋅, × -using SphericalFunctions: D!, Diterator, Dprep, Yiterator -using OrdinaryDiffEqVerner: Vern9 -using SciMLBase: - ODEFunction, - ODEProblem, - solve, - remake, - terminate!, - CallbackSet, - DiscreteCallback, - VectorContinuousCallback, - ODESolution, - parameterless_type, - FullSpecialize, - AbstractDiffEqInterpolation, - build_solution, - get_du -using SciMLBase.ReturnCode: ReturnCode -using SymbolicIndexingInterface: SymbolCache -using RecursiveArrayTools: DiffEqArray -using StaticArrays: SVector, MVector +using Quaternionic: + Quaternionic, QuatVec, Rotor, 𝐢, 𝐣, 𝐤, abs2vec, absvec, components, normalize, ⋅, × +using StaticArrays: MVector, SVector using TestItems: @testitem -# See the "Code structure" section of the documentation for a description of the simple -# hierarchy into which this code is organized. The different levels of that hierarchy are -# reflected cleanly in the files `include`d below. - -# It's more common in PN to use `ln` — which I also prefer, as `log` seems ambiguous. -const ln = log - -include("utilities.jl") -export termination_forwards, - termination_backwards, dtmin_terminator, decreasing_v_terminator, nonfinite_terminator -using .MathConstants - -include("pn_systems.jl") -export PNSystem, pn_order, BBH, BHBH, BHNS, NSNS, BNS, FDPNSystem, fd_pnsystem - -include("pn_expansion.jl") -export PNExpansion, PNTerm, PNExpansionParameter - -include("fundamental_variables.jl") -using .FundamentalVariables -#export M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, Λ₁, Λ₂ # Avoid clashes: don't export - -include("derived_variables.jl") -using .DerivedVariables -export total_mass, # M, # Avoid clashes: don't export nicer names for important variables - reduced_mass, # μ, - reduced_mass_ratio, # ν, - mass_difference_ratio, # δ, - mass_ratio, # q, - chirp_mass, # ℳ, - # X1, X₁, - # X2, X₂, - n_hat, - n̂, - lambda_hat, - λ̂, - ell_hat, - ℓ̂, - Omega, - Ω, - S⃗₁, - S⃗₂, - S⃗, - Σ⃗, - χ⃗, - χ⃗ₛ, - χ⃗ₐ, - chi_perp, - χₚₑᵣₚ, - chi_eff, - χₑ, - chi_p, - χₚ, - S⃗₀⁺, - S⃗₀⁻, - S₀⁺ₙ, - S₀⁻ₙ, - S₀⁺λ, - S₀⁻λ, - S₀⁺ₗ, - S₀⁻ₗ, - χ₁², - χ₂², - χ₁, - χ₂, - χ₁₂, - χ₁ₗ, - χ₂ₗ, - χₛₗ, - χₐₗ, - Sₙ, - Σₙ, - Sλ, - Σλ, - Sₗ, - Σₗ, - sₗ, - σₗ, - S₁ₙ, - S₁λ, - S₁ₗ, - S₂ₙ, - S₂λ, - S₂ₗ, - rₕ₁, - rₕ₂, - Ωₕ₁, - Ωₕ₂, - sin²θ₁, - sin²θ₂, - ϕ̇̂₁, - ϕ̇̂₂, - Î₀₁, - Î₀₂, - κ₁, - κ₂, - κ₊, - κ₋, - λ₁, - λ₂, - λ₊, - λ₋, - Λ̃, - Lambda_tilde - -include("pn_expressions.jl") -export gw_energy_flux, - 𝓕, - tidal_heating, - binding_energy, - 𝓔, - binding_energy_deriv, - 𝓔′, - Omega_p, - Ω⃗ₚ, - Omega_chi1, - Ω⃗ᵪ₁, - Omega_chi2, - Ω⃗ᵪ₂, - #𝛡, aₗ, Ω⃗ᵪ # Too obscure to bother with - γₚₙ, - inverse_separation, - γₚₙ′, - inverse_separation_deriv, - γₚₙ⁻¹, - inverse_separation_inverse, - separation, # r, - separation_deriv, # r′, - separation_dot, # ṙ, - separation_inverse, # r⁻¹, - mode_weights!, - h! - -include("dynamics.jl") -export up_down_instability, - estimated_time_to_merger, fISCO, ΩISCO, uniform_in_phase, orbital_evolution - -include("waveforms.jl") -export coorbital_waveform, - inertial_waveform, - coorbital_waveform_computation_storage, - inertial_waveform_computation_storage, - coorbital_waveform!, - inertial_waveform! - -include("compatibility_layers.jl") -export GWFrames - -include("assorted_binaries/examples.jl") -export superkick, hangup_kick -include("assorted_binaries/random.jl") -# Base.rand is the only function in that file, hence no need for exports - -include("precompilation.jl") - -include("predefinitions_Symbolics.jl") - -if !isdefined(Base, :get_extension) - using Requires -end - -@static if !isdefined(Base, :get_extension) - # COV_EXCL_START - - function __init__() - @require Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" include( - "../ext/PostNewtonianSymbolicsExt.jl" - ) - @require ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" include( - "../ext/PostNewtonianForwardDiffExt.jl" - ) - end - - # COV_EXCL_STOP -end +# While I wait for https://github.com/dalum/InlineExports.jl/pull/2 to be merged, we do the +# following rather than import from the package itself. Once that is merged, we can add the +# package as a dependency, uncomment the line above, remove this block, and remove the +# following file. +include("core/utilities/InlineExports.jl") +using .InlineExports: @public, @export + +# These are definitions / aliases that are common in PN literature and/or used throughout +# this package. +@public const 𝒾 = im # Type this as `\scri` +@public const γₑ = Base.MathConstants.γ # Distinguish Euler's constant from `γₚₙ = M/r` +public ζ3 # Defined and documented in `core/utilities/misc.jl` + +# We will use these types to ensure that precision is preserved in PN expressions. +@public const ExactReal = Union{Integer,Rational,AbstractIrrational} +@public const ExactNumber = Union{ExactReal,Complex{<:ExactReal}} +@public const ExactIntegerBased = Union{Integer,Rational} + +include("pn_systems/pn_systems.jl") +include("core/core.jl") +include("literature/literature.jl") +include("pn_expressions/pn_expressions.jl") +include("interface/interface.jl") end # module PostNewtonian diff --git a/src/compatibility_layers.jl b/src/compatibility_layers.jl deleted file mode 100644 index dccb1c83..00000000 --- a/src/compatibility_layers.jl +++ /dev/null @@ -1 +0,0 @@ -include("compatibility_layers/gwframes.jl") diff --git a/src/core/PNBase.jl b/src/core/PNBase.jl new file mode 100644 index 00000000..9e5872c6 --- /dev/null +++ b/src/core/PNBase.jl @@ -0,0 +1,173 @@ +public PNBase + +# Documented below so that we can list the functions in the module automatically. +baremodule PNBase + +# We want to be able to use the Base operators like `+`, `-`, `*`, `/`, and `^`, but we're +# already redefining those operators here, so we need alternative characters for them. +# Julia defines operators that can be used with equivalent precedence and as infix operators +# in this file: https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm. +# Circled versions of each will work, except for `^`, for which we use an arrow. They can +# be typed as `\oplus`, `\ominus`, `\circledast`, `\oslash`, and `\uparrow`. +using Base: Base, + as ⊕, - as ⊖, * as ⊛, / as ⊘, ^ as ↑ + +using PostNewtonian: constant_convert, PNSystem, ExactNumber, ExactIntegerBased +using PostNewtonian.InlineExports: @export +using Base: @inline + +@export @inline ln(pnsystem::PNSystem, x) = Base.log(constant_convert(pnsystem, x)) +@inline ln(x::AbstractFloat) = Base.log(x) + +@export @inline √(pnsystem::PNSystem, x) = Base.sqrt(constant_convert(pnsystem, x)) +@inline √(x::AbstractFloat) = Base.sqrt(x) + +@export @inline (+)(pnsystem::PNSystem, x, y) = ⊕(constant_convert(pnsystem, x), y) +@inline (+)(pnsystem::PNSystem, x) = constant_convert(pnsystem, x) +# @inline function (+)(pnsystem::PNSystem, w, x, y, z...) +# return ⊕(constant_convert(pnsystem, w), x, y, z...) +# end +@inline (+)(x::AbstractFloat, y::AbstractFloat) = x ⊕ y +@inline (+)(x::AbstractFloat, y::ExactNumber) = x ⊕ y +@inline (+)(x::ExactNumber, y::AbstractFloat) = x ⊕ y +@inline (+)(x::ExactIntegerBased, y::ExactIntegerBased) = x ⊕ y +@inline (+)(x::Number) = x +(+)(x, y, z, args...) = Base.afoldl(+, (x + y) + z, args...) + +@export @inline (-)(pnsystem::PNSystem, x, y) = ⊖(constant_convert(pnsystem, x), y) +@inline (-)(x::AbstractFloat, y::AbstractFloat) = x ⊖ y +@inline (-)(x::AbstractFloat, y::ExactNumber) = x ⊖ y +@inline (-)(x::ExactNumber, y::AbstractFloat) = x ⊖ y +@inline (-)(x::ExactIntegerBased, y::ExactIntegerBased) = x ⊖ y +@inline (-)(x::Number) = ⊖(x) +@inline (-)(pnsystem::PNSystem, x) = ⊖(constant_convert(pnsystem, x)) + +@export @inline (*)(pnsystem::PNSystem, x, y) = ⊛(constant_convert(pnsystem, x), y) +@inline (*)(pnsystem::PNSystem, x) = constant_convert(pnsystem, x) +# @inline function (*)(pnsystem::PNSystem, w, x, y, z...) +# return ⊛(constant_convert(pnsystem, w), x, y, z...) +# end +@inline (*)(x::AbstractFloat, y::AbstractFloat) = x ⊛ y +@inline (*)(x::AbstractFloat, y::ExactNumber) = x ⊛ y +@inline (*)(x::ExactNumber, y::AbstractFloat) = x ⊛ y +@inline (*)(x::ExactIntegerBased, y::ExactIntegerBased) = x ⊛ y +(*)(x, y, z, args...) = Base.afoldl(*, (x * y) * z, args...) + +@export @inline (/)(pnsystem::PNSystem, x, y) = ⊘(constant_convert(pnsystem, x), y) +@inline (/)(x::AbstractFloat, y::AbstractFloat) = x ⊘ y +@inline (/)(x::AbstractFloat, y::ExactNumber) = x ⊘ y +@inline (/)(x::ExactNumber, y::AbstractFloat) = x ⊘ y + +@export @inline (^)(pnsystem::PNSystem, x, n) = ↑(constant_convert(pnsystem, x), n) +@inline (^)(x::AbstractFloat, n::ExactNumber) = x ↑ n +@inline (^)(x::ExactNumber, n::AbstractFloat) = x ↑ n +@inline (^)(x::AbstractFloat, n::AbstractFloat) = x ↑ n + +# We can actually use the original definition of `//` for most purposes; we define it +# both ways here for simplicity. +@export @inline (//)(pnsystem::PNSystem, x, y) = Base.://(x, y) +@inline (//)(x, y) = Base.://(x, y) + +end # baremodule PNBase + +# COV_EXCL_START (Covered, but missed due to const-folding) +const pnbase_functions = filter(s -> isa(getfield(PNBase, s), Function), names(PNBase)) +# COV_EXCL_END + +@doc """ + PNBase + +This module provides many of the same essential functions available in Julia's `Base` +module, but restricted to operations we expect to be used in post-Newtonian contexts, so +that we can ensure that the resulting expressions are valid within that framework. This is +intended to be used inside `@pn_expression` modules. + +It is intentionally very restrictive, so that it only includes the basic arithmetic +operations that are used in post-Newtonian expressions, and even then only in modified forms +that take a `PNSystem` as the first argument. The defined operations are + + $(pnbase_functions) + +This module is not intended to be used directly, but is imported by the +[`@pn_expression`](@ref) macro, and its methods are called by [`@pn_expansion`](@ref) to +ensure that the arithmetic operations preserve the number type of the input `PNSystem`. +""" +PNBase + +@testitem "PNBase" begin + baremodule Mod + using PostNewtonian.PNBase + end + + using PostNewtonian: pnbase_functions + + const ln = log + + for NT ∈ (Float16, Float64, BigFloat) + pnsystem = BHNS(randn(NT, 15)) + Z = (1, 2, 3, 17, 31, 3//13, 47//59) + z = (Z..., ℯ, π) + + for x ∈ z + @test eval(:(Mod.:+))(pnsystem, x) isa NT + @test eval(:(Mod.:+))(pnsystem, x) == NT(x) + @test eval(:(Mod.:+))(x) == x + + @test eval(:(Mod.:-))(pnsystem, x) isa NT + @test eval(:(Mod.:-))(pnsystem, x) == -NT(x) + @test eval(:(Mod.:-))(x) == -x + + @test eval(:(Mod.:*))(pnsystem, x) isa NT + @test eval(:(Mod.:*))(pnsystem, x) == NT(x) + end + + for f ∈ (:+, :*) + op = f≡:+ ? sum : prod + for w ∈ Z, x ∈ Z, y ∈ Z + @test eval(:(Mod.$f))(pnsystem, w, x, y) isa NT + @test eval(:(Mod.$f))(pnsystem, w, x, y) == op(NT, (w, x, y)) + @test eval(:(Mod.$f))(w, x, y) ≡ op((w, x, y)) + for v ∈ Z + @test eval(:(Mod.$f))(pnsystem, v, w, x, y) isa NT + @test eval(:(Mod.$f))(pnsystem, v, w, x, y) == op(NT, (v, w, x, y)) + @test eval(:(Mod.$f))(v, w, x, y) ≡ op((v, w, x, y)) + end + end + end + + for f ∈ (:+, :-, :*, :/, :^, :ln, :√) + @test f ∈ pnbase_functions + end + for f ∈ (:+, :-, :*, :/, :^) + for x ∈ z, y ∈ z + @test eval(:(Mod.$f))(pnsystem, x, y) isa NT + @test eval(:(Mod.$f))(pnsystem, x, y) == eval(:($f))(NT(x), NT(y)) + @test eval(:(Mod.$f))(x, NT(y)) isa NT + @test eval(:(Mod.$f))(x, NT(y)) ≈ eval(:($f))(NT(x), NT(y)) + @test eval(:(Mod.$f))(NT(x), y) isa NT + @test eval(:(Mod.$f))(NT(x), y) ≈ eval(:($f))(NT(x), NT(y)) + @test eval(:(Mod.$f))(NT(x), NT(y)) isa NT + @test eval(:(Mod.$f))(NT(x), NT(y)) == eval(:($f))(NT(x), NT(y)) + end + end + for f ∈ (:+, :-, :*, ://) + for x ∈ Z, y ∈ Z + @test typeof(eval(:(Mod.$f))(x, y)) ≡ typeof(eval(:($f))(x, y)) + @test eval(:(Mod.$f))(x, y) == eval(:($f))(x, y) + end + end + for x ∈ Z, y ∈ Z + @test typeof(eval(:(Mod.://))(pnsystem, x, y)) ≡ typeof(x // y) + @test eval(:(Mod.://))(pnsystem, x, y) == x // y + end + for f ∈ (:ln, :√) + for x ∈ z + @test eval(:(Mod.$f))(pnsystem, x) isa NT + @test eval(:(Mod.$f))(pnsystem, x) == eval(:($f))(NT(x)) + @test eval(:(Mod.$f))(NT(x)) == eval(:($f))(NT(x)) + end + for x ∈ Z + @test_throws MethodError eval(:(Mod.$f))((x)) + end + end + end +end diff --git a/src/pn_expansion.jl b/src/core/PNExpansion.jl similarity index 52% rename from src/pn_expansion.jl rename to src/core/PNExpansion.jl index 070186da..44bf561d 100644 --- a/src/pn_expansion.jl +++ b/src/core/PNExpansion.jl @@ -1,3 +1,19 @@ +# We enclose all of this in a `baremodule` so that we can isolate Base operations, and use +# PNBase operations by default. +baremodule PNExpansions + +# See explanation in `PNBase.jl` for why we use these operators. +using Base: Base, NTuple, ntuple, Val, Vector, @doc, @raw_str, @assert, @inbounds, @__dot__, + (:), eltype, promote_type, isbitstype, min, max, one, zero, + ==, ≤, <, >, ÷, + as ⊕, - as ⊖, * as ⊛, / as ⊘, ^ as ↑ + +using PostNewtonian: PostNewtonian +using PostNewtonian.PNBase +using PostNewtonian.PNTerms +using PostNewtonian.InlineExports: @export, @public +using StaticArrays: MVector, SVector +import FastDifferentiation + # This a utility that allow us to interoperate with FastDifferentiation.Node and other # Number types. function _efficient_vector(::Val{N}, ::Val{T}) where {N,T} @@ -39,67 +55,61 @@ The `N` parameter is not related to the PN order; it is just used by Julia to kn elements are currently in the coefficients, but is required to be 1 ≤ N ≤ NMax. """ -struct PNExpansion{N,T,NMax} +@public struct PNExpansion{N,T,NMax} coeffs::NTuple{N,T} function PNExpansion{N,T,NMax}(coeffs) where {N,T,NMax} if N < 1 - throw(ArgumentError("`N=$N` must be >0.")) + throw(ArgumentError("`N=$N` must be greater than 0.")) # COV_EXCL_LINE end if N > NMax - throw(ArgumentError("`N=$N` must be <`NMax=$NMax`.")) + throw(ArgumentError("`N=$N` must be less than `NMax=$NMax`.")) # COV_EXCL_LINE end return new{N,T,NMax}(coeffs) end function PNExpansion(coeffs::NTuple{N,T}, NMax) where {N,T} if N < 1 - throw(ArgumentError("`N=$N` must be >0.")) + throw(ArgumentError("`N=$N` must be greater than 0.")) end if N > NMax - throw(ArgumentError("`N=$N` must be <`NMax=$NMax`.")) + throw(ArgumentError("`N=$N` must be less than `NMax=$NMax`.")) # COV_EXCL_LINE end return new{N,T,NMax}(coeffs) end end -pn_order(::PNExpansion{N,T,NMax}) where {N,T,NMax} = (NMax - 1)//2 +Base.Tuple(pn::PNExpansion) = pn.coeffs +SVector(pn::PNExpansion) = SVector(pn.coeffs) + +PostNewtonian.pn_order(::PNExpansion{N,T,NMax}) where {N,T,NMax} = (NMax ⊖ 1)//2 Base.getindex(pn::PNExpansion, i::Int) = pn.coeffs[i] -Base.length(pn::PNExpansion) = length(pn.coeffs) -Base.eltype(pn::PNExpansion) = eltype(pn.coeffs) +Base.length(pn::PNExpansion) = Base.length(pn.coeffs) +Base.eltype(pn::PNExpansion) = Base.eltype(pn.coeffs) function Base.sum(pn_expansion::PNExpansion{N,T,NMax}) where {N,T,NMax} - return sum(pn_expansion[i] for i ∈ 1:N, init ∈ zero(T)) + return Base.sum(pn_expansion.coeffs; init=zero(T)) end -function Base.:+(pn::PNExpansion{N,T1,NMax}, x::T2) where {N,T1,NMax,T2<:Number} +function PNBase.:+(pn::PNExpansion{N,T1,NMax}, x::T2) where {N,T1,NMax,T2<:Number} T3 = promote_type(T1, T2) return PNExpansion(ntuple(i -> i == 1 ? pn[1] + x : T3(pn[i]), Val(N)), NMax) end -Base.:+(x::T, pn::PNExpansion) where {T<:Number} = pn + x -function Base.:-(pn::PNExpansion{N,T,NMax}) where {N,T,NMax} - return PNExpansion{N,T,NMax}((-).(pn.coeffs)) -end +PNBase.:+(x::T, pn::PNExpansion) where {T<:Number} = PNBase.:+(pn, x) -function Base.:*(pn::PNExpansion{N,T1,NMax}, x::T2) where {N,T1,NMax,T2<:Number} - T3 = promote_type(T1, T2) - return PNExpansion{N,T3,NMax}(@. T3(pn.coeffs * x)) -end -Base.:*(x::T, pn::PNExpansion) where {T<:Number} = pn * x - -function Base.:+( +function PNBase.:+( pn1::PNExpansion{N1,T1,NMax1}, pn2::PNExpansion{N2,T2,NMax2} ) where {N1,N2,T1,T2,NMax1,NMax2} throw( ArgumentError( - "`PNExpansion` addition is only defined for objects of the same PN order." * + "`PNExpansion` addition is only defined for objects of the same PN order." ⊛ "\nGot NMax1=$(NMax1) and NMax2=$(NMax2).", ), ) end -function Base.:+( +function PNBase.:+( pn1::PNExpansion{N1,T1,NMax}, pn2::PNExpansion{N2,T2,NMax} ) where {N1,N2,T1,T2,NMax} if N1 > N2 @@ -114,161 +124,27 @@ function sum_term( ) where {N1,N2,T1,T2,NMax} T3 = promote_type(T1, T2) if i ≤ N1 - return T3(pn1.coeffs[i] + pn2.coeffs[i]) + return T3(pn1.coeffs[i] ⊕ pn2.coeffs[i]) else return T3(pn2.coeffs[i]) end end -function Base.:*( - pn1::PNExpansion{N1,T1,NMax1}, pn2::PNExpansion{N2,T2,NMax2} -) where {N1,N2,T1,T2,NMax1,NMax2} - throw( - ArgumentError( - "`PNExpansion` multiplication is only defined for objects of the same PN order." * - "\nGot NMax1=$(NMax1) and NMax2=$(NMax2).", - ), - ) -end - -function Base.:*( - pn1::PNExpansion{N1,T1,NMax}, pn2::PNExpansion{N2,T2,NMax} -) where {N1,N2,T1,T2,NMax} - if N1 > N2 - return pn2 * pn1 - else - N3 = min(N1 + N2 - 1, NMax) - PNExpansion(ntuple(i -> product_term(i, pn1, pn2), Val(N3)), NMax) - end -end - -function product_term( - i, pn1::PNExpansion{N1,T1,NMax}, pn2::PNExpansion{N2,T2,NMax} -) where {N1,N2,T1,T2,NMax} - T3 = promote_type(T1, T2) - return sum( - pn1.coeffs[j] * pn2.coeffs[i - j + 1] for - j ∈ max(1, i - N2 + 1):min(i, N1), init ∈ zero(T3) - ) -end - -Base.:/(p::PNExpansion, x::Number) = p * (1 / x) - -function FastDifferentiation.derivative( - pn_expansion::PNExpansion{N,T,NMax}, fd_node::FastDifferentiation.Node -) where {N,T,NMax} - return PNExpansion( - ntuple(i -> FastDifferentiation.derivative(pn_expansion[i], fd_node), Val(N)), NMax - ) -end - -Base.Tuple(pn::PNExpansion) = pn.coeffs -SVector(pn::PNExpansion) = SVector(pn.coeffs) - -""" - PNTerm{T,PNOrder,c⁻¹Exponent} - -This object represents a single term in a PNExpansion. It has a single field: `coeff`, -which is the coefficient of the term. The type parameter `T` is the type of the -coefficient. The type parameter `PNOrder` is a half-integer (just as in -[`PNSystem`](@ref)s) representing the PN order of the expansion. And the type parameter -`c⁻¹Exponent` is an integer representing the exponent of the PN expansion parameter ``1/c``. - -`PNTerm`s can be multiplied and divided by scalars and exponentiated by integers, to produce -another `PNTerm`. They can also be added to other `PNTerm`s to produce a `PNExpansion`. - -A simple way to define a `PNTerm` or a `PNExpansion` is to define the PN expansion parameter -```julia -c = PNExpansionParameter(pnsystem) -``` -and use that naturally in formulas, as in -```julia -e = 1 + (v/c)^2 * (-ν/12 - 3//4) + (v/c)^4 * (-ν^2/24 + 19ν/8 - 27//8) -``` -Any exponent higher than the desired `PNOrder` will be automatically set to zero. - -Useful facts: - - `v` has order `1/c` - - `x` has order `1/c^2` - - `γ` has order `1/c^2` - - `1/r` has order `1/c^2` - -""" -struct PNTerm{T,PNOrder,c⁻¹Exponent} - coeff::T - - function PNTerm{T,PNOrder,c⁻¹Exponent}(coeff) where {T,PNOrder,c⁻¹Exponent} - if c⁻¹Exponent > 2PNOrder - coeff = zero(coeff) - end - return new{T,PNOrder,c⁻¹Exponent}(coeff) - end - function PNTerm{T,PNOrder}(c⁻¹exp::Int, coeff) where {T,PNOrder} - if c⁻¹exp > 2PNOrder - coeff = zero(coeff) - end - return new{T,PNOrder,c⁻¹exp}(coeff) - end -end - -Base.length(pn::PNTerm) = 1 -Base.eltype(pn::PNTerm{T}) where {T} = T -c⁻¹exp(pn::PNTerm{T,PNOrder,c⁻¹Exponent}) where {T,PNOrder,c⁻¹Exponent} = c⁻¹Exponent - -function Base.sum(pn::PNTerm) - return pn.coeff -end - -function Base.:+(pn::PNTerm) - return pn -end - -function Base.inv(term::PNTerm{T,PNOrder,c⁻¹Exponent}) where {T,PNOrder,c⁻¹Exponent} - return PNTerm{T,PNOrder}(-c⁻¹exp(term), inv(term.coeff)) -end - -function Base.:^(term::PNTerm{T,PNOrder,c⁻¹Exponent}, n::Int) where {T,PNOrder,c⁻¹Exponent} - coeff = term.coeff^n - return PNTerm{typeof(coeff),PNOrder}(c⁻¹exp(term) * n, coeff) -end - -function Base.:*( - x::Number, term::PNTerm{T,PNOrder,c⁻¹Exponent} -) where {T,PNOrder,c⁻¹Exponent} - coeff = x * term.coeff - return PNTerm{typeof(coeff),PNOrder,c⁻¹Exponent}(coeff) -end -Base.:*(term::PNTerm, x::Number) = x * term - -function Base.:/( - term::PNTerm{T,PNOrder,c⁻¹Exponent}, x::Number -) where {T,PNOrder,c⁻¹Exponent} - coeff = term.coeff / x - return PNTerm{typeof(coeff),PNOrder,c⁻¹Exponent}(coeff) -end - -function Base.:/( - x::Number, term::PNTerm{T,PNOrder,c⁻¹Exponent} -) where {T,PNOrder,c⁻¹Exponent} - coeff = x / term.coeff - return PNTerm{typeof(coeff),PNOrder}(-c⁻¹exp(term), coeff) -end - -function Base.:+( +function PNBase.:+( x::T1, term::PNTerm{T2,PNOrder,c⁻¹Exponent} ) where {T1<:Number,T2,PNOrder,c⁻¹Exponent} if c⁻¹exp(term) < 0 throw( ArgumentError( - "Cannot add a `PNTerm` with a negative exponent: " * - "c⁻¹exp(term)=$(c⁻¹exp(term))." * + "Cannot add a `PNTerm` with a negative exponent: " ⊛ + "c⁻¹exp(term)=$(c⁻¹exp(term))." ⊛ "\nResult will be a `PNExpansion`, which cannot store positive exponents.", ), ) end T = promote_type(T1, T2) - N₀ = c⁻¹exp(term) + 1 - NMax = Int(2PNOrder + 1) + N₀ = c⁻¹exp(term) ⊕ 1 + NMax = Int(2 ⊛ PNOrder ⊕ 1) N = min(N₀, NMax) coeffs = _efficient_vector(Val(N), Val(T)) coeffs .= zero(T) @@ -278,36 +154,17 @@ function Base.:+( end return PNExpansion{N,T,NMax}(Tuple(coeffs)) end -Base.:+(term::PNTerm, x::Number) = x + term - -function Base.:-(term::PNTerm{T,PNOrder,c⁻¹Exponent}) where {T,PNOrder,c⁻¹Exponent} - return PNTerm{T,PNOrder,c⁻¹Exponent}(-term.coeff) -end - -function Base.:*( - term1::PNTerm{T1,PNOrder,c⁻¹E1}, term2::PNTerm{T2,PNOrder,c⁻¹E2} -) where {T1,T2,PNOrder,c⁻¹E1,c⁻¹E2} - c⁻¹Exponent = c⁻¹exp(term1) + c⁻¹exp(term2) - coeff = term1.coeff * term2.coeff - return PNTerm{typeof(coeff),PNOrder,c⁻¹Exponent}(coeff) -end -function Base.:/( - term1::PNTerm{T1,PNOrder,c⁻¹E1}, term2::PNTerm{T2,PNOrder,c⁻¹E2} -) where {T1,T2,PNOrder,c⁻¹E1,c⁻¹E2} - c⁻¹Exponent = c⁻¹E1 - c⁻¹E2 - coeff = term1.coeff / term2.coeff - return PNTerm{typeof(coeff),PNOrder,c⁻¹Exponent}(coeff) -end +PNBase.:+(term::PNTerm, x::Number) = PNBase.:+(x, term) -function Base.:+( +function PNBase.:+( term1::PNTerm{T1,PNOrder,c⁻¹E1}, term2::PNTerm{T2,PNOrder,c⁻¹E2} ) where {T1,T2,PNOrder,c⁻¹E1,c⁻¹E2} if c⁻¹exp(term1) < 0 throw( ArgumentError( - "Cannot add a `PNTerm` with a negative exponent: " * - "c⁻¹exp(term1)=$(c⁻¹exp(term1))." * + "Cannot add a `PNTerm` with a negative exponent: " ⊛ + "c⁻¹exp(term1)=$(c⁻¹exp(term1))." ⊛ "\nResult will be a `PNExpansion`, which cannot store positive exponents.", ), ) @@ -315,16 +172,16 @@ function Base.:+( if c⁻¹exp(term2) < 0 throw( ArgumentError( - "Cannot add a `PNTerm` with a negative exponent: " * - "c⁻¹exp(term2)=$(c⁻¹exp(term2))." * + "Cannot add a `PNTerm` with a negative exponent: " ⊛ + "c⁻¹exp(term2)=$(c⁻¹exp(term2))." ⊛ "\nResult will be a `PNExpansion`, which cannot store positive exponents.", ), ) end T = promote_type(T1, T2) - N1₀ = c⁻¹exp(term1) + 1 - N2₀ = c⁻¹exp(term2) + 1 - NMax = Int(2PNOrder + 1) + N1₀ = c⁻¹exp(term1) ⊕ 1 + N2₀ = c⁻¹exp(term2) ⊕ 1 + NMax = Int(2 ⊛ PNOrder ⊕ 1) N = min(max(N1₀, N2₀), NMax) coeffs = _efficient_vector(Val(N), Val(T)) coeffs .= zero(T) @@ -337,22 +194,20 @@ function Base.:+( return PNExpansion{N,T,NMax}(Tuple(coeffs)) end -Base.:-(term1::PNTerm, term2::PNTerm) = term1 + (-term2) - -function Base.:+( +function PNBase.:+( term::PNTerm{T1,PNOrder,c⁻¹E1}, expansion::PNExpansion{N2,T2,NMax2} ) where {T1,PNOrder,c⁻¹E1,N2,T2,NMax2} if c⁻¹exp(term) < 0 throw( ArgumentError( - "Cannot add a `PNTerm` with a negative exponent: " * - "c⁻¹exp(term)=$(c⁻¹exp(term))." * + "Cannot add a `PNTerm` with a negative exponent: " ⊛ + "c⁻¹exp(term)=$(c⁻¹exp(term))." ⊛ "\nResult will be a `PNExpansion`, which cannot store positive exponents.", ), ) end - N1 = c⁻¹exp(term) + 1 - NMax1 = Int(2PNOrder + 1) + N1 = c⁻¹exp(term) ⊕ 1 + NMax1 = Int(2 ⊛ PNOrder ⊕ 1) NMax = min(NMax1, NMax2) N = min(max(N1, N2), NMax) T = promote_type(T1, T2) @@ -368,31 +223,76 @@ function Base.:+( end return PNExpansion{N,T,NMax}(Tuple(coeffs)) end -Base.:+(expansion::PNExpansion, term::PNTerm) = term + expansion -Base.:-(term::PNTerm, x::Number) = term + (-x) -Base.:-(x::Number, term::PNTerm) = x + (-term) -Base.:-(term::PNTerm, expansion::PNExpansion) = term + (-expansion) -Base.:-(expansion::PNExpansion, term::PNTerm) = expansion + (-term) -Base.:-(x::Number, expansion::PNExpansion) = x + (-expansion) -Base.:-(expansion::PNExpansion, x::Number) = expansion + (-x) +PNBase.:+(expansion::PNExpansion, term::PNTerm) = PNBase.:+(term, expansion) + +PNBase.:-(term1::PNTerm, term2::PNTerm) = PNBase.:+(term1, -term2) +PNBase.:-(term::PNTerm, x::Number) = PNBase.:+(term, -x) +PNBase.:-(x::Number, term::PNTerm) = PNBase.:+(x, -term) +PNBase.:-(term::PNTerm, expansion::PNExpansion) = PNBase.:+(term, -expansion) +PNBase.:-(expansion::PNExpansion, term::PNTerm) = PNBase.:+(expansion, -term) +PNBase.:-(x::Number, expansion::PNExpansion) = PNBase.:+(x, -expansion) +PNBase.:-(expansion::PNExpansion, x::Number) = PNBase.:+(expansion, -x) + +function PNBase.:-(pn::PNExpansion{N,T,NMax}) where {N,T,NMax} + return PNExpansion{N,T,NMax}((-).(pn.coeffs)) +end + +function PNBase.:*(pn::PNExpansion{N,T1,NMax}, x::T2) where {N,T1,NMax,T2<:Number} + T3 = promote_type(T1, T2) + return PNExpansion{N,T3,NMax}(@. T3(pn.coeffs * x)) +end + +PNBase.:*(x::T, pn::PNExpansion) where {T<:Number} = PNBase.:*(pn, x) + +function PNBase.:*( + pn1::PNExpansion{N1,T1,NMax1}, pn2::PNExpansion{N2,T2,NMax2} +) where {N1,N2,T1,T2,NMax1,NMax2} + throw( + ArgumentError( + "`PNExpansion` multiplication is only defined for objects of the same PN order." ⊛ + "\nGot NMax1=$(NMax1) and NMax2=$(NMax2).", + ), + ) +end + +function PNBase.:*( + pn1::PNExpansion{N1,T1,NMax}, pn2::PNExpansion{N2,T2,NMax} +) where {N1,N2,T1,T2,NMax} + if N1 > N2 + return PNBase.:*(pn2, pn1) + else + N3 = min(N1 + N2 - 1, NMax) + PNExpansion(ntuple(i -> product_term(i, pn1, pn2), Val(N3)), NMax) + end +end + +function product_term( + i, pn1::PNExpansion{N1,T1,NMax}, pn2::PNExpansion{N2,T2,NMax} +) where {N1,N2,T1,T2,NMax} + T3 = promote_type(T1, T2) + return Base.sum( + pn1.coeffs[j] ⊛ pn2.coeffs[i - j + 1] for j ∈ max(1, i - N2 + 1):min(i, N1); + init=zero(T3), + ) +end -function Base.:*( +function PNBase.:*( expansion::PNExpansion{N1,T1,NMax1}, term::PNTerm{T2,PNOrder,c⁻¹E2} ) where {N1,T1,NMax1,T2,PNOrder,c⁻¹E2} ΔN = c⁻¹exp(term) # Note that ΔN may be negative! - NMax2 = Int(2PNOrder + 1) + NMax2 = Int(2 ⊛ PNOrder ⊕ 1) NMax = min(NMax1, NMax2) - N = min(max(N1, N1 + ΔN), NMax) + N = min(max(N1, N1 ⊕ ΔN), NMax) # Check that no terms from expansion will be lost to negative PN orders - @inbounds for i ∈ 1:min(max(0, -ΔN), N1) + @inbounds for i ∈ 1:min(max(0, ⊖(ΔN)), N1) if !iszero(expansion[i]) throw( ArgumentError( - "Cannot multiply `PNExpansion` by `PNTerm` with negative exponent: " * - "c⁻¹exp(term)=$(c⁻¹exp(term))." * - "\nResult will be a `PNExpansion`, which cannot store positive exponents.", + "Cannot multiply `PNExpansion` by `PNTerm` with negative exponent: " ⊛ + "c⁻¹exp(term)=$(c⁻¹exp(term)).\nThe result will be a `PNExpansion`, " ⊛ + "which cannot store positive exponents.", ), ) end @@ -401,24 +301,88 @@ function Base.:*( T = promote_type(T1, T2) coeffs = _efficient_vector(Val(N), Val(T)) coeffs .= zero(T) - @inbounds for i ∈ max(1, 1 - ΔN):min(N1, N - ΔN) - coeffs[i + ΔN] = expansion[i] * term.coeff + @inbounds for i ∈ max(1, 1 ⊖ ΔN):min(N1, N ⊖ ΔN) + coeffs[i ⊕ ΔN] = expansion[i] ⊛ term.coeff end return PNExpansion{N,T,NMax}(Tuple(coeffs)) end -Base.:*(term::PNTerm, expansion::PNExpansion) = expansion * term + +PNBase.:*(term::PNTerm, expansion::PNExpansion) = PNBase.:*(expansion, term) # (a, b, c, d, e, f, g) * (c⁻¹^2) = (0, 0, a, b, c, d, e) -Base.:/(expansion::PNExpansion, term::PNTerm) = expansion * inv(term) +PNBase.:/(expansion::PNExpansion, x) = PNBase.:*(expansion, Base.inv(x)) -""" - PNExpansionParameter(pnsystem) +# Note that an PNExpansion is really a *relative* expansion in `1/c` — *not* `v` or `x`. +# Therefore, the correct derivative with respect to any variable (other than `c`, which we +# never differentiate with respect to) extends to just derivatives of the coefficients, +# without any change to the exponent of `1/c`. +function FastDifferentiation.derivative( + pn_expansion::PNExpansion{N,T,NMax}, fd_node::FastDifferentiation.Node +) where {N,T,NMax} + return PNExpansion( + ntuple(i -> FastDifferentiation.derivative(pn_expansion[i], fd_node), Val(N)), NMax + ) +end -Create a [`PNTerm`](@ref) object representing the post-Newtonian expansion parameter ``c``. -This can be used to automatically create more complicated `PNTerm`s, which combine to form a -[`PNExpansion`](@ref). This is a simple but effective way to write PN formulas while -automatically tracking the PN order of each term. -""" -function PNExpansionParameter(::PNSystem{ST,PNOrder}) where {ST,PNOrder} - return PNTerm{eltype(ST),PNOrder}(-1, one(eltype(ST))) +end # baremodule PNExpansions + +@testitem "PNExpansion algebra" begin + using Base: Base, one, zero, <, ÷, + as ⊕, - as ⊖, * as ⊛, / as ⊘, ^ as ↑ + using StaticArrays: MVector, SVector + using Symbolics: @variables, simplify, substitute + using PostNewtonian.PNBase: ln, (√), (+), (-), (*), (/), (//), (^) + using PostNewtonian.PNExpansions: PNExpansion + + # Test edge cases + @test_throws ArgumentError PNExpansion{0, Float64, 1}(()) + @test_throws ArgumentError PNExpansion{2, Float64, 1}((1.2, 3.4)) + @test_throws ArgumentError PNExpansion((), 0) + @test_throws ArgumentError PNExpansion((1.2, 3.4), 1) + + for N1 ∈ 1:9 + # Test conversions + coeffs = ntuple(i -> i + 1.0, N1) + for NMax ∈ N1:(N1 ⊕ 3) + expansion = PNExpansion(coeffs, NMax) + @test Base.Tuple(expansion) == coeffs + @test SVector(expansion) == SVector(coeffs) + @test Base.eltype(expansion) == Float64 + @test Base.length(expansion) == N1 + for i ∈ 1:N1 + @test expansion[i] == coeffs[i] + end + end + + for N2 ∈ 1:9 + for NMax ∈ max(N1, N2):(N1 ⊕ N2 ⊕ 3) + + @variables c⁻¹ x[1:N1] y[1:N2] z + poly(e::PNExpansion) = sum(e[i] ⊛ c⁻¹↑(i ⊖ 1) for i ∈ 1:length(e)) + eˣ = PNExpansion(tuple(x...), NMax) + eʸ = PNExpansion(tuple(y...), NMax) + + # Test sums + polysum = simplify(poly(eˣ + eʸ); expand=true) + sumpoly = simplify(poly(eˣ) ⊕ poly(eʸ); expand=true) + Δ = simplify(polysum ⊖ sumpoly; expand=true) + @test iszero(Δ) + @test_throws ArgumentError eˣ + PNExpansion(tuple(z, x...), NMax ⊕ 1) + @test_throws ArgumentError PNExpansion(tuple(z, x...), NMax ⊕ 1) + eˣ + + # Test products + polyprod = simplify(poly(eˣ * eʸ); expand=true) + prodpoly = simplify( + substitute( + simplify(poly(eˣ) ⊛ poly(eʸ); expand=true), + Dict([c⁻¹↑n => 0 for n ∈ NMax:(2NMax ⊕ 3)]), + ); + expand=true, + ) + Δ = simplify(polyprod ⊖ prodpoly; expand=true) + @test iszero(Δ) + @test_throws ArgumentError eˣ * PNExpansion(tuple(z, x...), NMax ⊕ 1) + @test_throws ArgumentError PNExpansion(tuple(z, x...), NMax ⊕ 1) * eˣ + end + end + end end diff --git a/src/core/PNTerm.jl b/src/core/PNTerm.jl new file mode 100644 index 00000000..e5b5ad5a --- /dev/null +++ b/src/core/PNTerm.jl @@ -0,0 +1,309 @@ +# We enclose all of this in a `baremodule` so that we can isolate Base operations, and use +# PNBase operations by default. +baremodule PNTerms + +# See explanation in `PNBase.jl` for why we use these operators. +using Base: Base, @doc, @assert, one, zero, >, ÷, + as ⊕, - as ⊖, * as ⊛, / as ⊘, ^ as ↑ + +import PostNewtonian: constant_convert +using PostNewtonian: PostNewtonian, PNSystem +using PostNewtonian.InlineExports: @export +using PostNewtonian.PNBase + + +""" + PNTerm{T,PNOrder,c⁻¹Exponent} + +This object represents a single term in a PNExpansion. It has a single field: `coeff`, +which is the coefficient of the term. The type parameter `T` is the type of the +coefficient. The type parameter `PNOrder` is a half-integer (just as in +[`PNSystem`](@ref)s) representing the PN order of the expansion. And the type parameter +`c⁻¹Exponent` is an integer representing the exponent of the PN expansion parameter ``1/c``. + +`PNTerm`s can be multiplied and divided by scalars and exponentiated by integers, to produce +another `PNTerm`. They can also be added to other `PNTerm`s to produce a `PNExpansion`. + +A simple way to define a `PNTerm` or a `PNExpansion` is to define the PN expansion parameter +```julia +c = PNExpansionParameter(pnsystem) +``` +and use that naturally in formulas, as in +```julia +e = 1 + (v/c)^2 * (-ν/12 - 3//4) + (v/c)^4 * (-ν^2/24 + 19ν/8 - 27//8) +``` +Any exponent higher than the desired `PNOrder` will be automatically set to zero. + +Useful facts: + - `v` has order `1/c` + - `x` has order `1/c^2` + - `γ` has order `1/c^2` + - `1/r` has order `1/c^2` + +""" +@export struct PNTerm{T,PNOrder,c⁻¹Exponent} + coeff::T + + function PNTerm{T,PNOrder,c⁻¹Exponent}(coeff) where {T,PNOrder,c⁻¹Exponent} + if c⁻¹Exponent > 2 ⊛ PNOrder + coeff = zero(coeff) + end + return new{T,PNOrder,c⁻¹Exponent}(coeff) + end + function PNTerm{T,PNOrder}(c⁻¹exp::Int, coeff) where {T,PNOrder} + if c⁻¹exp > 2 ⊛ PNOrder + coeff = zero(coeff) + end + return new{T,PNOrder,c⁻¹exp}(coeff) + end +end + +""" + PNExpansionParameter(pnsystem) + +Create a [`PNTerm`](@ref) object representing the post-Newtonian expansion parameter ``c``. +This can be used to automatically create more complicated `PNTerm`s, which combine to form a +[`PNExpansion`](@ref). This is a simple but effective way to write PN formulas while +automatically tracking the PN order of each term. +""" +@export function PNExpansionParameter(::T) where {NT,PNOrder,T<:PNSystem{NT,PNOrder}} + return PNTerm{NT,PNOrder}(-1, one(T)) +end + +Base.length(pn::PNTerm) = 1 # COV_EXCL_LINE (Covered, but missed due to const-folding) +Base.eltype(pn::PNTerm{T}) where {T} = T + +@export c⁻¹exp(pn::PNTerm{T,PNOrder,c⁻¹Exponent}) where {T,PNOrder,c⁻¹Exponent} = + c⁻¹Exponent + +function PostNewtonian.constant_convert( + pn::P, term::T +) where {NT,PNOrder,P<:PNSystem{NT,PNOrder},T<:PNTerm{NT,PNOrder}} + term +end + +### NOTE: Adding or subtracting multiple `PNTerm`s will produce a `PNExpansion`, which +### is defined in `PNExpansion.jl`. The following additive functions are just unary. + +function Base.sum(term::PNTerm) + return term.coeff +end + +function PNBase.:+(term::PNTerm) + return term +end + +function PNBase.:-(term::PNTerm{T,PNOrder,c⁻¹Exponent}) where {T,PNOrder,c⁻¹Exponent} + return PNTerm{T,PNOrder,c⁻¹Exponent}(⊖(term.coeff)) +end + +function Base.inv(term::PNTerm{T,PNOrder,c⁻¹Exponent}) where {T,PNOrder,c⁻¹Exponent} + return PNTerm{T,PNOrder}(⊖(c⁻¹Exponent), Base.inv(term.coeff)) +end + +function PNBase.:√(term::PNTerm{T,PNOrder,c⁻¹Exponent}) where {T,PNOrder,c⁻¹Exponent} + @assert Base.iseven(c⁻¹Exponent) "Only half-integer PN orders are supported." + return PNTerm{T,PNOrder}(c⁻¹Exponent ÷ 2, Base.sqrt(term.coeff)) +end + +function PNBase.:^( + term::PNTerm{T,PNOrder,c⁻¹Exponent}, n::Int +) where {T,PNOrder,c⁻¹Exponent} + coeff = term.coeff↑n + return PNTerm{typeof(coeff),PNOrder}(c⁻¹exp(term) ⊛ n, coeff) +end + +function PNBase.:*( + term1::PNTerm{T1,PNOrder,c⁻¹E1}, term2::PNTerm{T2,PNOrder,c⁻¹E2} +) where {T1,T2,PNOrder,c⁻¹E1,c⁻¹E2} + c⁻¹Exponent = c⁻¹exp(term1) ⊕ c⁻¹exp(term2) + coeff = term1.coeff ⊛ term2.coeff + return PNTerm{typeof(coeff),PNOrder,c⁻¹Exponent}(coeff) +end + +function PNBase.:*( + x::Number, term::PNTerm{T,PNOrder,c⁻¹Exponent} +) where {T,PNOrder,c⁻¹Exponent} + coeff = x ⊛ term.coeff + return PNTerm{typeof(coeff),PNOrder,c⁻¹Exponent}(coeff) +end + +PNBase.:*(term::PNTerm, x::Number) = PNBase.:*(x, term) + +function PNBase.:/( + term1::PNTerm{T1,PNOrder,c⁻¹E1}, term2::PNTerm{T2,PNOrder,c⁻¹E2} +) where {T1,T2,PNOrder,c⁻¹E1,c⁻¹E2} + c⁻¹Exponent = c⁻¹E1 ⊖ c⁻¹E2 + coeff = term1.coeff ⊘ term2.coeff + return PNTerm{typeof(coeff),PNOrder,c⁻¹Exponent}(coeff) +end + +function PNBase.:/( + term::PNTerm{T,PNOrder,c⁻¹Exponent}, x::Number +) where {T,PNOrder,c⁻¹Exponent} + coeff = term.coeff ⊘ x + return PNTerm{typeof(coeff),PNOrder,c⁻¹Exponent}(coeff) +end + +function PNBase.:/( + x::Number, term::PNTerm{T,PNOrder,c⁻¹Exponent} +) where {T,PNOrder,c⁻¹Exponent} + coeff = x ⊘ term.coeff + return PNTerm{typeof(coeff),PNOrder}(⊖(c⁻¹exp(term)), coeff) +end + +end # baremodule PNTerms + +@testitem "PNTerm algebra" begin + using Base: Base, one, zero, <, ÷, + as ⊕, - as ⊖, * as ⊛, / as ⊘, ^ as ↑ + using DoubleFloats: Double64 + using PostNewtonian: PostNewtonian, pn_order + using PostNewtonian.PNBase: ln, (√), (+), (-), (*), (/), (//), (^) + using PostNewtonian.PNTerms: PNTerm, PNExpansionParameter, c⁻¹exp, PNBase, constant_convert + using PostNewtonian.PNExpansions: PNExpansion + + for T ∈ [Float64, Float16, Double64] + pn = BBH(randn(T, 14), 9//2) + pn[:v] = /(pn, 1, 5) + c = PNExpansionParameter(pn) + z = zero(T) + x = /(pn, 6, 5) + y = /(pn, 17, 5) + w = /(pn, 28, 5) + v = /(pn, 27, 13) + + # Test behavior of `c` as the basic PNTerm + for (term, c⁻¹exponent, coeff) ∈ ( + (c, -1, 1), + (c^2, -2, 1), + (x * c^2, -2, x), + (c^2 * x, -2, x), + (c^2 / x, -2, 1 / x), + ((x * c)^2, -2, x^2), + ((x * c^2) / c^4, 2, x), + ((x * c^2) / c^-4, -6, x), + ((x / c^2) / c^4, 6, x), + ((x / c^2) * (y / c^4), 6, x * y), + ) + @test c⁻¹exp(term) == c⁻¹exponent + @test term.coeff == coeff + @test term.coeff isa eltype(pn) + @test length(term) == 1 + @test eltype(term) ≡ T + end + + # Test PNExpressions + @test_throws ArgumentError PNExpansion((), 0) + for (expr, expected) ∈ ( + (w - (x - y / c), (w - x, y)), + (w - (x / c - y), (w + y, -x)), + (x - y / c, (x, -y)), + (x / c - y, (-y, x)), + (x / c^6 + y / c, (z, y, z, z, z, z, x)), + (x / c^6 + y / c + w / c^10, (z, y, z, z, z, z, x, z, z, z)), + (x / c^6 - y / c, (z, -y, z, z, z, z, x)), + (x / c^6 - y / c - w, (-w, -y, z, z, z, z, x)), + (x / c^6 - y / c - w / c^10, (z, -y, z, z, z, z, x, z, z, z)), + (x / c^6 - (y / c - w), (w, -y, z, z, z, z, x)), + (x / c^6 - (y / c - w / c^10), (z, -y, z, z, z, z, x, z, z, z)), + (-(x / c^6) - y / c, (z, -y, z, z, z, z, -x)), + (-(x / c^6) - y / c - w, (-w, -y, z, z, z, z, -x)), + (-(x / c^6) - y / c - w / c^10, (z, -y, z, z, z, z, -x, z, z, z)), + ((x * c^2) / c^4 + y / c, (z, y, x)), + ((x * c^2) / c^4 + y / c + w, (w, y, x)), + ((x * c^2) / c^9 + y / c + w, (w, y, z, z, z, z, z, x)), + (w + (x * c^2) / c^4 + y / c, (w, y, x)), + (w + (x * c^2) / c^9 + y / c, (w, y, z, z, z, z, z, x)), + (w + ((x * c^2) / c^4 + y / c), (w, y, x)), + (w + ((x * c^2) / c^9 + y / c), (w, y, z, z, z, z, z, x)), + (((x * c^2) / c^4 + y / c + w) / c^3, (z, z, z, w, y, x)), + (((x * c^2) / c^4 + y / c + w) / c^5, (z, z, z, z, z, w, y, x)), + (((x * c^2) / c^7 + y / c + w) / c^5, (z, z, z, z, z, w, y, z, z, z)), + (v * (((x * c^2) / c^4 + y / c + w) / c^3), v .* (z, z, z, w, y, x)), + ((((x * c^2) / c^4 + y / c + w) / c^3) * v, v .* (z, z, z, w, y, x)), + ((((x * c^2) / c^4 + y / c + w) / c^3) / v, (z, z, z, w, y, x) .* (1 / v)), + ) + @test expr.coeffs == expected + @test pn_order(expr) == pn_order(pn) + @test sum(expr) == sum(expected) + @test eltype(expr) ≡ T + end + + # Can't make a PNExpression with positive exponents + @test_throws ArgumentError x * c + y + @test_throws ArgumentError x * c + y / c + @test_throws ArgumentError x * c^2 + y + @test_throws ArgumentError x * c^2 + y / c + @test_throws ArgumentError y + x * c + @test_throws ArgumentError y / c + x * c + @test_throws ArgumentError y + x * c^2 + @test_throws ArgumentError y / c + x * c^2 + @test_throws ArgumentError x * c^2 + (y / c + z / c^2) + end + + pn = BBH(randn(14), 2//1) + + # constant_convert should just return the term + t0 = PNTerm{Float64,2//1}(0, 5.0) + @test constant_convert(pn, t0) ≡ t0 + + # Base.sum + @test sum(t0) == 5.0 + + # unary + (PNBase.+) + t1 = PNTerm{Float64,2}(1, 2.5) + @test +t1 ≡ t1 + + # unary - (PNBase.-) + t1n = -t1 + @test c⁻¹exp(t1n) == c⁻¹exp(t1) + @test t1n.coeff == -2.5 + + # inv + ti = inv(t1) + @test c⁻¹exp(ti) == -c⁻¹exp(t1) + @test ti.coeff == 1/2.5 + + # sqrt on even exponent + t2 = PNTerm{Float64,2}(2, 4.0) + ts = √(t2) + @test c⁻¹exp(ts) == 1 + @test ts.coeff == 2.0 + + # sqrt on odd exponent should error + t3 = PNTerm{Float64,2}(1, 9.0) + @test_throws AssertionError √(t3) + + # power + tp = t1 ^ 3 + @test c⁻¹exp(tp) == 3*c⁻¹exp(t1) + @test tp.coeff == 2.5^3 + + # multiply term * term + ta = PNTerm{Float64,2}(1, 2.0) + tb = PNTerm{Float64,2}(2, 3.0) + tab = ta * tb + @test c⁻¹exp(tab) == 3 + @test tab.coeff == 6.0 + + # scalar * term and term * scalar + ts1 = 4.0 * ta + ts2 = ta * 4.0 + @test c⁻¹exp(ts1) == c⁻¹exp(ta) + @test ts1.coeff == 8.0 + @test ts2.coeff == 8.0 + + # term / term + td = tb / ta + @test c⁻¹exp(td) == 1 # 2 - 1 + @test td.coeff == 1.5 + + # term / scalar + td1 = tb / 2.0 + @test c⁻¹exp(td1) == c⁻¹exp(tb) + @test td1.coeff == 1.5 + + # scalar / term + td2 = 12.0 / ta + @test c⁻¹exp(td2) == -1 # -c⁻¹exp(ta) + @test td2.coeff == 6.0 +end diff --git a/src/core/core.jl b/src/core/core.jl new file mode 100644 index 00000000..134df618 --- /dev/null +++ b/src/core/core.jl @@ -0,0 +1,20 @@ +# This directory provides the core functionality for the post-Newtonian framework — things +# that we will use to build out the rest of the code. As such, it is full of little coding +# details that are important for understanding the detailed structure of the code, but not +# for understanding the physics that code is representing. + +# These are low-level utilities. +include("utilities/misc.jl") +include("utilities/truncated_series_monoid.jl") +include("utilities/truncated_series_inversion.jl") + +# These are types and modules that help to build the post-Newtonian framework. +include("PNBase.jl") +include("PNTerm.jl") +include("PNExpansion.jl") +import PostNewtonian.PNTerms: PNExpansionParameter + +# These macros effectively form the interface used directly in the rest of the code. +include("pn_expansion.jl") +include("pn_expression.jl") +include("pn_reference.jl") diff --git a/src/core/pn_expansion.jl b/src/core/pn_expansion.jl new file mode 100644 index 00000000..8ebb2c7b --- /dev/null +++ b/src/core/pn_expansion.jl @@ -0,0 +1,133 @@ +@doc raw""" + @pn_expansion pnsystem expansion + +Mark `expansion` as a post-Newtonian expansion, to be truncated at the order given by the +`pnsystem`. + +!!! warning + + The symbols `c`, `x`, `γₚₙ`, and `γ` are all considered to be PN-expansion terms inside + the expression passed to this macro. If present inside the expression, this macro will + multiply each by the appropriate power of + [`PNExpansionParameter(pnsystem)`](@ref PNExpansionParameter) to ensure that the + expansion is truncated correctly. + +Note that we generally interpret this PN order as a *relative* PN order. For example, the +expression for [gravitational-wave energy flux](@ref 𝓕) looks like +```math +\mathcal{F} = \frac{32c^5}{5G} \nu^2 \left(\frac{v}{c}\right)^{10} +\left[1 - \left(\frac{ν}{12} + \frac{3}{4}\right) \left(\frac{v}{c}\right)^2 + \ldots\right] +``` +Here, the part in square brackets is the expansion in terms of *relative* PN order, with the +1 representing the relative 0-pN term, the ``(v/c)^2`` term being the relative 1-pN term, +etc. So in the code, we apply `@pn_expansion` to the part in square brackets: +```julia +32c^5 / 5G * ν^2 * (v / c)^10 * @pn_expansion(1 - (ν/12 + 3/4) * (v/c)^2 + ...) +``` +Note that the entire expression is written inside a function that is modified by the +[`@pn_expression`](@ref) macro, which automatically inserts the `pnsystem` argument to this +`@pn_expansion` call, so you generally should not have to worry about it. + +This macro gathers terms in `expansion` by the powers of ``1/c`` involved, zeroing out any +terms with powers of ``1/c`` higher than (twice) the `pnsystem`'s `PNOrder` parameter, and +combine the terms using the `PNExpansionReducer` specified in argument of the function that +includes this macro call. + +The expansion and truncation are achieved by multiplying `c` by a +[`PNExpansionParameter(pnsystem)`](@ref PNExpansionParameter), which is just a +[`PNTerm`](@ref) with a coefficient of 1 and a `c⁻¹Exponent` of -1. This redefinition +happens inside a `let` block created by this macro so that it doesn't interfere with any +`c`s on the outside. For example, in the flux expression above, the `c`s in `32c^5 / 5G * +ν^2 * (v / c)^10` are outside the scope of the macro, so even if we set `c=2` above that +line the expansion will still be correctly truncated, and the value of `c` will be +preserved. + +In the literature, some PN expansions do not *explicitly* use the `c` parameter, but instead +define the expansion in terms of the dimensionless parameters [`x`](@ref) or [`γₚₙ`](@ref), +which include powers of `c` in their definitions. Thus, if these symbols are present inside +the expression passed to this macro, they will be multiplied by the appropriate power of +`PNExpansionParameter`. The literature simply uses `γ`, rather than the more explicit `γₚₙ` +we use here, so `γ` will be treated the same as `γₚₙ`. + +Euler's constant — sometimes called the Euler–Mascheroni constant, and distinct from Euler's +*number* ``e`` — is usually denoted by `γ` (including in Julia's own `Base.MathConstants`), +but is distinguished in the post-Newtonian literature by the subscript "E", and is defined +in this package as [`γₑ`](@ref). + +!!! note + + Because `x` and `γₚₙ` are "of order" ``1/c^2``, their exponents are generally + half-integers in any expansion. Evaluating a term like `x^(7/2)` generically will be + relatively inefficient, requiring a floating-point division, the logarithm of `x`, a + floating-point multiplication, and exponentiation. Compared to a single square-root and + integer exponentiation, this is slow. Moreover, it does not work well with the + [`PNTerm`](@ref) mechanism. So another thing this macro does is search for terms like + `x^(7/2)` and convert them to `(√x)^7`, and similarly for `γₚₙ` and `γ`. This only + works for explicit half-integers, rather than variables that may be half-integers. +""" +@public macro pn_expansion(pnsystem, expr) + expansion_parameters = Expr[] + if MacroTools.inexpr(expr, :c) + push!(expansion_parameters, :(c = c * PNExpansionParameter($pnsystem))) + end + if MacroTools.inexpr(expr, :x) + push!(expansion_parameters, :(x = x / PNExpansionParameter($pnsystem)^2)) + expr = MacroTools.postwalk(expr) do ex + MacroTools.@capture(ex, x^(n_Int/2)) || return ex + return :((√x)^$n) + end + end + if MacroTools.inexpr(expr, :γₚₙ) + push!(expansion_parameters, :(γₚₙ = γₚₙ / PNExpansionParameter($pnsystem)^2)) + expr = MacroTools.postwalk(expr) do ex + MacroTools.@capture(ex, γₚₙ^(n_Int/2)) || return ex + return :((√γₚₙ)^$n) + end + end + if MacroTools.inexpr(expr, :γ) + push!(expansion_parameters, :(γ = γ / PNExpansionParameter($pnsystem)^2)) + expr = MacroTools.postwalk(expr) do ex + MacroTools.@capture(ex, γ^(n_Int/2)) || return ex + return :((√γ)^$n) + end + end + if isempty(expansion_parameters) + error("No expansion parameters found in `@pn_expansion`.") + end + return esc(MacroTools.unblock(quote + let $(expansion_parameters...) + PNExpansionReducer($expr) + end + end)) +end + +@testitem "@pn_expansion" begin + using PostNewtonian: @pn_expansion + using MacroTools + + input = @macroexpand @pn_expansion pnsystem ( + 1 - (ν/12 + 3/4) * (v/c)^2 + 4x^3 + 5x^(7/2) + ) + output = MacroTools.unblock( + quote + let c = c * PNExpansionParameter(pnsystem), + x = x / PNExpansionParameter(pnsystem)^2 + + PNExpansionReducer(1 - (ν/12 + 3/4) * (v/c)^2 + 4x^3 + 5(√x)^7) + end + end, + ) + @test MacroTools.striplines(input) == MacroTools.striplines(output) + + input = @macroexpand @pn_expansion pnsystem (1 - (ν/12 + 3/4)γ + 4γₚₙ^3 + 5γₚₙ^(7/2)) + output = MacroTools.unblock( + quote + let γₚₙ = γₚₙ / PNExpansionParameter(pnsystem)^2, + γ = γ / PNExpansionParameter(pnsystem)^2 + + PNExpansionReducer(1 - (ν/12 + 3/4)γ + 4γₚₙ^3 + 5(√γₚₙ)^7) + end + end, + ) + @test MacroTools.striplines(input) == MacroTools.striplines(output) +end diff --git a/src/core/pn_expression.jl b/src/core/pn_expression.jl new file mode 100644 index 00000000..02221265 --- /dev/null +++ b/src/core/pn_expression.jl @@ -0,0 +1,316 @@ +""" + @pn_expression [arg_index=1] func + +This macro makes it easier to define post-Newtonian expressions. + +The optional first argument to this macro is `arg_index`, which just tells us which argument +to the function `func` is a `PNSystem` — defaulting to the first argument. For example, the +variables defined in [`PostNewtonian.FundamentalVariables`](@ref "Fundamental variables") +all take a single argument of `pnsystem`, which is used to compute the values for those +variables; this macro just needs to know where to find `pnsystem`. + +The required argument to this macro is a function the will compute some values related to +the `pnsystem`. + +Once it has this information, there are three types of transformations the macro will make: + + 1. If either `PNExpansionReducer` or `@pn_expansion` is used in the expression, this adds a + keyword argument `pn_expansion_reducer::Val{PNExpansionReducer}=Val(sum)` to the + function signature. This is used to determine how to reduce the PN expansion terms. + The default is `Val(sum)`, which will just return a single number, but `Val(identity)` + can be used to return the expansion. The reducing function can be used inside the main + function as `PNExpansionReducer`, and will be automatically used inside any + `@pn_expansion`. + 2. For every function defined in the module where this macro is called that takes a single + `PNSystem` argument, this macro will look for the name of that function inside the + expression. If it finds any such names, it will replace them with the corresponding + calls to the function with `pnsystem` as the argument. For example, you can simply use + the symbols `M₁` or `μ` in your code, rather than calling them as [`M₁(pnsystem)`](@ref + M₁) or [`μ(pnsystem)`](@ref μ) every time they appear. To be more explicit, this is + achieved by defining the relevant quantities in a `let` block placed around the body of + `func`, so that the values may be used efficiently without recomputation. If you need + to use one of those functions with different arguments, you'll need to address them + explicitly with the module name — as in `PostNewtonian.v(;Ω, M)`. + 3. Insert the `pnsystem` argument as the first argument to each occurrence of + `@pn_expansion` that needs it. + +For example, we might write a function like this: +```julia +@pn_expression function f(pnsystem) + 5μ/c^2 * @pn_expansion(1 + 4(v/c)^2) +end +``` +That is effectively rewritten by this macro as +```julia +function f(pnsystem, ::Val{PNExpansionReducer}=Val(sum)) where {PNExpansionReducer} + let μ=μ(pnsystem), c=c(pnsystem), v=v(pnsystem) + 5μ/c^2 * @pn_expansion pnsystem (1 + 4(v/c)^2) + end +end +``` +The [`@pn_expansion`](@ref) macro is further expanded so that the final result looks like +```julia +function f(pnsystem, ::Val{PNExpansionReducer}=Val(sum)) where {PNExpansionReducer} + let μ=μ(pnsystem), c=c(pnsystem), v=v(pnsystem) + 5μ/c^2 * ( + let c=PNExpansionParameter(pnsystem) + PNExpansionReducer(1 + 4(v/c)^2) + end + ) + end +end +``` +Moreover, this expression should itself be defined within an [`@pn_reference`](@ref) module, +which preserves the precision of the `pnsystem`, so that we can define `pnsystem` with, +e.g., `Float16` or `BigFloat` numbers, and natural expressions like `2π` or `4/3` won't +automatically be converted to `Float64` and spoil the requested precision. +""" +@public macro pn_expression(arg_index, func=:(nothing)) + # Note that macros secretly get two extra variables: `__module__` and `__source__`. + # These refer to the place where the macro was called. The second is useful for + # debugging, but the first is crucial here, because it lets us see what's defined in the + # module in which this macro was used. + + # First, we just search for everything defined in the module where this macro is called. + all_names = if VERSION < v"1.12.0-beta1" + # See the warning in `@pn_reference` for why we should avoid `using` on Julia <1.12 + names(__module__; all=true, imported=true) + else + names(__module__; all=true, imported=true, usings=true) + end + + # Next, we narrow that list down to callable objects defined in the `__module__` where + # this macro was used. Specifically, we filter for those objects that take one + # `PNSystem`, and nothing else, as an argument. These will be valid targets for + # replacement in the body that `@pn_expression` is applied to. + pnsystem_functions = filter( + function (name) + if isdefined(__module__, name) + f = getfield(__module__, name) + if isa(f, Base.Callable) + if !isempty(methods(f, Tuple{PNSystem})) + return true + end + end + end + return false + end, all_names + ) + + # Now, we pass that information along to the function that actually modifies our code + return esc(pn_expression(arg_index, func, pnsystem_functions, __module__, __source__)) +end + +function pn_expression(arg_index, func, pnsystem_functions, __module__, __source__) + # Handle the default argument + if func ≡ :(nothing) + arg_index, func = 1, arg_index + end + + # Check to make sure that `arg_index` is an integer; we'll check that it's valid below. + if !isa(arg_index, Integer) + error( + "The optional argument to `@pn_expression` must be an integer, not " * + "$(typeof(arg_index))\nThe incorrect application is at $(__source__).", + ) + end + + # Check to make sure that `func` is a function-definition expression + if !MacroTools.isdef(func) + error( + "The `@pn_expression` macro can only be applied to function definitions.\n" * + "The incorrect application is at $(__source__).", + ) + end + + # MacroTools has this nice function to parse function definitions so we can operate on + # each piece separately. + splitfunc = MacroTools.splitdef(func) + + # Check that the argument index is valid + if arg_index < 1 || arg_index > length(splitfunc[:args]) + error( + "Invalid argument index $arg_index for function $(splitfunc[:name]); " * + "it must be between 1 and $(length(splitfunc[:args]))\n" * + "The incorrect application is at $(__source__).", + ) + end + + # Get the name of the PNSystem argument + pnsystem = MacroTools.namify(splitfunc[:args][arg_index]) + + # Add `pnsystem` as the argument to each @pn_expansion call... + new_body = MacroTools.postwalk(splitfunc[:body]) do x + if MacroTools.isexpr(x, :macrocall) && + x.args[1] == Symbol("@pn_expansion") && + !isa(x.args[end - 1], Symbol) # ...unless there's already one there + x′ = deepcopy(x) + insert!(x′.args, length(x′.args), pnsystem) + x′ + else + x + end + end + + # Expand all the macros inside the body + new_body = macroexpand(__module__, new_body; recursive=true) + + # If `PNExpansionReducer` is or will be in the body of the function, we need to make + # sure it is included in the function signature. + if MacroTools.inexpr(new_body, :(@pn_expansion)) || + MacroTools.inexpr(new_body, :(PNExpansionReducer)) + + # Just so we don't accidentally add it twice, make sure it's not already in the + # function signature. + if !any(MacroTools.inexpr.(splitfunc[:kwargs], :(PNExpansionReducer))) + # Append a keyword argument `pn_expansion_reducer` to the function signature, + # with default value `Val(sum)`. The `Val` parameter is captured as + # `PNExpansionReducer`, which we can then use in the body of the function — + # specifically, it is automatically used by the `@pn_expansion` macro. + splitfunc[:kwargs] = [ + splitfunc[:kwargs] + :( + $(Expr( + :kw, + :(pn_expansion_reducer::Val{PNExpansionReducer}), + :(Val(Base.sum)), + )) + ) + ] + + # Add `PNExpansionReducer` to the `where` clause + splitfunc[:whereparams] = (splitfunc[:whereparams]..., :PNExpansionReducer) + end + end + + # Look for any of the `pnsystem_functions` in the body of the function and prepare an + # entry for the `let` block that will surround the body on output. + pnsystem_function_exprs = [ + :($s = $s($pnsystem)) for + s ∈ filter(s -> MacroTools.inexpr(new_body, s), pnsystem_functions) + ] + + # Walk the expression tree and find all function calls to any of the + # `pnbase_functions`, and insert `pnsystem` as the first argument. + new_body = MacroTools.postwalk(new_body) do x + if iscall(x, pnbase_functions) + insert!(x.args, 2, (pnsystem)) + x + else + x + end + end + + # Include the `let` statements so that the functions can all be used as plain symbols + # without having to call them on `pnsystem`, but we do so without burying it in a code + # block. + new_body = MacroTools.unblock(quote + #@fastmath + let $(pnsystem_function_exprs...) + $(MacroTools.unblock(new_body)) + end + end) + + # Replace the old body with the new one + splitfunc[:body] = new_body + + # And reassemble the function definition + return MacroTools.combinedef(splitfunc) +end + +@testitem "@pn_expression" begin + using MacroTools + + baremodule Mod + # These are the expressions added by `@pn_reference` + using Base: Base, Val + eval(x::Expr) = Core.eval(Base.@__MODULE__, x) + include(p::AbstractString) = Base.include(Base.@__MODULE__, p) + using PostNewtonian: PostNewtonian, @pn_expression, @pn_expansion, 𝒾, γₑ, ζ3 + using PostNewtonian.PNBase + + # Below are what we would normally write manually + import PostNewtonian: M₁, M₂, χ₁ˣ, χ₁ʸ, χ₁ᶻ, v, Φ + const x = Base.://(7, 2) + f(pnsys::PostNewtonian.PNSystem) = x + @pn_expression function g(pnsy) + f + M₁ + end + @pn_expression h(pns) = f - M₂ + @pn_expression function i(pn) + f * χ₁ˣ * γₑ + end + @pn_expression function j(pnsyst) + f / χ₁ʸ + end + @pn_expression function k(pnsyste) + f ^ χ₁ᶻ + end + @pn_expression function l(pnsystm) + f * ln(v) * ζ3 + end + @pn_expression function m(pnsystem) + √f * Φ + end + + const expr1 = Base.@macroexpand @pn_expression function n(pnsystem) + l * f * ln(v) * ζ3 + m * Φ / c + end + + const expr2 = Base.@macroexpand @pn_expression function n(pnsystem) + @pn_expansion l * f * ln(v) * ζ3 + m * Φ / c + end + + end # baremodule Mod + + import .Mod + + const ln = log + + output1 = :( + function n(pnsystem;) + let f=f(pnsystem), l=l(pnsystem), m=m(pnsystem), v=v(pnsystem), Φ=Φ(pnsystem) + + pnsystem + + pnsystem * l * f * ln(pnsystem, v) * ζ3 + + /(pnsystem, pnsystem * m * Φ, c) + end + end + ) + @test MacroTools.striplines(Mod.expr1) == MacroTools.striplines(output1) + + # Because the `c...` in the `let c...` statement is actually in a block, we have to do + # this little `c2` hack, so our explicit version resembles the generated version. + c2 = [:(c = pnsystem * c * PNExpansionParameter(pnsystem))] + output2 = :( + function n( + pnsystem; pn_expansion_reducer::Val{PNExpansionReducer}=Val(Base.sum) + ) where {PNExpansionReducer} + let f=f(pnsystem), l=l(pnsystem), m=m(pnsystem), v=v(pnsystem), Φ=Φ(pnsystem) + + let $(c2...) + PNExpansionReducer( + pnsystem + + pnsystem * l * f * ln(pnsystem, v) * ζ3 + + /(pnsystem, pnsystem * m * Φ, c), + ) + end + end + end + ) + @test MacroTools.striplines(Mod.expr2) == MacroTools.striplines(output2) + + for NT ∈ (Float16, Float64, BigFloat) + pnsystem = BHNS(NT.(1:15)) + for v ∈ (:g, :h, :i, :j, :k, :l, :m) + @test eval(:(Mod.$v))(pnsystem) isa NT + end + @test Mod.g(pnsystem) == NT(7//2) + pnsystem[:M₁] + @test Mod.h(pnsystem) == NT(7//2) - pnsystem[:M₂] + @test Mod.i(pnsystem) == NT(7//2) * pnsystem[:χ₁ˣ] * PostNewtonian.γₑ + @test Mod.j(pnsystem) == NT(7//2) / pnsystem[:χ₁ʸ] + @test Mod.k(pnsystem) == NT(7//2) ^ pnsystem[:χ₁ᶻ] + @test Mod.l(pnsystem) == NT(7//2) * log(pnsystem[:v]) * PostNewtonian.ζ3 + @test Mod.m(pnsystem) == √(NT(7//2)) * pnsystem[:Φ] + end +end diff --git a/src/core/pn_reference.jl b/src/core/pn_reference.jl new file mode 100644 index 00000000..a2ec6598 --- /dev/null +++ b/src/core/pn_reference.jl @@ -0,0 +1,195 @@ +""" +This file defines the `@pn_reference` macro, which is used to create a module for a specific +Post-Newtonian reference. Its purpose is to *un*define even the most basic operations, such +as addition, multiplication, and so on, to ensure that all operations are sufficiently +overridden by `@pn_expression`. For example, integer division `1/3` will result in a +`Float64` by default. But `@pn_expression` will extract the number type `NT` of the +`pnsystem` argument, and redefine integer division to return something compatible with `NT` +instead — possibly a `Double64` or `Sympy` expression, for example. + +The [julia docs +say](https://docs.julialang.org/en/v1/manual/modules/#Default-top-level-definitions-and-bare-modules) +that a standard module is essentially this: + +```julia +baremodule Mod + +using Base + +eval(x) = Core.eval(Mod, x) +include(p) = Base.include(Mod, p) + +... + +end +``` +We just want to replace that `using` with `import`. This will ensure that only operations +that are already handled by `@pn_expression` will be defined; if they aren't, there will be +an error. + +Similarly, we want the author to *have to* define every single variable to be used in the PN +expression. In most cases, the variable can just be imported from `common_variables` under +its own name. There may be cases, however, where the name needs to change, or a variable +needs to be defined just in the given module. One prominent example is that some authors +use `η` where we use `ν`. In any case, this will make it easier for `@pn_expression` to +look through the current module for symbols that appear in the expression that need to be +replaced with a call to that function. + +""" + +function pn_reference(expr, __module__, __source__) + # A module `Expr` has head `:module` and three arguments: + # 1. a boolean indicating if this is a module (true) as opposed to a baremodule (false) + # 2. the module name (a `Symbol`) + # 3. the module body (an `Expr` with head `:block`) + if MacroTools.isexpr(expr, :module) + # Check to make sure that this module is structured exactly as expected + if length(expr.args) ≠ 3 + error( + "Found a module expression with $(length(expr.args)) arguments:\n" * + "$(expr)", + ) + end + if ! MacroTools.isexpr(expr.args[1], Bool) + error("Found a module expression with a non-boolean flag: $(expr.args[1])") + end + if ! MacroTools.isexpr(expr.args[2], Symbol, :symbol) + error( + "Found a module expression with a non-symbol name: $(expr.args[2])\n" * + "$(expr)", + ) + end + if ! MacroTools.isexpr(expr.args[3], :block) + error("Found a module expression with a non-block body: $(dump(expr.args[3]))") + end + + # Warn if the module uses `using` on Julia < 1.12 + if VERSION < v"1.12.0-beta1" && any( + arg -> hasproperty(arg, :head) && getproperty(arg, :head) ≡ :using, + expr.args[3].args, + ) + @warn "Prefer `import` inside `@pn_reference` modules on Julia<1.12\n" * + "You are defining a `@pn_reference` module that uses `using` at\n" * + "`$(__source__)`.\n" * + "Due to a limitation in Julia 1.11 and earlier, you must use `import`\n" * + "rather than `using` to import function names that you want to use in a\n" * + "`@pn_expression`." + end + + # Now, we assemble the new module, mostly by prepending some imports to the contents + module_name = expr.args[2] + module_body = expr.args[3].args + public = VERSION ≥ v"1.11.0-beta1" ? Expr(:public, module_name) : :() + new_module = quote + $public + Base.@__doc__ baremodule $(module_name) + using Base: Base, Val, π, @raw_str, @doc + eval(x::Expr) = Core.eval($(module_name), x) + include(p::AbstractString) = Base.include($(module_name), p) + using PostNewtonian: + @pn_expression, @pn_expansion, PNExpansionParameter, 𝒾, γₑ, ζ3 + using PostNewtonian.PNBase + $(module_body...) + end + end + + # Finally, we return this as a `:toplevel` expression, to ensure that it is + # not buried in some block that causes an error. + return Expr(:toplevel, new_module) + else + error("@pn_reference can only be used with module expressions, not `$expr`") + end +end + +""" + @pn_reference + +Create a module for a specific Post-Newtonian reference. + +!!! warning + + Due to limitations of Julia versions less than 1.12, you *must* use `import` instead of + `using` to import variables inside the module created by `@pn_reference`, or they won't + be available to `@pn_expression`. + +The purposes of this macro are: + + 1. To isolate the code for each reference, allowing for different notations such as + `η` or `ν` for the reduced mass ratio, or for subtly different definitions of + fundamental quantities like spin. + 2. To require that all functions and variables used in the expressions defined in the + module are explicitly imported or defined, to minimize the chance of accidentally + using incorrect definitions. + 3. To preserve precision relevant to the number type of the input `PNSystem` + by redefining basic operations such as addition, multiplication, and so on. + +Different sources in the literature may use different notations for the same variables, so +enclosing definitions related to a particular reference in a module allows us to use the +appropriate notation within that module while still interfacing with this package and its +conventions outside of the module. For example, some authors use `η` to denote the +symmetric mass ratio whereas this package uses `ν`. We can import this with `using +..PostNewtonian: ν as η` inside the module, and then use `η` in the expressions defined +inside that module, to resemble the reference. But when any expression using `η` is called +from outside the module, the choice of variable used inside that expression will not affect +the result. + +This macro transforms the module to which it is applied, so that unlike a normal module that +effectively includes `using Base` — which allows access to such basic operations as +addition, multiplication, and so on — it instead includes `import Base`. It also includes +`using PostNewtonian: @pn_expression, @pn_expansion`, the first of which redefines the basic +operations — at least those used in post-Newtonian expressions — to account for the number +type relevant to the input `PNSystem`. By not importing the basic operations from `Base`, +we ensure that only those redefined by `@pn_expression` are available in the module, which +ensures that they preserve the number type. If any are missing, `@pn_expression` should be +extended. + +""" +@public macro pn_reference(ex) + esc(pn_reference(ex, __module__, __source__)) +end + +@testitem "@pn_reference" begin + using MacroTools: MacroTools + using PostNewtonian: @pn_reference + + input = @macroexpand @pn_reference module Einstein1918 + import PostNewtonian: G, c, M, χ⃗₁, χ⃗₂, v, pn_order + import Quaternionic: absvec + @pn_expression χ₁(pnsystem) = absvec(χ⃗₁) + @pn_expression χ₂(pnsystem) = absvec(χ⃗₂) + const x = 3 + module InnerMod + const z = 4 + end + import .InnerMod: z + @pn_expression function y(pnsystem) + G*M/c^3 * @pn_expansion(x + χ₁ + χ₂ + z*(v/c)) + end + end + + output = quote + baremodule Einstein1918 + using Base: Base, Val, π, @raw_str, @doc + eval(x::Expr) = Core.eval(Einstein1918, x) + include(p::AbstractString) = Base.include(Einstein1918, p) + using PostNewtonian: @pn_expression, @pn_expansion, PNExpansionParameter, 𝒾, γₑ, ζ3 + using PostNewtonian.PNBase + + import PostNewtonian: G, c, M, χ⃗₁, χ⃗₂, v, pn_order + import Quaternionic: absvec + @pn_expression χ₁(pnsystem) = absvec(χ⃗₁) + @pn_expression χ₂(pnsystem) = absvec(χ⃗₂) + const x = 3 + module InnerMod + const z = 4 + end + import .InnerMod: z + @pn_expression function y(pnsystem) + G*M/c^3 * @pn_expansion(x + χ₁ + χ₂ + z*(v/c)) + end + end + end + + @test MacroTools.striplines(input).args[1].args[2].args[2] == + MacroTools.striplines(output).args[1] +end diff --git a/src/core/utilities/InlineExports.jl b/src/core/utilities/InlineExports.jl new file mode 100644 index 00000000..7ce6408e --- /dev/null +++ b/src/core/utilities/InlineExports.jl @@ -0,0 +1,304 @@ +# NOTE: This file borrows from the `InlineExports.jl` package, which is licensed under the +# MIT License. The original source can be found at https://github.com/dalum/InlineExports.jl + +module NoExport + +import Base: @__doc__ + +export @export, @public + +eval(quote + """ + @export + + No-op. Used to disable inline exports. + """ + macro $(Symbol("export"))(expr::Expr) + return esc(expr) + end +end) + +""" + @public + +No-op. Used to disable inline public macro. +""" +macro public(expr::Expr) + return esc(expr) +end + +end # module NoExport + +module InlineExports + +import Base: @__doc__ + +export @export, @public + +eval(quote + """ + @export + + Return the expression with all bindings exported. + + ``` + julia> module M + using InlineExports + @export begin + const a = 2 + abstract type S <: Number end + struct T <: S + val + end + end + @export f(x::TT) where {TT<:S} = x.val^2 + end + M + + julia> using .M + + julia> f(T(a)) + 4 + ``` + """ + macro $(Symbol("export"))(expr::Expr) + return handle(expr, :export) + end +end) + +@static if VERSION < v"1.11" + using ..NoExport: @public +else + """ + @public + + Return the expression with all bindings marked as public. + + ``` + julia> module M + using InlineExports + @public begin + const a = 2 + abstract type S <: Number end + struct T <: S + val + end + end + @public f(x::TT) where {TT<:S} = x.val^2 + end + M + + julia> using .M + + julia> M.f(M.T(M.a)) + 4 + ``` + """ + macro public(expr::Expr) + return handle(expr, :public) + end +end + +function handle(expr::Expr, export_or_public::Symbol) + r = handle(expr) + ep = if r isa Symbol + Expr(export_or_public, r) + else + Expr(export_or_public, r...) + end + # COV_EXCL_START + return esc(quote + $ep + Base.@__doc__ $expr + end) + # COV_EXCL_END +end + +handle(::Any) = nothing +handle(x::Symbol) = x +handle(expr::Expr) = handle(Val(expr.head), expr) + +handle(::Val{:block}, expr) = filter(x -> x !== nothing, map(handle, expr.args)) +handle(::Val{:const}, expr) = handle(expr.args[1]) +handle(::Val{:(::)}, expr) = handle(expr.args[1]) +handle(::Val{:(=)}, expr) = handle(expr.args[1]) +handle(::Val{:function}, expr) = handle(expr.args[1]) +handle(::Val{:where}, expr) = handle(expr.args[1]) +handle(::Val{:macro}, expr) = Symbol("@", handle(expr.args[1])) +handle(::Val{:struct}, expr) = handle(expr.args[2]) +handle(::Union{Val{:abstract},Val{:primitive}}, expr) = handle(expr.args[1]) + +handle(::Val{:<:}, expr) = handle(expr.args[1]) +handle(::Val{:curly}, expr) = handle(expr.args[1]) +handle(::Val{:call}, expr) = handle(expr.args[1]) +function handle(::Val{:macrocall}, expr) + if expr.args[1]==Symbol("@doc") || + (expr.args[1] == Core.GlobalRef(Core, Symbol("@doc"))) + if length(expr.args) != 4 + # COV_EXCL_START + error("@doc expression found with $(length(expr.args)) args:\n$expr") + # COV_EXCL_END + end + handle(expr.args[4]) + else + filter(x -> x !== nothing, map(handle, expr.args[3:end])) + end +end + +end # module InlineExports + +@testitem "InlineExports" begin + using Markdown: @doc_str + + module Bla + using PostNewtonian.InlineExports: @export, @public + + @export macro garble(expr::Expr) + return esc(expr) + end + + @public macro gorble(expr::Expr) + return esc(expr) + end + + @export abstract type Flork{T} end + @public abstract type Flark{T} end + + @export m::Int = 3 + @public n::Int = 4 + + @export @eval :evala + @public @eval :evalb + + @export function funca(x) + x^2 + end + @public function funcb(x) + x^3 + end + + @export begin + "`const a` doc" + const a = 2 + "`abstract type S` doc" + abstract type S <: Number end + "`struct T` doc" + struct T <: S + val + end + end + """ + f(x) + + Here a doc! + """ + @export f(x::TT) where {TT<:S} = x.val^2 + + @public begin + "`const b` doc" + const b = 3 + "`abstract type U` doc" + abstract type U <: Number end + "`struct V` doc" + struct V <: U + val + end + end + """ + g(x) + + There a doc! + """ + @public g(x::VV) where {VV<:U} = x.val^3 + + begin + "`const c` doc" + const c = 5 + "`abstract type W` doc" + abstract type W <: Number end + "`struct X` doc" + struct X <: W + val + end + end + """ + h(x) + + Everywhere a doc, doc! + """ + h(x::XX) where {XX<:W} = x.val^5 + + end # module Bla + + using .Bla + + @test (@macroexpand @garble x=3) == :(x=3) + @test (@macroexpand Bla.@gorble y=4) == :(y=4) + + @test m isa Int + @test m == 3 + @test Bla.n isa Int + @test Bla.n == 4 + + # @test hasproperty(Bla, :evala) + # @test hasproperty(Bla, :evalb) + + @test funca(3) == 9 + @test Bla.funcb(3) == 27 + + @test f(T(a)) == 4 + @test Bla.g(Bla.V(Bla.b)) == 27 + @test Bla.h(Bla.X(Bla.c)) == 3125 + + @test Base.isexported(Bla, :a) + @test Base.isexported(Bla, :S) + @test Base.isexported(Bla, :T) + @test Base.isexported(Bla, :f) + @test !Base.isexported(Bla, :b) + @test !Base.isexported(Bla, :U) + @test !Base.isexported(Bla, :V) + @test !Base.isexported(Bla, :g) + @test !Base.isexported(Bla, :c) + @test !Base.isexported(Bla, :W) + @test !Base.isexported(Bla, :X) + @test !Base.isexported(Bla, :h) + + @test Base.ispublic(Bla, :a) + @test Base.ispublic(Bla, :S) + @test Base.ispublic(Bla, :T) + @test Base.ispublic(Bla, :f) + @test Base.ispublic(Bla, :b) + @test Base.ispublic(Bla, :U) + @test Base.ispublic(Bla, :V) + @test Base.ispublic(Bla, :g) + @test !Base.ispublic(Bla, :c) + @test !Base.ispublic(Bla, :W) + @test !Base.ispublic(Bla, :X) + @test !Base.ispublic(Bla, :h) + + @test Base.hasproperty(Bla, :a) + @test Base.hasproperty(Bla, :S) + @test Base.hasproperty(Bla, :T) + @test Base.hasproperty(Bla, :f) + @test Base.hasproperty(Bla, :b) + @test Base.hasproperty(Bla, :U) + @test Base.hasproperty(Bla, :V) + @test Base.hasproperty(Bla, :g) + # @test Base.hasproperty(Bla, :c) # This group evaluates to false for some reason! + # @test Base.hasproperty(Bla, :W) # But that's true even for modules that have nothing + # @test Base.hasproperty(Bla, :X) # to do with `InlineExports`?! + # @test Base.hasproperty(Bla, :h) # Anyway, we used them in tests above... 🤷 + + @test repr(@doc(Bla.a)) == "`const a` doc\n" + @test repr(@doc(Bla.b)) == "`const b` doc\n" + @test repr(@doc(Bla.c)) == "`const c` doc\n" + @test repr(@doc(Bla.S)) == "`abstract type S` doc\n" + @test repr(@doc(Bla.U)) == "`abstract type U` doc\n" + @test repr(@doc(Bla.W)) == "`abstract type W` doc\n" + @test repr(@doc(Bla.T)) == "`struct T` doc\n" + @test repr(@doc(Bla.V)) == "`struct V` doc\n" + @test repr(@doc(Bla.X)) == "`struct X` doc\n" + @test repr(@doc(Bla.f)) == """```\nf(x)\n```\n\nHere a doc!\n""" + @test repr(@doc(Bla.g)) == """```\ng(x)\n```\n\nThere a doc!\n""" + @test repr(@doc(Bla.h)) == """```\nh(x)\n```\n\nEverywhere a doc, doc!\n""" +end diff --git a/src/core/utilities/misc.jl b/src/core/utilities/misc.jl new file mode 100644 index 00000000..189ba40a --- /dev/null +++ b/src/core/utilities/misc.jl @@ -0,0 +1,134 @@ +# Declared public in src/PostNewtonian.jl +@irrational ζ3 1.2020569031595942 big"1.20205690315959428539973816151144999076498629234049888179227155534183820578631309018645587360933525814619915" +""" + ζ3 + apery + +[Apéry's constant](https://en.wikipedia.org/wiki/Ap%C3%A9ry%27s_constant) is +defined as ``ζ(3)``, where ``ζ`` is the Riemann zeta function. This is OEIS +sequence [A002117](https://oeis.org/A002117). + +```julia-repl +julia> PostNewtonian.apery +ζ3 = 1.2020569031595... + +julia> PostNewtonian.ζ3 +ζ3 = 1.2020569031595... + +julia> sum((1:10_000_000).^-3) +1.2020569031595896 +``` +""" +ζ3 # We document it this way because `@irrational` cannot handle docstrings. + +# Declared public in src/PostNewtonian.jl +@doc raw""" + γₑ + +[Euler's constant](https://en.wikipedia.org/wiki/Euler%27s_constant) (also known as the +Euler–Mascheroni constant) is defined as the limit as ``n \to \infty`` of the difference +between the ``n``th partial sum of the harmonic series and ``\log(n)``. This is OEIS +sequence [A001620](https://oeis.org/A001620). + +This is distinct from the Euler's *number* ``e``, which is defined as the limit as ``n \to +\infty`` of the sum of ``1/n!``. + +Note that it is usually denoted simply as `γ` in the broader literature (and in Julia's own +`Base.MathConstants`), but that symbol is used in the post-Newtonian literature for the +quantity denoted in this package as [`γₚₙ`](@ref). To distinguish between the two, the PN +literature uses ``\gamma_\mathrm{E}`` for Euler's constant. (There is no Unicode subscript +"E", so we use "e" instead.) + +```julia-repl +julia> PostNewtonian.γₑ +γₑ = 0.5772156649015... + +julia> n=10_000_000; sum(1 ./ (1:n))-log(n) +0.5772157149015307 +``` +""" +γₑ # We document it here because docs don't fit nicely in the main file where it's defined. + +""" + value(x) + +Return `x` or the value wrapped by the `Dual` number `x` +""" +@public value(x::T) where {T} = hasfield(T, :value) ? getfield(x, :value) : x + +""" + iscall(x, symbols) + +Return `true` if the `Expr` `x` is a call to any element of `symbols`. +""" +iscall(x, symbols) = MacroTools.isexpr(x, :call) && x.args[1] ∈ symbols + +""" + isadd(x) + +Return `true` if the `Expr` `x` is a call to `(+)` or `:+`. +""" +isadd(x) = iscall(x, ((+), :+)) + +""" + ismul(x) + +Return `true` if the `Expr` `x` is a call to `(*)` or `:*`. +""" +ismul(x) = iscall(x, ((*), :*)) + +@testitem "core.misc" begin + using DoubleFloats + using ForwardDiff: Dual + using PostNewtonian: ζ3, γₑ, value, iscall, isadd, ismul + + # ζ3 formula + @test ζ3 ≈ sum((1:10_000_000) .^ -3) + + # γₑ formula + N = 10_000_000 + δγₑ = 1/2N + @test γₑ ≈ sum(1 ./ (1:N)) - log(N) - δγₑ + + # value + struct Dummy + value + end + struct Dummier + valuet + end + for T ∈ (Float16, Float32, Float64, Double16, Double32, Double64, BigFloat) + x = T(big"1.2") + @test value(x) isa T + @test value(x) == x + d = Dummy(x) + @test value(d) isa T + @test value(d) == x + dr = Dummier(x) + @test value(dr) isa Dummier + @test value(dr) == dr + v = (T(big"3.4"), T(big"5.6"), T(big"7.8")) + for i ∈ eachindex(v) + ẋ = Dual{:Taggo}(x, v[begin:i]) + @test value(ẋ) isa T + @test value(ẋ) == x + end + end + + # iscall and friends + @test iscall(:(log(1.2)), (:log,)) + @test iscall(:(log(1.2)), (:log, :sin)) + @test !iscall(:(log(1.2)), (:sin,)) + @test isadd(:(1 + 2)) + @test isadd(:(1 + 2c + 3c^2)) + @test isadd(:(1 + (2n + 3m))) + @test isadd(Expr(:call, :+, 1, 2)) + @test isadd(Expr(:call, (+), 1, 2)) + @test !isadd(:(1 * 2)) + @test ismul(:(1 * 2)) + @test ismul(:(1 * 2c * 3c^2)) + @test ismul(:(1 * (2c * 3d))) + @test ismul(Expr(:call, :*, 1, 2)) + @test ismul(Expr(:call, (*), 1, 2)) + @test !ismul(:(1 + 2)) +end diff --git a/src/utilities/truncated_series_inversion.jl b/src/core/utilities/truncated_series_inversion.jl similarity index 98% rename from src/utilities/truncated_series_inversion.jl rename to src/core/utilities/truncated_series_inversion.jl index 31eaa50b..48265f71 100644 --- a/src/utilities/truncated_series_inversion.jl +++ b/src/core/utilities/truncated_series_inversion.jl @@ -16,7 +16,7 @@ This function is essentially a helper function for the [`lagrange_inversion`](@r function. """ -function x╱f_mod_xⁿ⁻¹(a::NTuple{N,T}) where {N,T} +@public function x╱f_mod_xⁿ⁻¹(a::NTuple{N,T}) where {N,T} b = zeros(MVector{N,typeof(inv(a[1]))}) b[1] = inv(a[1]) for i ∈ 2:N @@ -113,7 +113,7 @@ This function is essentially a helper function for the [`lagrange_inversion`](@r function. """ -function hⁱ✖h_mod_xⁿ⁻¹(hⁱ::NTuple{N,T}, h::NTuple{N,T}) where {N,T} +@public function hⁱ✖h_mod_xⁿ⁻¹(hⁱ::NTuple{N,T}, h::NTuple{N,T}) where {N,T} hⁱ⁺¹ = zeros(MVector{N,T}) for i ∈ 1:N hⁱ⁺¹[i] = sum((hⁱ[j] * h[i - j + 1] for j ∈ 1:i)) @@ -394,7 +394,7 @@ actually be beneficial in practice, so we stick with the basic algorithm here would not be too difficult to implement if needed. """ -function lagrange_inversion(a::NTuple{N,T}) where {N,T} +@public function lagrange_inversion(a::NTuple{N,T}) where {N,T} h = x╱f_mod_xⁿ⁻¹(a) f⁻¹ = zeros(MVector{N,typeof(h[end] / 2)}) hⁱ = h # Create storage for the loop diff --git a/src/core/utilities/truncated_series_monoid.jl b/src/core/utilities/truncated_series_monoid.jl new file mode 100644 index 00000000..c23ec022 --- /dev/null +++ b/src/core/utilities/truncated_series_monoid.jl @@ -0,0 +1,294 @@ +@doc raw""" + truncated_series_inverse(a) + truncated_series_inverse!(b, a) + +Given the coefficients `a` of a series, find the coefficients `b` of the *multiplicative* +inverse of that series, up to the order of the original series. That is, if +```math +A \colonequals \sum_{i=0}^n a_{i} v^i, +``` +then we return the coefficients `b` of the series +```math +B \colonequals \sum_{i=0}^n b_{i} v^i +``` +such that +```math +A\, B = 1 + \mathcal{O}(v^{n+1}). +``` + +See [`lagrange_inversion`](@ref) for the *compositional* inverse (a.k.a. reversion), which +returns the coefficients of ``f^{-1}`` such that ``f^{-1}(f(v)) = v + +\mathcal{O}(v^{n+1})``. + +Note that this function returns the *coefficients* of the inverse, rather than its value. +This is relevant for use in [`truncated_series_product`](@ref) and +[`truncated_series_ratio`](@ref) — the latter of which just combines the former with this +function. + +!!! note + + This function requires that the constant term (`a[1]`) be nonzero. If you have a series + that starts at a higher term — say, ``v^n`` for ``n>0`` — you should factor out the + ``v^n``, and multiply the series resulting from this function by ``v^{-n}``. + +## Explanation + +The inverse coefficients can be computed fairly easily by induction. Start by defining +```math +b_0 = 1/a_0. +``` +Now, assuming that we've computed all coefficients up to and including ``b_{i}``, we can +compute ``b_{i+1}`` from the condition that the term proportional to ``v^{i+1}`` in the +product of the series and its inverse must be zero. That coefficient of that term is +clearly given by the sum of all pairs of coefficients ``a_j b_{i+1-j}`` for +``j=0,1,\ldots,i+1``: +```math +\sum_{j=0}^{i+1} a_j b_{i+1-j} = a_0 b_{i+1} + \sum_{j=1}^{i+1} a_j b_{i+1-j}. +``` +Setting this last expression to zero, using the value of ``b_0`` above, and rearranging, we +have +```math +b_{i+1} = -b_0\sum_{j=1}^{i} a_j b_{i+1-j}. +``` +""" +@public function truncated_series_inverse(a::AbstractVector) + b = similar(a) + return truncated_series_inverse!(b, a) +end + +function truncated_series_inverse(a::NTuple{N,T}) where {N,T} + b = MVector{N,T}(undef) + truncated_series_inverse!(b, SVector{N,T}(a)) + return Tuple(b) +end + +@public function truncated_series_inverse!(b, a) + # We fake 0-based indexing by using `begin + i` for `i ∈ 0:n`. + @assert length(b) == length(a) + n = length(a) - 1 + @inbounds @fastmath if n ≥ 0 + b[begin + 0] = inv(a[begin + 0]) + end + @inbounds @fastmath for i ∈ 0:(n - 1) + b[begin + i + 1] = + -b[begin + 0] * sum( + (a[begin + j] * b[begin + i + 1 - j] for j ∈ 1:(i + 1)); + init=zero(eltype(a)), + ) + end + return b +end + +@doc raw""" + truncated_series_product(a, b, v) + +Evaluate the truncated product of the series `a` and `b`, which are expanded in powers of +`v`. + +Note that this function returns the *value* of the summation, rather than its coefficients. + +Here we define the series in terms of the coefficients `a` and `b` as +```math +A \colonequals \sum_{i=0}^n a_{i} v^i +\qquad +B \colonequals \sum_{i=0}^n b_{i} v^i, +``` +and return the *value* of the product ``A\, B`` truncated at ``v^n``. + +Internally, the sums are performed using `evalpoly`. + +See also [`truncated_series_ratio`](@ref). +""" +@public function truncated_series_product(a, b, v) + @assert length(a) == length(b) + N = length(a) - 1 + if N < 0 + return zero(v) + end + AB = b[begin + N] * a[begin + 0] + for n ∈ (N - 1):-1:0 + AB = muladd( + v, AB, b[begin + n] * evalpoly(v, @view a[(begin + 0):(begin + (N - n))]) + ) + end + return AB +end + +function truncated_series_product(a::NTuple{NT,T}, b, v) where {NT,T} + @assert length(a) == length(b) + N = length(a) - 1 + if N < 0 + return zero(v) + end + AB = b[begin + N] * a[begin + 0] + for n ∈ (N - 1):-1:0 + AB = muladd(v, AB, b[begin + n] * evalpoly(v, a[(begin + 0):(begin + (N - n))])) + end + return AB +end + +@doc raw""" + truncated_series_ratio(a, b, v) + +Evaluate the truncated ratio of the series `a` and `b`, which are expanded in powers of `v`. + +Note that this function returns the *value* of the summation, rather than its coefficients. + +Here we define the series in terms of the coefficients `a` and `b` as +```math +A \colonequals \sum_{i=0}^n a_{i} v^i +\qquad +B \colonequals \sum_{i=0}^n b_{i} v^i, +``` +and return the *value* of the ratio ``A / B`` truncated at ``v^n``. + +This function simply combines [`truncated_series_product`](@ref) and +[`truncated_series_inverse`](@ref). +""" +@public function truncated_series_ratio(a, b, v) + return truncated_series_product(a, truncated_series_inverse(b), v) +end + +@doc raw""" + truncated_series_ratio(a, b) + +Evaluate the truncated ratio of the series `a` and `b` at expansion value 1. + +This is relevant when the expansion is not in the dynamic variable `v`, for example, but in +powers of ``1/c`` as in post-Newtonian expansions. (That is, when the `v` dependence is +already included in the input coefficients.) + +This is different from `truncated_series_ratio(a, b, 1)` in that `a` and `b` may have +different lengths, and it should be somewhat more efficient. +""" +function truncated_series_ratio(a::NTuple{N1,T1}, b::NTuple{N2,T2}) where {N1,N2,T1,T2} + if N1 == 0 && N2 == 0 + throw( + ArgumentError( + "In `truncated_series_ratio(a,b)`, both arguments have length 0; " * + "this is not allowed.", + ), + ) + end + if N2 == 0 + throw( + ArgumentError( + "In `truncated_series_ratio(a,b)`, argument `b` has length 0; " * + "this is not allowed.", + ), + ) + end + if N1 == 0 + return zero(T2) + end + + N = max(N1, N2) + T = promote_type(T1, T2) + + # The uppercase `N`s represent the number of terms in the tuples, while the lowercase + # `n`s represent the highest index of the terms. + n1, n2, n = N1 - 1, N2 - 1, N - 1 + + # Next, we compute the same thing as `truncated_series_inverse` except that we truncate + # this inverse series at `n`, instead of `n2`. Specifically, the differences are that + # (1) the range of iteration over `i` extends to `(n-1)` instead of `(n2-1)`, and (2) + # the range of iteration over `j` extends to `min(i+1, n2)` instead of `(i+1)`. + b⁻¹ = MVector{N,T}(undef) + @inbounds @fastmath begin + b⁻¹[begin + 0] = inv(b[begin + 0]) + for i ∈ 0:(n - 1) + b⁻¹[begin + i + 1] = + -b⁻¹[begin + 0] * sum( + (b[begin + j] * b⁻¹[begin + i + 1 - j] for j ∈ 1:min((i + 1), n2)); + init=zero(T), + ) + end + + # Now, we do the same thing as `truncated_series_product`, except that we account + # for the fact that `a` may not be as long as `b⁻¹`, and we are assuming `v=1`. + a╱b = zero(T) + for i1 ∈ 0:n1 + a╱b += a[begin + i1] * sum((b⁻¹[begin + i2] for i2 ∈ 0:(n - i1)); init=zero(T)) + end + a╱b + end +end + +@testitem "truncated_series_ratio(a,b)" begin + using Random + using DoubleFloats + using StaticArrays: SVector + import PostNewtonian: + truncated_series_inverse, truncated_series_ratio, truncated_series_product + Random.seed!(123) + + # truncated_series_product tests + # N < 0, empty vectors => always zero + @test truncated_series_product((), (), 3.14) == 0.0 + @test truncated_series_product(Float64[], Float64[], 3.14) == 0.0 + + # N = 0, single‐term series => a0*b0 + a0, b0 = 2.5, -1.5 + @test truncated_series_product([a0], [b0], 42) == a0 * b0 + + # N = 1, two‐term series with vector inputs + a = [1.0, 2.0] # 1 + 2v + b = [3.0, 4.0] # 3 + 4v + v = 5.0 + # (1 + 2v)*(3 + 4v) = 3 + (6+4)v + ··, truncate ⇒ 3 +10⋅5 = 53 + @test truncated_series_product(a, b, v) == 53.0 + + # same with tuple dispatch + @test truncated_series_product(Tuple(a), Tuple(b), v) == 53.0 + + # truncated_series_ratio edge cases + # N2 == 0 (empty b) must throw ArgumentError + a = (1.0, 2.0, 3.0) + a_empty = () + b_empty = () + @test_throws ArgumentError truncated_series_ratio(a, b_empty) + @test_throws ArgumentError truncated_series_ratio(a_empty, b_empty) + + # N1 == 0 (empty a) returns zero of promoted type + a_empty = () + b = (5, -2) + @test truncated_series_ratio(a_empty, b) ≡ + zero(promote_type(eltype(a_empty), eltype(b))) + + for T ∈ [Float32, Float64, Double64] + for N ∈ 1:15 + A = rand(T, N) + A[1] = one(T) + rand(T) / 100 + local a = Tuple(A) + x = rand(T) + ϵ = eps(sum(a) * N) + for N1 ∈ 1:N + expected = sum(truncated_series_inverse(a)) + unit = zeros(T, N1) + unit[1] = one(T) + @test truncated_series_ratio(Tuple(unit), a) ≈ expected rtol = ϵ + end + @test truncated_series_ratio(a, a) ≈ 1 rtol = ϵ + @test truncated_series_ratio(a, x .* a) ≈ 1 / x rtol = ϵ + @test truncated_series_ratio(x .* a, a) ≈ x rtol = ϵ + + c = Tuple(rand(T, N)) + @test truncated_series_ratio(c, a) ≈ + truncated_series_ratio(SVector(c), SVector(a), 1) rtol = ϵ + + for Nzero ∈ 2:N + cshort = c[begin:(Nzero - 1)] + czeros = (cshort..., (zero(T) for i ∈ Nzero:N)...) + #! format: off + @test truncated_series_ratio(cshort, a) ≈ + truncated_series_ratio(czeros, a) atol=2eps(T) rtol=2eps(T) + + ashort = a[begin:(Nzero - 1)] + azeros = (ashort..., (zero(T) for i ∈ Nzero:N)...) + @test truncated_series_ratio(c, ashort) ≈ + truncated_series_ratio(c, azeros) atol=2eps(T) rtol=2eps(T) + #! format: on + end + end + end +end diff --git a/src/derived_variables.jl b/src/derived_variables.jl deleted file mode 100644 index 9091c887..00000000 --- a/src/derived_variables.jl +++ /dev/null @@ -1,81 +0,0 @@ -module DerivedVariables - -using ..PostNewtonian: VecOrPNSystem -using ..PostNewtonian.FundamentalVariables -using Quaternionic: 𝐢, 𝐣, 𝐤, QuatVec, ⋅, ×, abs2vec, absvec - -include("derived_variables/mass_combinations.jl") -export total_mass, - M, - reduced_mass, - μ, - reduced_mass_ratio, - ν, - mass_difference_ratio, - δ, - mass_ratio, - q, - chirp_mass, - ℳ, - X1, - X₁, - X2, - X₂ - -include("derived_variables/orbital_elements.jl") -export n_hat, n̂, lambda_hat, λ̂, ell_hat, ℓ̂, Omega, Ω, lnv - -include("derived_variables/spin_combinations.jl") -export S⃗₁, - S⃗₂, - S⃗, - Σ⃗, - χ⃗, - χ⃗ₛ, - χ⃗ₐ, - chi_perp, - χₚₑᵣₚ, - χₑ, - chi_eff, - χₚ, - chi_p, - S⃗₀⁺, - S⃗₀⁻, - S₀⁺ₙ, - S₀⁻ₙ, - S₀⁺λ, - S₀⁻λ, - S₀⁺ₗ, - S₀⁻ₗ, - χ₁², - χ₂², - χ₁, - χ₂, - χ₁₂, - χ₁ₗ, - χ₂ₗ, - χₛₗ, - χₐₗ, - Sₙ, - Σₙ, - Sλ, - Σλ, - Sₗ, - Σₗ, - sₗ, - σₗ, - S₁ₙ, - S₁λ, - S₁ₗ, - S₂ₙ, - S₂λ, - S₂ₗ - -include("derived_variables/horizons.jl") -export rₕ₁, - rₕ₂, Ωₕ₁, Ωₕ₂, sin²θ₁, sin²θ₂, ϕ̇̂₁, ϕ̇̂₂, Î₀₁, Î₀₂, κ₁, κ₂, κ₊, κ₋, λ₁, λ₂, λ₊, λ₋ - -include("derived_variables/tidal_coupling.jl") -export Λ̃, Lambda_tilde - -end diff --git a/src/dynamics.jl b/src/dynamics.jl deleted file mode 100644 index e03d7e17..00000000 --- a/src/dynamics.jl +++ /dev/null @@ -1,3 +0,0 @@ -include("dynamics/up_down_instability.jl") -include("dynamics/right_hand_sides.jl") -include("dynamics/orbital_evolution.jl") diff --git a/src/fundamental_variables.jl b/src/fundamental_variables.jl deleted file mode 100644 index db75b10d..00000000 --- a/src/fundamental_variables.jl +++ /dev/null @@ -1,163 +0,0 @@ -module FundamentalVariables - -using ..PostNewtonian -using ..PostNewtonian: PNSystem, BHNS, NSNS, FDPNSystem -using ..PostNewtonian: M₁index, M₂index, χ⃗₁indices, χ⃗₂indices, Rindices, vindex, Φindex -using Quaternionic: Quaternionic, QuatVec, Rotor - -export M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, Λ₁, Λ₂, M1, M2, chi1, chi2, Phi, Lambda1, Lambda2 - -## NOTE: -## This indices used below are intimately bound to choices made in the definitions of -## the various `PNSystem`s. Any changes there must be mirrored here, and vice versa. - -""" - M₁(pnsystem) - M1(pnsystem) - -Mass of object 1 in this system. -""" -M₁(s::PNSystem) = M₁(s.state) -M₁(state::AbstractVector) = @inbounds state[M₁index] -const M1 = M₁ - -""" - M₂(pnsystem) - M2(pnsystem) - -Mass of object 2 in this system. -""" -M₂(s::PNSystem) = M₂(s.state) -M₂(state::AbstractVector) = @inbounds state[M₂index] -const M2 = M₂ - -""" - χ⃗₁(pnsystem) - chi1(pnsystem) - -Dimensionless spin vector of object 1 in this system, as a `QuatVec`. -""" -χ⃗₁(s::PNSystem) = χ⃗₁(s.state) -χ⃗₁(state::AbstractVector) = @inbounds QuatVec(view(state, χ⃗₁indices)...) -const chi1 = χ⃗₁ - -""" - χ⃗₂(pnsystem) - chi2(pnsystem) - -Dimensionless spin vector of object 2 in this system, as a `QuatVec`. -""" -χ⃗₂(s::PNSystem) = χ⃗₂(s.state) -χ⃗₂(state::AbstractVector) = @inbounds QuatVec(view(state, χ⃗₂indices)...) -const chi2 = χ⃗₂ - -""" - R(pnsystem) - -Orientation of the binary, as a `Rotor`. - -At any instant, the binary is represented by the right-handed triad ``(n̂, λ̂, ℓ̂)``, where -[``n̂``](@ref PostNewtonian.n̂) is the unit vector pointing from object 2 to object 1, and -the instantaneous velocities of the binary's elements are in the ``n̂``-``λ̂`` plane. This -`Rotor` will rotate the ``x̂`` vector to be along ``n̂``, the ``ŷ`` vector to be along -``λ̂``, and the ``ẑ`` vector to be along ``ℓ̂``. - -Note that the angular velocity associated to `R` is given by ``Ω⃗ = 2 Ṙ R̄ = Ω ℓ̂ + ϖ n̂``. -(Any component of ``Ω⃗`` along ``λ̂`` would violate the condition that the velocities be in -the ``n̂``-``λ̂`` plane.) Here, the scalar quantity ``Ω`` is the orbital angular frequency, -and ``ϖ`` is the precession angular frequency. - -See also [`n̂`](@ref PostNewtonian.n̂), [`λ̂`](@ref PostNewtonian.λ̂), [`ℓ̂`](@ref -PostNewtonian.ℓ̂), [`Ω`](@ref PostNewtonian.Ω), and [`𝛡`](@ref PostNewtonian.𝛡)``=ϖ n̂``. -""" -R(s::PNSystem) = R(s.state) -R(state::AbstractVector) = @inbounds Rotor(view(state, Rindices)...) - -@doc raw""" - v(pnsystem) - v(;Ω, M=1) - -Post-Newtonian velocity parameter. This is related to the orbital angular frequency -``\Omega`` as -```math -v \colonequals (M\,\Omega)^{1/3}, -``` -where ``M`` is the total mass of the binary. - -Note that if you want to pass the value ``Ω`` (rather than a `PNSystem`), you must pass it -as a keyword argument — as in `v(Ω=0.1)`. - -See also [`Ω`](@ref). -""" -v(s::PNSystem) = v(s.state) -v(state::AbstractVector) = @inbounds state[vindex] -v(; Ω, M=1) = ∛(M * Ω) - -""" - Φ(pnsystem) - Phi(pnsystem) - -Integrated orbital phase of the system. It is computed as the integral of [`Ω`](@ref). -""" -Φ(s::PNSystem) = Φ(s.state) -Φ(state::AbstractVector) = @inbounds state[Φindex] -const Phi = Φ - -@doc raw""" - Λ₁(pnsystem) - Lambda1(pnsystem) - -Quadrupolar tidal-coupling parameter of object 1 in this system. - -We imagine object 1 begin placed in an (adiabatic) external field with Newtonian potential -``\phi``, resulting in a tidal field measured by ``\partial_i \partial_j \phi`` evaluated at -the center of mass of the object. This induces a quadrupole moment ``Q_{ij}`` in object 1, -which can be related to the tidal field as -```math -Q_{ij} = -\frac{G^4}{c^{10}} \Lambda_1 M_1^5 \partial_i \partial_j \phi, -``` -where ``M_1`` is the mass of object 1. This tidal-coupling parameter ``\Lambda_1`` can be -related to the Love number ``k_2`` (where the subscript 2 refers to the fact that this is -for the ``\ell=2`` quadrupole, rather than object 2) as -```math -\Lambda_1 = \frac{2}{3} \frac{c^{10}}{G^5} \frac{R_1^5}{M_1^5} k_2, -``` -where ``R_1`` is the radius of object 1. Note that ``\Lambda_1`` is dimensionless. For -black holes, it is precisely zero; for neutron stars it may range up to 1; more exotic -objects may have significantly larger values. - -Note that — as of this writing — only `NSNS` systems can have a nonzero value for this -quantity. (`BHNS` systems can only have a nonzero value for ``\Lambda_2``.) All other -types return `0`, which Julia can use to eliminate code that would then be 0. Thus, it is -safe and efficient to use this quantity in any PN expression that specializes on the type of -`pnsystem`. - -See also [`Λ₂`](@ref) and [`Λ̃`](@ref). -""" -Λ₁(pn::PNSystem) = zero(eltype(pn)) -Λ₁(pn::NSNS) = pn.Λ₁ -Λ₁(pn::FDPNSystem) = pn.Λ₁ -const Lambda1 = Λ₁ - -@doc raw""" - Λ₂(pnsystem) - Lambda2(pnsystem) - -Quadrupolar tidal coupling parameter of object 2 in this system. - -See [`Λ₁`](@ref) for details about the definition, swapping "object 1" with "object 2". - -Note that — as of this writing — only `BHNS` and `NSNS` systems can have a nonzero value for -this quantity. All other types return `0`, which Julia can use to eliminate code that would -then be 0. Thus, it is safe and efficient to use this quantity in any PN expression that -specializes on the type of `pnsystem`. - -See also [`Λ₁`](@ref) and [`Λ̃`](@ref). -""" -Λ₂(pn::PNSystem) = zero(eltype(pn)) -Λ₂(pn::BHNS) = pn.Λ₂ -Λ₂(pn::NSNS) = pn.Λ₂ -Λ₂(pn::FDPNSystem) = pn.Λ₂ -const Lambda2 = Λ₂ - -end diff --git a/src/assorted_binaries/examples.jl b/src/interface/assorted_binaries/examples.jl similarity index 100% rename from src/assorted_binaries/examples.jl rename to src/interface/assorted_binaries/examples.jl diff --git a/src/assorted_binaries/random.jl b/src/interface/assorted_binaries/random.jl similarity index 100% rename from src/assorted_binaries/random.jl rename to src/interface/assorted_binaries/random.jl diff --git a/src/compatibility_layers/gwframes.jl b/src/interface/compatibility_layers/gwframes.jl similarity index 98% rename from src/compatibility_layers/gwframes.jl rename to src/interface/compatibility_layers/gwframes.jl index ad848c38..343bca4d 100644 --- a/src/compatibility_layers/gwframes.jl +++ b/src/interface/compatibility_layers/gwframes.jl @@ -231,8 +231,8 @@ function PNWaveform( frame=transpose(stack(solution[[:Rʷ, :Rˣ, :Rʸ, :Rᶻ]])), M1=solution[:M₁], M2=solution[:M₂], - chi1=transpose(stack(solution[[:χ⃗₁ˣ, :χ⃗₁ʸ, :χ⃗₁ᶻ]])), - chi2=transpose(stack(solution[[:χ⃗₂ˣ, :χ⃗₂ʸ, :χ⃗₂ᶻ]])), + chi1=transpose(stack(solution[[:χ₁ˣ, :χ₁ʸ, :χ₁ᶻ]])), + chi2=transpose(stack(solution[[:χ₂ˣ, :χ₂ʸ, :χ₂ᶻ]])), v=solution[:v], Phi=solution[:Φ], ) diff --git a/src/utilities/combine_solutions.jl b/src/interface/dynamics/combine_solutions.jl similarity index 100% rename from src/utilities/combine_solutions.jl rename to src/interface/dynamics/combine_solutions.jl diff --git a/src/dynamics/orbital_evolution.jl b/src/interface/dynamics/orbital_evolution.jl similarity index 98% rename from src/dynamics/orbital_evolution.jl rename to src/interface/dynamics/orbital_evolution.jl index 19d7af07..684a9883 100644 --- a/src/dynamics/orbital_evolution.jl +++ b/src/interface/dynamics/orbital_evolution.jl @@ -227,12 +227,12 @@ The evolved variables, in order, are * `M₁`: Mass of black hole 1 * `M₂`: Mass of black hole 2 - * `χ⃗₁ˣ`: ``x`` component of dimensionless spin of black hole 1 - * `χ⃗₁ʸ`: ``y`` component... - * `χ⃗₁ᶻ`: ``z`` component... - * `χ⃗₂ˣ`: ``x`` component of dimensionless spin of black hole 2 - * `χ⃗₂ʸ`: ``y`` component... - * `χ⃗₂ᶻ`: ``z`` component... + * `χ₁ˣ`: ``x`` component of dimensionless spin of black hole 1 + * `χ₁ʸ`: ``y`` component... + * `χ₁ᶻ`: ``z`` component... + * `χ₂ˣ`: ``x`` component of dimensionless spin of black hole 2 + * `χ₂ʸ`: ``y`` component... + * `χ₂ᶻ`: ``z`` component... * `Rʷ`: Scalar component of frame rotor * `Rˣ`: ``x`` component... * `Rʸ`: ``y`` component... diff --git a/src/dynamics/right_hand_sides.jl b/src/interface/dynamics/right_hand_sides.jl similarity index 96% rename from src/dynamics/right_hand_sides.jl rename to src/interface/dynamics/right_hand_sides.jl index b221da22..fa783fca 100644 --- a/src/dynamics/right_hand_sides.jl +++ b/src/interface/dynamics/right_hand_sides.jl @@ -37,12 +37,12 @@ end Ṙ = Ω⃗ * R / 2 u̇[M₁index] = Ṁ₁ u̇[M₂index] = Ṁ₂ - u̇[χ⃗₁ˣindex] = χ⃗̇₁.x - u̇[χ⃗₁ʸindex] = χ⃗̇₁.y - u̇[χ⃗₁ᶻindex] = χ⃗̇₁.z - u̇[χ⃗₂ˣindex] = χ⃗̇₂.x - u̇[χ⃗₂ʸindex] = χ⃗̇₂.y - u̇[χ⃗₂ᶻindex] = χ⃗̇₂.z + u̇[χ₁ˣindex] = χ⃗̇₁.x + u̇[χ₁ʸindex] = χ⃗̇₁.y + u̇[χ₁ᶻindex] = χ⃗̇₁.z + u̇[χ₂ˣindex] = χ⃗̇₂.x + u̇[χ₂ʸindex] = χ⃗̇₂.y + u̇[χ₂ᶻindex] = χ⃗̇₂.z u̇[Rʷindex] = Ṙ.w u̇[Rˣindex] = Ṙ.x u̇[Rʸindex] = Ṙ.y diff --git a/src/utilities/termination_criteria.jl b/src/interface/dynamics/termination_criteria.jl similarity index 100% rename from src/utilities/termination_criteria.jl rename to src/interface/dynamics/termination_criteria.jl diff --git a/src/dynamics/up_down_instability.jl b/src/interface/dynamics/up_down_instability.jl similarity index 100% rename from src/dynamics/up_down_instability.jl rename to src/interface/dynamics/up_down_instability.jl diff --git a/src/interface/interface.jl b/src/interface/interface.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/interface/interface.jl @@ -0,0 +1 @@ + diff --git a/src/interface/orbital_evolution.jl b/src/interface/orbital_evolution.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/interface/orbital_evolution.jl @@ -0,0 +1 @@ + diff --git a/src/interface/pn.jl b/src/interface/pn.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/interface/pn.jl @@ -0,0 +1 @@ + diff --git a/src/waveforms.jl b/src/interface/waveform.jl similarity index 100% rename from src/waveforms.jl rename to src/interface/waveform.jl diff --git a/src/literature/Blanchet2024.jl b/src/literature/Blanchet2024.jl new file mode 100644 index 00000000..95db07a2 --- /dev/null +++ b/src/literature/Blanchet2024.jl @@ -0,0 +1,81 @@ +@doc raw""" +Expressions from [Blanchet2024](@cite) + +This package mostly derives its notation from that paper. The main exception is that +Blanchet uses the symbol ``m`` for mass and ``\mathup{M}`` for ADM mass, while we reserve +``m`` for the azimuthal number of spin-weighted spherical harmonics, and use ``M`` for mass +instead. (ADM mass does not appear in this package as of this writing.) + +In Sec. 3.2.4, Blanchet defines the total mass ``m=m₁+m₂``, the relative mass difference +``\Delta = (m₁ - m₂) / m``, the reduced mass ``μ = m₁ m₂ / m``, and the symmetric mass ratio +``ν ≡ \mu/m = m₁ m₂ / m²``. He also poses ``X₁ = m₁ / m`` and ``X₂ = m₂ / m`` so that ``Δ = +X₁ - X₂`` and ``ν = X₁ X₂``. + +In Eq. (369), he defines +```math +\gamma = \frac{GM}{rc^2}. +``` + +In Eq. (375), he defines the "frequency-related parameter" +```math +x = \left(\frac{GM\Omega}{c^3}\right)^{2/3}, +``` +Note that this ``\Omega`` is "the orbital frequency [...] of the circular orbit as measured +by a distant observer." He does not define this completely, except to say that it is the +frequency associated with the asymptotic Killing vector field "in any natural coordinate +system which respects the helical symmetry" for an idealized circular system. + +[Trestini2025](@cite) describes roughly the same frequency as the "waveform frequency" Ω, +and uses "orbital frequency" ω to refer to — presumably — the coordinate frequency. + +""" +@pn_reference module Blanchet2024 + +import PostNewtonian: G, c, x, ν, γₑ + +""" + Eq483(pnsystem) + +Quasi-circular non-spinning 4.5PN energy flux terms. + +As given in Eq. (483) of [Blanchet2024](@cite), this expression includes "contributions from +tails, iterated tails, and tails-of-memory", but no contributions from spin. + +""" +@pn_expression function Eq483(pnsystem) + ℱ = + (32c^5 / 5G * ν * x^5) * @pn_expansion( + 1 + + (-1247/336 - 35/12 * ν)x + + (4π)x^(3/2) + + (-44711/9072 + 9271/504 * ν + 65/18 * ν^2)x^2 + + (-8191/672 - 583/24 * ν)π * x^(5/2) + + ( + 6643739519/69854400 + 16/3 * π^2 / 3 - 1712/105 * γₑ - + 856/105 * ln(16x) + (-134543/7776 + 41/48 * π^2)ν - 94403/3024 * ν^2 - + 775/324 * ν^3 + )x^3 + + (-16285/504 + 214745/1728 * ν + 193385/3024 * ν^2)π * x^(7/2) + + ( + -323105549467/3178375200 + 232597/4410 * γₑ - 1369/126 * π^2 + + 39931/294 * ln(2) - 47385/1568 * ln(3) + + 232597/8820 * ln(x) + + ( + -1452202403629/1466942400 + 41478/245 * γₑ - 267127/4608 * π^2 + + 479062/2205 * ln(2) + + 47385/392 * ln(3) + + 20739/245 * ln(x) + )ν + + (1607125/6804 - 3157/384 * π^2)ν^2 + + 6875/504 * ν^3 + + 5/6 * ν^4 + )x^4 + + ( + 265978667519/745113600 - 6848/105 * γₑ - 3424/105 * ln(16x) + + (2062241/22176 + 41/12 * π^2)ν - 133112905/290304 * ν^2 - + 3719141/38016 * ν^3 + )π * x^(9/2) + ) +end + +end # module Blanchet2024 diff --git a/src/literature/Einstein1918.jl b/src/literature/Einstein1918.jl new file mode 100644 index 00000000..f1ea0f56 --- /dev/null +++ b/src/literature/Einstein1918.jl @@ -0,0 +1,9 @@ +@pn_reference module Einstein1918 + +import PostNewtonian: G, c, M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, χₛ + +# import common variables +# define variables not in common variables +# write individual expressions as separate functions with `@pn_expression` + +end diff --git a/src/literature/TaylorPoisson2008.jl b/src/literature/TaylorPoisson2008.jl new file mode 100644 index 00000000..bcb56584 --- /dev/null +++ b/src/literature/TaylorPoisson2008.jl @@ -0,0 +1,20 @@ +@doc raw""" +Expressions from [TaylorPoisson2008](@cite) + +Note that there are expressions in the paper that could probably be used pretty easily to +generalize to precessing and/or eccentric systems. +""" +@pn_reference module TaylorPoisson2008 + +import PostNewtonian: G, c, v, M₁ as m₁, M₂ as m₂, M as m, r, χ₁ₗ as χ₁, χ₂ₗ as χ₂ + +# These are defined in the text below Eq. (9.5), though I've added subscripts to identify +# them as applying to the first and second bodies, respectively. +ϵ₁(pnsystem) = Base.sign(χ₁(pnsystem)) +ϵ₂(pnsystem) = Base.sign(χ₂(pnsystem)) + +@pn_expression function Eq_9_4(pnsystem) end + +@pn_expression function Eq_9_7(pnsystem) end + +end # module TaylorPoisson2008 diff --git a/src/literature/Trestini2025.jl b/src/literature/Trestini2025.jl new file mode 100644 index 00000000..53fb89e8 --- /dev/null +++ b/src/literature/Trestini2025.jl @@ -0,0 +1,24 @@ +@doc raw""" +Expressions from [Trestini2025](@cite) + +""" +@pn_reference module Trestini2025 + +import PostNewtonian: G, c, v, M₁ as m₁, M₂ as m₂, M as m, r, χ₁ₗ as χ₁, χ₂ₗ as χ₂ + +""" + ℵ₈(pnsystem) + +4PN tidal dissipation coefficient + +As given in the text below Eqs. (7.3) of [Trestini2025](@cite). Trestini defines ℵ₂ₙ as the + +> tidal dissipation (or black hole absorption) coefficient entering at the ``n``PN order +> beyond the leading, quadrupolar flux ('aleph' stands for 'absorption'). +""" +@pn_expression ℵ₈(pnsystem) = 1 - 4ν + 2ν^2 + +# Eq. (7.3a) +@pn_expression ℱₑᴴ(pnsystem) = 32c^5 * ν^2 / 5G * ℵ₈ * y^9 + +end # module Trestini2025 diff --git a/src/derived_variables/horizons.jl b/src/literature/common_variables/horizons.jl similarity index 87% rename from src/derived_variables/horizons.jl rename to src/literature/common_variables/horizons.jl index bc34154d..3e45a4bf 100644 --- a/src/derived_variables/horizons.jl +++ b/src/literature/common_variables/horizons.jl @@ -7,7 +7,7 @@ As defined on page 2, line 4, of [Alvi (2001)](https://doi.org/10.1103/PhysRevD.64.104020). See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -rₕ₁(s::VecOrPNSystem) = M₁(s) * (1 + √(1 - min(χ₁²(s), 1))) +@public rₕ₁(s::PNSystem) = M₁(s) * (1 + √(1 - min(χ₁²(s), 1))) """ rₕ₂(s) @@ -18,7 +18,7 @@ As defined on page 2, line 4, of [Alvi (2001)](https://doi.org/10.1103/PhysRevD.64.104020). See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -rₕ₂(s::VecOrPNSystem) = M₂(s) * (1 + √(1 - min(χ₂²(s), 1))) +@public rₕ₂(s::PNSystem) = M₂(s) * (1 + √(1 - min(χ₂²(s), 1))) """ Ωₕ₁(s) @@ -29,7 +29,7 @@ As defined on page 2, line 5, of [Alvi (2001)](https://doi.org/10.1103/PhysRevD.64.104020). See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -Ωₕ₁(s::VecOrPNSystem) = χ₁(s) / 2rₕ₁(s) +@public Ωₕ₁(s::PNSystem) = χ₁(s) / 2rₕ₁(s) """ Ωₕ₂(s) @@ -40,7 +40,7 @@ As defined on page 2, line 5, of [Alvi (2001)](https://doi.org/10.1103/PhysRevD.64.104020). See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -Ωₕ₂(s::VecOrPNSystem) = χ₂(s) / 2rₕ₂(s) +@public Ωₕ₂(s::PNSystem) = χ₂(s) / 2rₕ₂(s) """ sin²θ₁(s) @@ -50,7 +50,7 @@ Sine-squared of angle between spin of black hole 1 and vector to black hole 2. Compare to Eq. (18) of [Alvi (2001)](https://doi.org/10.1103/PhysRevD.64.104020). See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -function sin²θ₁(s::VecOrPNSystem) +@public function sin²θ₁(s::PNSystem) let χ₁² = χ₁²(s) ifelse(iszero(χ₁²), one(χ₁²), abs2vec(n̂(s) × χ⃗₁(s)) / χ₁²) end @@ -64,7 +64,7 @@ Sine-squared of angle between spin of black hole 2 and vector to black hole 1. Compare to Eq. (18) of [Alvi (2001)](https://doi.org/10.1103/PhysRevD.64.104020). See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -function sin²θ₂(s::VecOrPNSystem) +@public function sin²θ₂(s::PNSystem) let χ₂² = χ₂²(s) ifelse(iszero(χ₂²), one(χ₂²), abs2vec(n̂(s) × χ⃗₂(s)) / χ₂²) end @@ -83,7 +83,7 @@ that depend on this. See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -function ϕ̇̂₁(s::VecOrPNSystem) +@public function ϕ̇̂₁(s::PNSystem) let χ₁ = χ₁(s), sin²θ₁ = sin²θ₁(s), M = M(s) ifelse( iszero(χ₁), @@ -106,7 +106,7 @@ that depend on this. See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -function ϕ̇̂₂(s::VecOrPNSystem) +@public function ϕ̇̂₂(s::PNSystem) let χ₂ = χ₂(s), sin²θ₂ = sin²θ₂(s), M = M(s) ifelse( iszero(χ₂), @@ -125,7 +125,7 @@ This is the moment divided by ``ν^2 v^{12}``, as given by Eq. (10) of [Alvi (2001)](https://doi.org/10.1103/PhysRevD.64.104020). See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -function Î₀₁(s::VecOrPNSystem) +@public function Î₀₁(s::PNSystem) let χ₁² = χ₁²(s), sin²θ₁ = sin²θ₁(s) (16rₕ₁(s) / 5M(s)^2) * M₁(s)^3 * sin²θ₁ * (1 - 3//4 * χ₁² + 15//4 * χ₁² * sin²θ₁) end @@ -140,7 +140,7 @@ This is the moment divided by ``ν^2 v^{12}``, as given by Eq. (10) of [Alvi (2001)](https://doi.org/10.1103/PhysRevD.64.104020). See the documentation section on ["Horizons"](@ref Horizons) for more details. """ -function Î₀₂(s::VecOrPNSystem) +@public function Î₀₂(s::PNSystem) let χ₂² = χ₂²(s), sin²θ₂ = sin²θ₂(s) (16rₕ₂(s) / 5M(s)^2) * M₂(s)^3 * sin²θ₂ * (1 - 3//4 * χ₂² + 15//4 * χ₂² * sin²θ₂) end @@ -155,7 +155,7 @@ The "quadrupolar polarisability" of object 1 used by [Bohé et al. Note that Bohé et al. refer to the closely related (and co-authored) [Marsat (2014)](https://arxiv.org/abs/1411.4118), who notes above Eq. (4.7) that this is denoted ``C_{\mathrm{ES}^2}`` in [Levi and Steinhoff (2014)](https://arxiv.org/abs/1410.2601), who -in turn notes that "we can set ... the Wilson coefficients ``C_{\mathrm{ES}^2} = +in turn note that "we can set ... the Wilson coefficients ``C_{\mathrm{ES}^2} = C_{\mathrm{BS}^3} = 1`` for the black hole case." However, a very similar constant ``\kappa_A`` is used in Eq. (2.1) of [Buonanno et al. @@ -173,7 +173,7 @@ See also [`λ₁`](@ref). quantity may also be related to [`λ₁`](@ref). Pull requests or issues with more information are welcome. """ -function κ₁(s::VecOrPNSystem) +@public function κ₁(s::PNSystem) return 1 end @@ -183,7 +183,7 @@ end The "quadrupolar polarisability" of object 2 used by [Bohé et al. (2015)](https://arxiv.org/abs/1501.01529). See [`κ₁`](@ref) for more details. """ -function κ₂(s::VecOrPNSystem) +@public function κ₂(s::PNSystem) return 1 end @@ -193,7 +193,7 @@ end Equal to [`κ₁`](@ref)` + `[`κ₂`](@ref); defined below Eq. (3.28) of [Bohé et al. (2015)](https://arxiv.org/abs/1501.01529). """ -function κ₊(s::VecOrPNSystem) +@public function κ₊(s::PNSystem) return κ₁(s) + κ₂(s) end @@ -203,7 +203,7 @@ end Equal to [`κ₁`](@ref)` - `[`κ₂`](@ref); defined below Eq. (3.28) of [Bohé et al. (2015)](https://arxiv.org/abs/1501.01529). """ -function κ₋(s::VecOrPNSystem) +@public function κ₋(s::PNSystem) return κ₁(s) - κ₂(s) end @@ -212,8 +212,8 @@ end The "quadrupolar polarisability" of object 1 used by [Marsat (2014)](https://arxiv.org/abs/1411.4118), who notes above Eq. (4.11) that this is denoted -``C_{\mathrm{BS}^2}`` in [Levi and Steinhoff (2014)](https://arxiv.org/abs/1410.2601), who -in turn notes that "we can set ... the Wilson coefficients ``C_{\mathrm{ES}^2} = +``C_{\mathrm{BS}^3}`` in [Levi and Steinhoff (2014)](https://arxiv.org/abs/1410.2601), who +in turn note that "we can set ... the Wilson coefficients ``C_{\mathrm{ES}^2} = C_{\mathrm{BS}^3} = 1`` for the black hole case." See also [`κ₁`](@ref). @@ -226,7 +226,7 @@ See also [`κ₁`](@ref). quantity may also be related to [`λ₁`](@ref). Pull requests or issues with more information are welcome. """ -function λ₁(s::VecOrPNSystem) +@public function λ₁(s::PNSystem) return 1 end @@ -236,7 +236,7 @@ end The "quadrupolar polarisability" of object 2 used by [Bohé et al. (2015)](https://arxiv.org/abs/1501.01529). See [`λ₁`](@ref) for more details. """ -function λ₂(s::VecOrPNSystem) +@public function λ₂(s::PNSystem) return 1 end @@ -246,7 +246,7 @@ end Equal to [`λ₁`](@ref)` + `[`λ₂`](@ref); defined below Eq. (3.28) of [Bohé et al. (2015)](https://arxiv.org/abs/1501.01529). """ -function λ₊(s::VecOrPNSystem) +@public function λ₊(s::PNSystem) return λ₁(s) + λ₂(s) end @@ -256,6 +256,6 @@ end Equal to [`λ₁`](@ref)` - `[`λ₂`](@ref); defined below Eq. (3.28) of [Bohé et al. (2015)](https://arxiv.org/abs/1501.01529). """ -function λ₋(s::VecOrPNSystem) +@public function λ₋(s::PNSystem) return λ₁(s) - λ₂(s) end diff --git a/src/derived_variables/mass_combinations.jl b/src/literature/common_variables/mass_combinations.jl similarity index 65% rename from src/derived_variables/mass_combinations.jl rename to src/literature/common_variables/mass_combinations.jl index 95044df1..30cef306 100644 --- a/src/derived_variables/mass_combinations.jl +++ b/src/literature/common_variables/mass_combinations.jl @@ -6,9 +6,9 @@ Compute the total mass ``M₁+M₂``. """ -M(M₁, M₂) = M₁ + M₂ -M(s::VecOrPNSystem) = M(M₁(s), M₂(s)) -const total_mass = M +@public M(M₁, M₂) = M₁ + M₂ +M(s::PNSystem) = M(M₁(s), M₂(s)) +@public const total_mass = M """ μ(pnsystem) @@ -18,9 +18,9 @@ const total_mass = M Compute the reduced mass ``(M₁ M₂)/(M₁+M₂)``. """ -μ(M₁, M₂) = (M₁ * M₂) / (M₁ + M₂) -μ(s::VecOrPNSystem) = μ(M₁(s), M₂(s)) -const reduced_mass = μ +@public μ(M₁, M₂) = (M₁ * M₂) / (M₁ + M₂) +μ(s::PNSystem) = μ(M₁(s), M₂(s)) +@public const reduced_mass = μ """ ν(pnsystem) @@ -32,10 +32,10 @@ Compute the reduced mass ratio ``(M₁ M₂)/(M₁+M₂)^2``. Note that the denominator is squared, unlike in the reduced mass [`μ`](@ref). """ -ν(M₁, M₂) = (M₁ * M₂) / (M₁ + M₂)^2 -ν(s::VecOrPNSystem) = ν(M₁(s), M₂(s)) +@public ν(M₁, M₂) = (M₁ * M₂) / (M₁ + M₂)^2 +ν(s::PNSystem) = ν(M₁(s), M₂(s)) ν(; q) = q / (1 + q)^2 -const reduced_mass_ratio = ν +@public const reduced_mass_ratio = ν """ δ(pnsystem) @@ -48,10 +48,10 @@ Compute mass-difference ratio ``(M₁-M₂)/(M₁+M₂)``. Note that we do not restrict to ``M₁ ≥ M₂`` or vice versa; if you prefer that ``δ`` always be positive (or always negative), you are responsible for ensuring that. """ -δ(M₁, M₂) = (M₁ - M₂) / (M₁ + M₂) -δ(s::VecOrPNSystem) = δ(M₁(s), M₂(s)) +@public δ(M₁, M₂) = (M₁ - M₂) / (M₁ + M₂) +δ(s::PNSystem) = δ(M₁(s), M₂(s)) δ(; q) = (q - 1) / (q + 1) -const mass_difference_ratio = δ +@public const mass_difference_ratio = δ """ q(pnsystem) @@ -64,9 +64,9 @@ Compute mass ratio ``M₁/M₂``. Note that we do not restrict to ``M₁ ≥ M₂`` or vice versa; if you prefer that ``q`` always be greater than or equal to 1 (or vice versa), you are responsible for ensuring that. """ -q(M₁, M₂) = M₁ / M₂ -q(s::VecOrPNSystem) = q(M₁(s), M₂(s)) -const mass_ratio = q +@public q(M₁, M₂) = M₁ / M₂ +q(s::PNSystem) = q(M₁(s), M₂(s)) +@public const mass_ratio = q """ ℳ(pnsystem) @@ -82,9 +82,9 @@ The chirp mass is defined as \\mathcal{M} = \\frac{(M_1 M_2)^{3/5}} {(M_1 + M_2)^{1/5}}. ``` """ -ℳ(M₁, M₂) = ((M₁ * M₂)^3 / (M₁ + M₂))^(1//5) -ℳ(s::VecOrPNSystem) = ℳ(M₁(s), M₂(s)) -const chirp_mass = ℳ +@public ℳ(M₁, M₂) = ((M₁ * M₂)^3 / (M₁ + M₂))^(1//5) +ℳ(s::PNSystem) = ℳ(M₁(s), M₂(s)) +@public const chirp_mass = ℳ """ X₁(pnsystem) @@ -94,9 +94,9 @@ const chirp_mass = ℳ Compute the reduced *individual* mass ``M₁/(M₁+M₂)``. """ -X₁(M₁, M₂) = M₁ / (M₁ + M₂) -X₁(s::VecOrPNSystem) = X₁(M₁(s), M₂(s)) -const X1 = X₁ +@public X₁(M₁, M₂) = M₁ / (M₁ + M₂) +X₁(s::PNSystem) = X₁(M₁(s), M₂(s)) +@public const X1 = X₁ """ X₂(pnsystem) @@ -106,6 +106,6 @@ const X1 = X₁ Compute the reduced *individual* mass ``M₂/(M₁+M₂)``. """ -X₂(M₁, M₂) = M₂ / (M₁ + M₂) -X₂(s::VecOrPNSystem) = X₂(M₁(s), M₂(s)) -const X2 = X₂ +@public X₂(M₁, M₂) = M₂ / (M₁ + M₂) +X₂(s::PNSystem) = X₂(M₁(s), M₂(s)) +@public const X2 = X₂ diff --git a/src/derived_variables/orbital_elements.jl b/src/literature/common_variables/orbital_elements.jl similarity index 59% rename from src/derived_variables/orbital_elements.jl rename to src/literature/common_variables/orbital_elements.jl index d0e24064..29829896 100644 --- a/src/derived_variables/orbital_elements.jl +++ b/src/literature/common_variables/orbital_elements.jl @@ -10,9 +10,9 @@ The unit vector pointing from object 2 to object 1, when the frame is given by t n̂(R) = R x̂ R̄ ``` """ -n̂(R) = QuatVec(R(𝐢)) -n̂(s::VecOrPNSystem) = n̂(R(s)) -const n_hat = n̂ +@public n̂(R) = QuatVec(R(𝐢)) +n̂(s::PNSystem) = n̂(R(s)) +@public const n_hat = n̂ """ λ̂(pnsystem) @@ -27,9 +27,9 @@ the frame is given by the rotor `R`. This is equal to ``` This also completes the right-handed triple of ``(n̂, λ̂, ℓ̂)``. """ -λ̂(R) = QuatVec(R(𝐣)) -λ̂(s::VecOrPNSystem) = λ̂(R(s)) -const lambda_hat = λ̂ +@public λ̂(R) = QuatVec(R(𝐣)) +λ̂(s::PNSystem) = λ̂(R(s)) +@public const lambda_hat = λ̂ """ ℓ̂(pnsystem) @@ -43,9 +43,9 @@ given by the rotor `R`. This is equal to ℓ̂(R) = R ẑ R̄ ``` """ -ℓ̂(R) = QuatVec(R(𝐤)) -ℓ̂(s::VecOrPNSystem) = ℓ̂(R(s)) -const ell_hat = ℓ̂ +@public ℓ̂(R) = QuatVec(R(𝐤)) +ℓ̂(s::PNSystem) = ℓ̂(R(s)) +@public const ell_hat = ℓ̂ @doc raw""" Ω(pnsystem) @@ -63,8 +63,22 @@ definition* as ``` See also [`v`](@ref). """ -Ω(; v, M=1) = v^3 / M -Ω(s::VecOrPNSystem) = Ω(; v=v(s), M=M(s)) -const Omega = Ω +@public Ω(; v, M=1) = v^3 / M +Ω(s::PNSystem) = Ω(; v=v(s), M=M(s)) +@public const Omega = Ω -lnv(s::VecOrPNSystem) = ln(v(s)) +@doc raw""" + x(pnsystem) + x(;v, M=1) + +The "frequency-related parameter" defined in Eq. (375) of [Blanchet2024](@cite) as +```math +x \colonequals \left(\frac{Gm\Omega}{c^3}\right)^{2/3} +``` +where `m` is the total mass of the binary, and `Ω` is the orbital angular frequency. +This is related to the PN velocity parameter `v` as +```math +x = \left(\frac{v}{c}\right)^{2}. +``` +""" +@public x(s::PNSystem) = (v(s)/c(s))^2 diff --git a/src/derived_variables/spin_combinations.jl b/src/literature/common_variables/spin_combinations.jl similarity index 59% rename from src/derived_variables/spin_combinations.jl rename to src/literature/common_variables/spin_combinations.jl index e36b5cbe..42952dd3 100644 --- a/src/derived_variables/spin_combinations.jl +++ b/src/literature/common_variables/spin_combinations.jl @@ -3,14 +3,14 @@ Dimensionful spin vector of object 1. """ -S⃗₁(s::VecOrPNSystem) = χ⃗₁(s) * M₁(s)^2 +@public S⃗₁(s::PNSystem) = χ⃗₁(s) * M₁(s)^2 """ S⃗₂(pnsystem) Dimensionful spin vector of object 2. """ -S⃗₂(s::VecOrPNSystem) = χ⃗₂(s) * M₂(s)^2 +@public S⃗₂(s::PNSystem) = χ⃗₂(s) * M₂(s)^2 """ S⃗(pnsystem) @@ -18,8 +18,8 @@ S⃗₂(s::VecOrPNSystem) = χ⃗₂(s) * M₂(s)^2 Total (dimensionful) spin vector ``S⃗₁+S⃗₂``. """ -S⃗(M₁, M₂, χ⃗₁, χ⃗₂) = χ⃗₁ * M₁^2 + χ⃗₂ * M₂^2 -S⃗(s::VecOrPNSystem) = S⃗(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) +@public S⃗(M₁, M₂, χ⃗₁, χ⃗₂) = χ⃗₁ * M₁^2 + χ⃗₂ * M₂^2 +S⃗(s::PNSystem) = S⃗(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) """ Σ⃗(pnsystem) @@ -27,8 +27,8 @@ S⃗(s::VecOrPNSystem) = S⃗(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) Differential spin vector ``M(a⃗₂-a⃗₁)``. """ -Σ⃗(M₁, M₂, χ⃗₁, χ⃗₂) = (M₁ + M₂) * (χ⃗₂ * M₂ - χ⃗₁ * M₁) -Σ⃗(s::VecOrPNSystem) = Σ⃗(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) +@public Σ⃗(M₁, M₂, χ⃗₁, χ⃗₂) = (M₁ + M₂) * (χ⃗₂ * M₂ - χ⃗₁ * M₁) +Σ⃗(s::PNSystem) = Σ⃗(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) """ χ⃗(pnsystem) @@ -36,29 +36,29 @@ Differential spin vector ``M(a⃗₂-a⃗₁)``. Normalized spin vector ``S⃗/M²``. """ -χ⃗(S⃗, M) = S⃗ / M^2 -χ⃗(s::VecOrPNSystem) = χ⃗(S⃗(s), M(s)) +@public χ⃗(S⃗, M) = S⃗ / M^2 +χ⃗(s::PNSystem) = χ⃗(S⃗(s), M(s)) """ χ⃗ₛ(M₁, M₂, χ⃗₁, χ⃗₂) Symmetric spin vector ``(χ⃗₁+χ⃗₂)/2``. """ -χ⃗ₛ(χ⃗₁, χ⃗₂) = (χ⃗₁ + χ⃗₂) / 2 +@public χ⃗ₛ(χ⃗₁, χ⃗₂) = (χ⃗₁ + χ⃗₂) / 2 χ⃗ₛ(M₁, M₂, χ⃗₁, χ⃗₂) = (χ⃗₁ + χ⃗₂) / 2 -χ⃗ₛ(s::VecOrPNSystem) = χ⃗ₛ(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) +χ⃗ₛ(s::PNSystem) = χ⃗ₛ(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) """ χ⃗ₐ(M₁, M₂, χ⃗₁, χ⃗₂) Antisymmetric spin vector ``(χ⃗₁-χ⃗₂)/2``. """ -χ⃗ₐ(χ⃗₁, χ⃗₂) = (χ⃗₁ - χ⃗₂) / 2 +@public χ⃗ₐ(χ⃗₁, χ⃗₂) = (χ⃗₁ - χ⃗₂) / 2 χ⃗ₐ(M₁, M₂, χ⃗₁, χ⃗₂) = (χ⃗₁ - χ⃗₂) / 2 -χ⃗ₐ(s::VecOrPNSystem) = χ⃗ₐ(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) +χ⃗ₐ(s::PNSystem) = χ⃗ₐ(M₁(s), M₂(s), χ⃗₁(s), χ⃗₂(s)) -χₚₑᵣₚ(s::VecOrPNSystem) = √(χ₁²(s) - (χ₁ₗ(s))^2 + χ₂²(s) - (χ₂ₗ(s))^2) -const chi_perp = χₚₑᵣₚ +@public χₚₑᵣₚ(s::PNSystem) = √(χ₁²(s) - (χ₁ₗ(s))^2 + χ₂²(s) - (χ₂ₗ(s))^2) +@public const chi_perp = χₚₑᵣₚ @doc raw""" χₑ(s) @@ -74,10 +74,8 @@ Defined as \right) \cdot \frac{\hat{\mathbf{L}}_{\mathrm{N}}} {M}. ``` """ -function χₑ(s::VecOrPNSystem) - return (S₁ₗ(s) / M₁(s) + S₂ₗ(s) / M₂(s)) / M(s) -end -const chi_eff = χₑ +@public χₑ(s::PNSystem) = (S₁ₗ(s) / M₁(s) + S₂ₗ(s) / M₂(s)) / M(s) +@public const chi_eff = χₑ @doc raw""" χₚ(s) @@ -112,7 +110,7 @@ convention. Because it seems to be the trend, this function uses the latter definition. """ -function χₚ(s::VecOrPNSystem) +@public function χₚ(s::PNSystem) χ₁ₚₑᵣₚ = √(χ₁ₙ(s)^2 + χ₁λ(s)^2) χ₂ₚₑᵣₚ = √(χ₂ₙ(s)^2 + χ₂λ(s)^2) let q = 1 / q(s) # This is to convert to LVK's convention @@ -152,16 +150,16 @@ the case for black holes. You can define `κ₁` and `κ₂` to have other valu See also [`S⃗₀⁻`](@ref). """ -S⃗₀⁺(s::VecOrPNSystem) = S⃗₀⁺(M₁(s), M₂(s), κ₁(s), κ₂(s), S⃗₁(s), S⃗₂(s)) +@public S⃗₀⁺(s::PNSystem) = S⃗₀⁺(M₁(s), M₂(s), κ₁(s), κ₂(s), S⃗₁(s), S⃗₂(s)) function S⃗₀⁺(M₁, M₂, κ₁, κ₂, S⃗₁, S⃗₂) M = M₁ + M₂ κᵣ = (κ₁ / κ₂)^(1//4) return (M / M₁) * κᵣ * √(1 + √(1 - κ₁ * κ₂)) * S⃗₁ + (M / M₂) / κᵣ * √(1 - √(1 - κ₁ * κ₂)) * S⃗₂ end -S₀⁺ₙ(s::VecOrPNSystem) = S⃗₀⁺(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁ₙ(s), S₂ₙ(s)) -S₀⁺λ(s::VecOrPNSystem) = S⃗₀⁺(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁λ(s), S₂λ(s)) -S₀⁺ₗ(s::VecOrPNSystem) = S⃗₀⁺(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁ₗ(s), S₂ₗ(s)) +@public S₀⁺ₙ(s::PNSystem) = S⃗₀⁺(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁ₙ(s), S₂ₙ(s)) +@public S₀⁺λ(s::PNSystem) = S⃗₀⁺(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁λ(s), S₂λ(s)) +@public S₀⁺ₗ(s::PNSystem) = S⃗₀⁺(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁ₗ(s), S₂ₗ(s)) @doc raw""" S⃗₀⁻(s) @@ -181,38 +179,38 @@ the case for black holes. You can define `κ₁` and `κ₂` to have other valu See also [`S⃗₀⁺`](@ref). """ -S⃗₀⁻(s::VecOrPNSystem) = S⃗₀⁻(M₁(s), M₂(s), κ₁(s), κ₂(s), S⃗₁(s), S⃗₂(s)) +@public S⃗₀⁻(s::PNSystem) = S⃗₀⁻(M₁(s), M₂(s), κ₁(s), κ₂(s), S⃗₁(s), S⃗₂(s)) S⃗₀⁻(M₁, M₂, κ₁, κ₂, S⃗₁, S⃗₂) = S⃗₀⁺(M₂, M₁, κ₂, κ₁, S⃗₂, S⃗₁) -S₀⁻ₙ(s::VecOrPNSystem) = S⃗₀⁻(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁ₙ(s), S₂ₙ(s)) -S₀⁻λ(s::VecOrPNSystem) = S⃗₀⁻(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁λ(s), S₂λ(s)) -S₀⁻ₗ(s::VecOrPNSystem) = S⃗₀⁻(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁ₗ(s), S₂ₗ(s)) - -χ₁²(s::VecOrPNSystem) = abs2vec(χ⃗₁(s)) -χ₂²(s::VecOrPNSystem) = abs2vec(χ⃗₂(s)) -χ₁(s::VecOrPNSystem) = absvec(χ⃗₁(s)) -χ₂(s::VecOrPNSystem) = absvec(χ⃗₂(s)) -χ₁₂(s::VecOrPNSystem) = χ⃗₁(s) ⋅ χ⃗₂(s) -χₛₗ(s::VecOrPNSystem) = χ⃗ₛ(s) ⋅ ℓ̂(s) -χₐₗ(s::VecOrPNSystem) = χ⃗ₐ(s) ⋅ ℓ̂(s) -χ₁ₙ(s::VecOrPNSystem) = χ⃗₁(s) ⋅ n̂(s) -χ₁λ(s::VecOrPNSystem) = χ⃗₁(s) ⋅ λ̂(s) -χ₁ₗ(s::VecOrPNSystem) = χ⃗₁(s) ⋅ ℓ̂(s) -χ₂ₙ(s::VecOrPNSystem) = χ⃗₂(s) ⋅ n̂(s) -χ₂λ(s::VecOrPNSystem) = χ⃗₂(s) ⋅ λ̂(s) -χ₂ₗ(s::VecOrPNSystem) = χ⃗₂(s) ⋅ ℓ̂(s) - -Sₙ(s::VecOrPNSystem) = S⃗(s) ⋅ n̂(s) -Σₙ(s::VecOrPNSystem) = Σ⃗(s) ⋅ n̂(s) -Sλ(s::VecOrPNSystem) = S⃗(s) ⋅ λ̂(s) -Σλ(s::VecOrPNSystem) = Σ⃗(s) ⋅ λ̂(s) -Sₗ(s::VecOrPNSystem) = S⃗(s) ⋅ ℓ̂(s) -Σₗ(s::VecOrPNSystem) = Σ⃗(s) ⋅ ℓ̂(s) -sₗ(s::VecOrPNSystem) = S⃗(s) ⋅ ℓ̂(s) / M(s)^2 -σₗ(s::VecOrPNSystem) = Σ⃗(s) ⋅ ℓ̂(s) / M(s)^2 - -S₁ₙ(s::VecOrPNSystem) = S⃗₁(s) ⋅ n̂(s) -S₁λ(s::VecOrPNSystem) = S⃗₁(s) ⋅ λ̂(s) -S₁ₗ(s::VecOrPNSystem) = S⃗₁(s) ⋅ ℓ̂(s) -S₂ₙ(s::VecOrPNSystem) = S⃗₂(s) ⋅ n̂(s) -S₂λ(s::VecOrPNSystem) = S⃗₂(s) ⋅ λ̂(s) -S₂ₗ(s::VecOrPNSystem) = S⃗₂(s) ⋅ ℓ̂(s) +@public S₀⁻ₙ(s::PNSystem) = S⃗₀⁻(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁ₙ(s), S₂ₙ(s)) +@public S₀⁻λ(s::PNSystem) = S⃗₀⁻(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁λ(s), S₂λ(s)) +@public S₀⁻ₗ(s::PNSystem) = S⃗₀⁻(M₁(s), M₂(s), κ₁(s), κ₂(s), S₁ₗ(s), S₂ₗ(s)) + +@public χ₁²(s::PNSystem) = abs2vec(χ⃗₁(s)) +@public χ₂²(s::PNSystem) = abs2vec(χ⃗₂(s)) +@public χ₁(s::PNSystem) = absvec(χ⃗₁(s)) +@public χ₂(s::PNSystem) = absvec(χ⃗₂(s)) +@public χ₁₂(s::PNSystem) = χ⃗₁(s) ⋅ χ⃗₂(s) +@public χₛₗ(s::PNSystem) = χ⃗ₛ(s) ⋅ ℓ̂(s) +@public χₐₗ(s::PNSystem) = χ⃗ₐ(s) ⋅ ℓ̂(s) +@public χ₁ₙ(s::PNSystem) = χ⃗₁(s) ⋅ n̂(s) +@public χ₁λ(s::PNSystem) = χ⃗₁(s) ⋅ λ̂(s) +@public χ₁ₗ(s::PNSystem) = χ⃗₁(s) ⋅ ℓ̂(s) +@public χ₂ₙ(s::PNSystem) = χ⃗₂(s) ⋅ n̂(s) +@public χ₂λ(s::PNSystem) = χ⃗₂(s) ⋅ λ̂(s) +@public χ₂ₗ(s::PNSystem) = χ⃗₂(s) ⋅ ℓ̂(s) + +@public Sₙ(s::PNSystem) = S⃗(s) ⋅ n̂(s) +@public Σₙ(s::PNSystem) = Σ⃗(s) ⋅ n̂(s) +@public Sλ(s::PNSystem) = S⃗(s) ⋅ λ̂(s) +@public Σλ(s::PNSystem) = Σ⃗(s) ⋅ λ̂(s) +@public Sₗ(s::PNSystem) = S⃗(s) ⋅ ℓ̂(s) +@public Σₗ(s::PNSystem) = Σ⃗(s) ⋅ ℓ̂(s) +@public sₗ(s::PNSystem) = S⃗(s) ⋅ ℓ̂(s) / M(s)^2 +@public σₗ(s::PNSystem) = Σ⃗(s) ⋅ ℓ̂(s) / M(s)^2 + +@public S₁ₙ(s::PNSystem) = S⃗₁(s) ⋅ n̂(s) +@public S₁λ(s::PNSystem) = S⃗₁(s) ⋅ λ̂(s) +@public S₁ₗ(s::PNSystem) = S⃗₁(s) ⋅ ℓ̂(s) +@public S₂ₙ(s::PNSystem) = S⃗₂(s) ⋅ n̂(s) +@public S₂λ(s::PNSystem) = S⃗₂(s) ⋅ λ̂(s) +@public S₂ₗ(s::PNSystem) = S⃗₂(s) ⋅ ℓ̂(s) diff --git a/src/derived_variables/tidal_coupling.jl b/src/literature/common_variables/tidal_coupling.jl similarity index 92% rename from src/derived_variables/tidal_coupling.jl rename to src/literature/common_variables/tidal_coupling.jl index 211306a6..ff172f23 100644 --- a/src/derived_variables/tidal_coupling.jl +++ b/src/literature/common_variables/tidal_coupling.jl @@ -16,7 +16,7 @@ tidal couplings ``\Lambda_1`` and ``\Lambda_2`` of the two components. See also [`Λ₁`](@ref) and [`Λ₂`](@ref). """ -Λ̃(s::VecOrPNSystem) = +@public Λ̃(s::PNSystem) = 16//13 * ((M₁(s) + 12M₂(s)) * M₁(s)^4 * Λ₁(s) + (M₂(s) + 12M₁(s)) * M₂(s)^4 * Λ₂(s)) / M(s)^5 -const Lambda_tilde = Λ̃ +@public const Lambda_tilde = Λ̃ diff --git a/src/literature/literature.jl b/src/literature/literature.jl new file mode 100644 index 00000000..2775b895 --- /dev/null +++ b/src/literature/literature.jl @@ -0,0 +1,13 @@ +# These files define functions encapsulating common variables used throughout the +# literature. Note that not every reference uses these conventions, which is why +# they must be explicitly imported to be used by `@pn_reference` modules. +include("common_variables/horizons.jl") +include("common_variables/mass_combinations.jl") +include("common_variables/orbital_elements.jl") +include("common_variables/spin_combinations.jl") +include("common_variables/tidal_coupling.jl") + +# Now we include the `@pn_reference` modules themselves, named by the bibtex keys we use for +# them in ``../references.bib`. +#include("Einstein1918.jl") +include("Blanchet2024.jl") diff --git a/src/pn_expressions.jl b/src/pn_expressions.jl deleted file mode 100644 index 5ab622e6..00000000 --- a/src/pn_expressions.jl +++ /dev/null @@ -1,7 +0,0 @@ -include("utilities/macros.jl") -include("pn_expressions/flux.jl") -include("pn_expressions/tidal_heating.jl") -include("pn_expressions/binding_energy.jl") -include("pn_expressions/separation.jl") -include("pn_expressions/precession.jl") -include("pn_expressions/mode_weights.jl") diff --git a/src/pn_expressions/angular_momentum.jl b/src/pn_expressions/angular_momentum.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/pn_expressions/angular_momentum.jl @@ -0,0 +1 @@ + diff --git a/src/pn_expressions/binding_energy.jl b/src/pn_expressions/binding_energy.jl index f93f394d..8a4374e3 100644 --- a/src/pn_expressions/binding_energy.jl +++ b/src/pn_expressions/binding_energy.jl @@ -56,7 +56,7 @@ overall factor is used, leading to a sign difference. 77ν^4 / 31104 + 301ν^3 / 1728 + (-498449//3456 + 3157π^2 / 576)ν^2 + - (-123671//5760 + 1792ln2 / 15 + 9037π^2 / 1536 + 896γₑ / 15)ν + + (-123671//5760 + 1792ln(2) / 15 + 9037π^2 / 1536 + 896γₑ / 15)ν + 2ln(v) * (448ν / 15) ) @@ -67,9 +67,9 @@ overall factor is used, leading to a sign difference. ν^5 / 512 + 55ν^4 / 512 + (-1353π^2 / 256 + 69423//512)ν^3 + - (-21337π^2 / 1024 + 3a₆ᶜ¹ - 896ln2 / 5 - 448γₑ / 5 + 893429//2880)ν^2 + + (-21337π^2 / 1024 + 3a₆ᶜ¹ - 896ln(2) / 5 - 448γₑ / 5 + 893429//2880)ν^2 + ( - -228916843//115200 - 9976γₑ / 35 + 729ln3 / 7 - 23672ln2 / 35 + + -228916843//115200 - 9976γₑ / 35 + 729ln(3) / 7 - 23672ln(2) / 35 + 126779π^2 / 512 )ν + 2ln(v) * (-4988ν / 35 - 656ν^2 / 5) @@ -82,19 +82,19 @@ overall factor is used, leading to a sign difference. (272855π^2 / 124416 - 20543435//373248)ν^4 + ( 1232γₑ / 27 + 6634243π^2 / 110592 - 11a₆ᶜ¹ / 2 - 71700787//51840 + - 2464ln2 / 27 + 2464ln(2) / 27 )ν^3 + ( 113176680983//14515200 + 18491π^4 / 2304 + - 246004ln2 / 105 + + 246004ln(2) / 105 + 112772γₑ / 105 + a₆ᶜ¹ * 11//2 + a₇ˡⁿ¹ * 2//3 + - a₇ᶜ¹ * 11//3 - 86017789π^2 / 110592 - 2673ln3 / 14 + a₇ᶜ¹ * 11//3 - 86017789π^2 / 110592 - 2673ln(3) / 14 )ν^2 + ( - -389727504721//43545600 + 74888ln2 / 243 - 7128ln3 / 7 - + -389727504721//43545600 + 74888ln(2) / 243 - 7128ln(3) / 7 - 30809603π^4 / 786432 - 3934568γₑ / 8505 + 9118627045π^2 / 5308416 )ν + 2ln(v) * @@ -220,7 +220,7 @@ function 𝓔′code( ) 𝓔′statements[end] = 𝓔′return - if PNExpansionReducer === identity + if PNExpansionReducer ≡ identity # When `pn_expansion_reducer=Val(identity)` is passed, we return a PNExpansion NMax = Int(2PNOrder + 1) return quote diff --git a/src/pn_expressions/dynamics.jl b/src/pn_expressions/dynamics.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/pn_expressions/dynamics.jl @@ -0,0 +1 @@ + diff --git a/src/pn_expressions/flux.jl b/src/pn_expressions/flux.jl index 000c74ac..54eef84a 100644 --- a/src/pn_expressions/flux.jl +++ b/src/pn_expressions/flux.jl @@ -39,20 +39,21 @@ overall factor is used, leading to a sign difference. (v / c)^2 * (-1247//336 - 35ν / 12) + (v / c)^3 * (4π) + (v / c)^4 * (-44711//9072 + 9271ν / 504 + 65ν^2 / 18) + - (v / c)^5 * ((-8191//672 - 583 * ν / 24)π) + + (v / c)^5 * ((-8191//672 - 583ν / 24)π) + (v / c)^6 * ( - 6643739519//69854400 + 16π^2 / 3 - 1712 * (γₑ + 2ln2 + ln(v)) / 105 + - (-134543//7776 + 41π^2 / 48)ν - 94403ν^2 / 3024 - 775ν^3 / 324 + 6643739519//69854400 + 16π^2 / 3 - + 1712 * (γₑ + 2ln(2) + ln(v)) / 105 + (-134543//7776 + 41π^2 / 48)ν - + 94403ν^2 / 3024 - 775ν^3 / 324 ) + (v / c)^7 * ((-16285//504 + 214745ν / 1728 + 193385ν^2 / 3024)π) + (v / c)^8 * ( -323105549467//3178375200 + 232597γₑ / 4410 - 1369π^2 / 126 + - 39931ln2 / 294 - 47385ln3 / 1568 + + 39931ln(2) / 294 - 47385ln(3) / 1568 + 232597ln(v) / 4410 + ( -1452202403629//1466942400 + 41478γₑ / 245 - 267127π^2 / 4608 + - 479062ln2 / 2205 + - 47385ln3 / 392 + + 479062ln(2) / 2205 + + 47385ln(3) / 392 + 41478ln(v) / 245 )ν + (1607125//6804 - 3157π^2 / 384)ν^2 + @@ -61,7 +62,7 @@ overall factor is used, leading to a sign difference. ) + (v / c)^9 * ( ( - 265978667519//745113600 - 6848 * (γₑ + 2ln2 + ln(v)) / 105 + + 265978667519//745113600 - 6848 * (γₑ + 2ln(2) + ln(v)) / 105 + (2062241//22176 + 41π^2 / 12)ν - 133112905ν^2 / 290304 - 3719141ν^3 / 38016 )π @@ -129,32 +130,32 @@ overall factor is used, leading to a sign difference. + (v / c)^10 * ( -2500861660823683//2831932303200 - 424223π^2 / 6804 - - 83217611ln2 / 1122660 + + 83217611ln(2) / 1122660 + 916628467γₑ / 7858620 + - 47385ln3 / 196 + + 47385ln(3) / 196 + 916628467ln(v) / 7858620 ) + (v / c)^11 * ( - -142155π * ln3 / 784 + + -142155π * ln(3) / 784 + 8399309750401π / 101708006400 + 177293γₑ * π / 1176 + - 8521283π * ln2 / 17640 + + 8521283π * ln(2) / 17640 + 177293π * ln(v) / 1176 ) + (v / c)^12 * ( - -271272899815409ln2 / 157329572400 - 54784π^2 * ln2 / 315 - - 246137536815857γₑ / 157329572400 - 437114506833ln3 / 789268480 - + -271272899815409ln(2) / 157329572400 - 54784π^2 * ln(2) / 315 - + 246137536815857γₑ / 157329572400 - 437114506833ln(3) / 789268480 - 256π^4 / 45 - 27392γₑ * π^2 / 315 - 27392ζ3 / 105 - - 37744140625ln5 / 260941824 + + 37744140625ln(5) / 260941824 + 1465472γₑ^2 / 11025 + - 5861888γₑ * ln2 / 11025 + - 5861888ln2^2 / 11025 + + 5861888γₑ * ln(2) / 11025 + + 5861888ln(2)^2 / 11025 + 2067586193789233570693//602387400044430000 + 3803225263π^2 / 10478160 + ln(v) * ( -246137536815857//157329572400 - 27392π^2 / 315 + 2930944γₑ / 11025 + - 5861888ln2 / 11025 + + 5861888ln(2) / 11025 + 1465472ln(v) / 11025 ) ) diff --git a/src/pn_expressions/mode_weights.jl b/src/pn_expressions/mode_weights.jl index c6187197..531e5f23 100644 --- a/src/pn_expressions/mode_weights.jl +++ b/src/pn_expressions/mode_weights.jl @@ -63,9 +63,9 @@ is from Eq. (4.15) of that reference. h[Yindex(2,1,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^1 * (𝒾 * δ / 3) + (v/c)^3 * (𝒾 * δ * (-17 + 20ν) / 84) - + (v/c)^4 * ((δ * (1 + 2𝒾*π + 4ln2)) / 6) + + (v/c)^4 * ((δ * (1 + 2𝒾*π + 4ln(2))) / 6) + (v/c)^5 * (𝒾 * δ * (-172 + ν * (-2036 + 237ν)) / 1512) - + (v/c)^6 * (δ*(-34𝒾*π - 17*(1 + 4ln2) + 2ν * (353 + 6𝒾*π + 12ln2)) / 168) + + (v/c)^6 * (δ*(-34𝒾*π - 17*(1 + 4ln(2)) + 2ν * (353 + 6𝒾*π + 12ln(2))) / 168) ) h[Yindex(2,2,ℓₘᵢₙ)] = h₀ * @pn_expansion( 1 @@ -75,14 +75,14 @@ is from Eq. (4.15) of that reference. + (v/c)^5 * (-24𝒾*ν + ((-107 + 34ν)π) / 21) + (v/c)^6 * ( (27027409//646800) - 856γₑ/105 + (ν*(-834555 + ν*(-729396 + 114635ν))) / 99792 - + 41ν * π^2 / 96 + (2π*(214𝒾 + 35π))/105 - 1712ln2/105 + + 41ν * π^2 / 96 + (2π*(214𝒾 + 35π))/105 - 1712ln(2)/105 - (856//105)*ln(v) ) + (v/c)^7 * ((-2𝒾 * ν * (-501655 + 24396ν) + 15*(-2173 + 2ν*(-2459 + 560ν))π) / 11340) # Eq. (6.17) of Blanchet et al. (2023) + (v/c)^8 * ( - - 846557506853//12713500800 + 45796γₑ/2205 - 22898𝒾*π/2205 - 107π^2/63 + 45796(2ln2+ln(v))/2205 - + (-336005827477//4237833600 + 15284γₑ/441 - 219314𝒾*π/2205 - 9755*π^2/32256 + 15284(2ln2+ln(v))/441)ν + - 846557506853//12713500800 + 45796γₑ/2205 - 22898𝒾*π/2205 - 107π^2/63 + 45796(2ln(2)+ln(v))/2205 + + (-336005827477//4237833600 + 15284γₑ/441 - 219314𝒾*π/2205 - 9755*π^2/32256 + 15284(2ln(2)+ln(v))/441)ν + (256450291//7413120 - 1025*π^2/1008)ν^2 - 81579187ν^3/15567552 + 26251249ν^4/31135104 ) ) @@ -94,15 +94,15 @@ is from Eq. (4.15) of that reference. h[Yindex(3,1,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^1 * (𝒾 * δ / 12√14) + (v/c)^3 * (-𝒾 * δ * (4 + ν) / 18√14) - + (v/c)^4 * (δ * (7 + 5𝒾*π + 10ln2) / 60√14) + + (v/c)^4 * (δ * (7 + 5𝒾*π + 10ln(2)) / 60√14) + (v/c)^5 * (-𝒾 * δ * (-607 + ν*(272 + 247ν)) / 2376√14) + (v/c)^6 * ( - δ * (-5𝒾 * (16 + 7ν)π + 2*(-56 + ν - 5*(16 + 7ν)*ln2)) / 360√14 + δ * (-5𝒾 * (16 + 7ν)π + 2*(-56 + ν - 5*(16 + 7ν)*ln(2))) / 360√14 ) + (v/c)^7 * ( 𝒾 * δ / 12√14 * ( - (10753397//1513512) - 2ln2*((212//105) + ln2) - (26//21)*γₑ + (π^2/6) - - 2𝒾*π*((41//105) + ln2) + (ν/8)*(-(1738843//19305) + (41//8)*π^2) + (10753397//1513512) - 2ln(2)*((212//105) + ln(2)) - (26//21)*γₑ + (π^2/6) + - 2𝒾*π*((41//105) + ln(2)) + (ν/8)*(-(1738843//19305) + (41//8)*π^2) + (327059//30888)*ν^2 - (17525//15444)*ν^3 + ln(v) * (-26//21) ) @@ -117,15 +117,15 @@ is from Eq. (4.15) of that reference. h[Yindex(3,3,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^1 * (-3𝒾 * √(15//224) * δ) + (v/c)^3 * (-3𝒾 * √(15//56) * δ * (-2 + ν)) - + (v/c)^4 * (√(243//70) * δ * (-7 - 5𝒾*π + 10ln³╱₂) / 4) + + (v/c)^4 * (√(243//70) * δ * (-7 - 5𝒾*π + 10ln(3/2)) / 4) + (v/c)^5 * (-𝒾 * √(3//542080) * δ * (369 + (-3676 + 887ν)ν)) - + (v/c)^6 * (δ * (-3645𝒾 * (-8 + 3ν)π + (40824 - 96206ν + 7290*(-8 + 3ν)ln³╱₂)) / 216√210) + + (v/c)^6 * (δ * (-3645𝒾 * (-8 + 3ν)π + (40824 - 96206ν + 7290*(-8 + 3ν)ln(3/2))) / 216√210) + (v/c)^7 * ( ((-3𝒾)/4) * √(15//14) * δ * ( - (19388147//280280) + (492//35)ln³╱₂ - 18*ln³╱₂^2 - (78//7)γₑ + (3//2)π^2 - + 6𝒾 * π * (-41//35 + 3ln³╱₂) + (19388147//280280) + (492//35)ln(3/2) - 18*ln(3/2)^2 - (78//7)γₑ + (3//2)π^2 + + 6𝒾 * π * (-41//35 + 3ln(3/2)) + (-7055//3432 + 41//64 * π^2)ν - (318841//17160)ν^2 + (8237//2860)ν^3 - + ln(v) * (-(39//7) * 4ln2) + + ln(v) * (-(39//7) * 4ln(2)) ) ) ) @@ -149,7 +149,7 @@ is from Eq. (4.15) of that reference. h[Yindex(4,1,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^3 * (𝒾 * δ * (1 - 2ν) / 84√10) + (v/c)^5 * (-𝒾 * δ * (404 + (-1011 + 332ν)ν) / 11088√10) - + (v/c)^6 * (δ * (64 - 1661ν - 30𝒾*(-1 + 2ν)π + 60*(1 - 2ν)ln2) / 2520√10) + + (v/c)^6 * (δ * (64 - 1661ν - 30𝒾*(-1 + 2ν)π + 60*(1 - 2ν)ln(2)) / 2520√10) ) h[Yindex(4,2,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^2 * (√5 * (1 - 3ν) / 63) @@ -160,12 +160,12 @@ is from Eq. (4.15) of that reference. h[Yindex(4,3,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^3 * (9𝒾 * δ * (-1 + 2ν) / 4√70) + (v/c)^5 * (3𝒾 * δ * (468 + (-1267 + 524ν)ν) / 176√70) - + (v/c)^6 * (δ * (-5184 + 16301ν + 2430𝒾*(-1 + 2ν)π + 4860*(1 - 2ν)ln³╱₂) / 360√70) + + (v/c)^6 * (δ * (-5184 + 16301ν + 2430𝒾*(-1 + 2ν)π + 4860*(1 - 2ν)ln(3/2)) / 360√70) ) h[Yindex(4,4,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^2 * (8 * √(5//7) * (-1 + 3ν) / 9) + (v/c)^4 * (4 * (1779 + 5ν*(-1273 + 525ν)) / 297√35) - + (v/c)^5 * ((160*(-1 + 3ν)π + 𝒾*(336 - 1193ν + 320*(-1 + 3ν)ln2)) / 9√35) + + (v/c)^5 * ((160*(-1 + 3ν)π + 𝒾*(336 - 1193ν + 320*(-1 + 3ν)ln(2))) / 9√35) + (v/c)^6 * ((-9618039 + 7ν*(9793071 + 5ν*(-3231338 + 678291ν))) / 405405√35) ) end @@ -175,7 +175,7 @@ is from Eq. (4.15) of that reference. h[Yindex(5,1,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^3 * (𝒾 * δ * (1 - 2ν) / 288√385) + (v/c)^5 * (-𝒾 * δ * (179 + 4*(-88 + ν)ν) / 11232√385) - + (v/c)^6 * (δ * (181 - 70𝒾*(-1 + 2ν)π + 140ln2 - 28ν*(313 + 10ln2)) / 20160√385) + + (v/c)^6 * (δ * (181 - 70𝒾*(-1 + 2ν)π + 140ln(2) - 28ν*(313 + 10ln(2))) / 20160√385) ) h[Yindex(5,2,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^4 * ((2 + 10*(-1 + ν)ν) / 27√55) @@ -184,7 +184,7 @@ is from Eq. (4.15) of that reference. h[Yindex(5,3,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^3 * (9𝒾 * √(3//110) * δ * (-1 + 2ν) / 32) + (v/c)^5 * (3𝒾 * √(3//110) * δ * (207 + 8ν*(-58 + 11ν)) / 416) - + (v/c)^6 * (δ * (-395847 + 1171828ν + 153090𝒾*(-1 + 2ν)π - 306180*(-1 + 2ν)*ln³╱₂) / 60480√330) + + (v/c)^6 * (δ * (-395847 + 1171828ν + 153090𝒾*(-1 + 2ν)π - 306180*(-1 + 2ν)*ln(3/2)) / 60480√330) ) h[Yindex(5,4,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^4 * ((-32 - 160*(-1 + ν)ν) / 9√165) @@ -193,7 +193,7 @@ is from Eq. (4.15) of that reference. h[Yindex(5,5,ℓₘᵢₙ)] = h₀ * @pn_expansion( (v/c)^3 * (-625𝒾 * δ * (-1 + 2ν) / 96√66) + (v/c)^5 * (-625𝒾 * δ * (263 + 16ν*(-43 + 16ν)) / 3744√66) - + (v/c)^6 * (δ * (565625 - 1481676ν - 218750𝒾*(-1 + 2ν)π + 437500*(-1 + 2ν)ln⁵╱₂) / 6720√66) + + (v/c)^6 * (δ * (565625 - 1481676ν - 218750𝒾*(-1 + 2ν)π + 437500*(-1 + 2ν)ln(5/2)) / 6720√66) ) end diff --git a/src/pn_expressions/pn_expressions.jl b/src/pn_expressions/pn_expressions.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/pn_expressions/pn_expressions.jl @@ -0,0 +1 @@ + diff --git a/src/pn_expressions/separation.jl b/src/pn_expressions/separation.jl index 31f1a573..cec73b4b 100644 --- a/src/pn_expressions/separation.jl +++ b/src/pn_expressions/separation.jl @@ -239,7 +239,7 @@ from the Newton iterations in [`γₚₙ′`](@ref). ) γₚₙ₀′statements[end] = γₚₙ₀′return - if PNExpansionReducer === identity + if PNExpansionReducer ≡ identity # When `pn_expansion_reducer=Val(identity)` is passed, we return a PNExpansion NMax = Int(2PNOrder + 1) return quote diff --git a/src/pn_expressions/waveform.jl b/src/pn_expressions/waveform.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/pn_expressions/waveform.jl @@ -0,0 +1 @@ + diff --git a/src/pn_systems.jl b/src/pn_systems.jl deleted file mode 100644 index f860ded7..00000000 --- a/src/pn_systems.jl +++ /dev/null @@ -1,312 +0,0 @@ -""" - PNSystem{ST, PNOrder} - -Base type for all PN systems, such as `BBH`, `BHNS`, and `NSNS`. - -These objects encode all essential properties of the binary, including its current state. -As such, they can be used as inputs to the various [fundamental](@ref Fundamental-variables) -and [derived variables](@ref Derived-variables), as well as [PN expressions](@ref) and -[dynamics](@ref Dynamics) functions. - -All subtypes should contain a `state` vector holding all of the fundamental variables for -the given type of system. The parameter `ST` is the type of the `state` vector — for -example, `Vector{Float64}`. `PNOrder` is a `Rational` giving the order to which PN -expansions should be carried. -""" -abstract type PNSystem{ST,PNOrder} end - -const VecOrPNSystem = Union{AbstractVector,PNSystem} - -const pnsystem_symbols = ( - :M₁, :M₂, :χ⃗₁ˣ, :χ⃗₁ʸ, :χ⃗₁ᶻ, :χ⃗₂ˣ, :χ⃗₂ʸ, :χ⃗₂ᶻ, :Rʷ, :Rˣ, :Rʸ, :Rᶻ, :v, :Φ -) - -for (i, s) ∈ enumerate(pnsystem_symbols) - sindex = Symbol("$(s)index") - @eval const $sindex = $i -end - -const χ⃗₁indices = χ⃗₁ˣindex:χ⃗₁ᶻindex -const χ⃗₂indices = χ⃗₂ˣindex:χ⃗₂ᶻindex -const Rindices = Rʷindex:Rᶻindex - -Base.eltype(::Type{PNT}) where {ST,PNT<:PNSystem{ST}} = eltype(ST) -Base.one(x::T) where {T<:PNSystem} = one(T) -Base.zero(x::T) where {T<:PNSystem} = zero(T) -Base.float(x::T) where {T<:PNSystem} = float(T) -Base.one(::Type{PNT}) where {PNT<:PNSystem} = one(eltype(PNT)) -Base.zero(::Type{PNT}) where {PNT<:PNSystem} = zero(eltype(PNT)) -Base.float(::Type{PNT}) where {PNT<:PNSystem} = float(eltype(PNT)) -pn_order(::PNSystem{ST,PNOrder}) where {ST,PNOrder} = PNOrder -order_index(pn::PNSystem) = 1 + Int(2pn_order(pn)) - -""" - causes_domain_error!(u̇, p) - -Ensure that these parameters correspond to a physically valid set of PN parameters. - -If the parameters are not valid, this function should modify `u̇` to indicate that the -current step is invalid. This is done by filling `u̇` with `NaN`s, which will be detected -by the ODE solver and cause it to try a different (smaller) step size. - -Currently, the only check that is done is to test that these parameters result in a PN -parameter v>0. In the future, this function may be expanded to include other checks. -""" -function causes_domain_error!(u̇, p::PNSystem{VT}) where {VT} - if p.state[vindex] ≤ 0 # If this is expanded, document the change in the docstring. - u̇ .= convert(eltype(VT), NaN) - true - else - false - end -end - -function prepare_system(; M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ=0, PNOrder=typemax(Int)) - state = [M₁; M₂; vec(QuatVec(χ⃗₁)); vec(QuatVec(χ⃗₂)); components(Rotor(R)); v; Φ] - ST = typeof(state) - PNOrder = prepare_pn_order(PNOrder) - return (ST, PNOrder, state) -end - -function prepare_pn_order(PNOrder) - if PNOrder != typemax(Int) - round(Int, 2PNOrder)//2 - else - (typemax(Int) - 2)//2 - end -end - -""" - BBH{T, PNOrder} - -The [`PNSystem`](@ref) subtype describing a binary black hole system. - -The `state` vector here holds the fundamental variables `M₁`, `M₂`, `χ⃗₁`, `χ⃗₂`, `R`, `v`, -with the spins unpacked into three components each, and `R` unpacked into four — for a total -of 13 elements. - -Optionally, `Φ` may also be tracked as the 14th element of the `state` vector. This is just -the integral of the orbital angular frequency `Ω`, and holds little interest for general -systems beyond a convenient description of how "far" the system has evolved. -""" -struct BBH{T,PNOrder} <: PNSystem{T,PNOrder} - state::T - - BBH{T,PNOrder}(state) where {T,PNOrder} = new{T,PNOrder}(state) - function BBH(; M₁, M₂, χ⃗₁, χ⃗₂, v, R=Rotor(1), Φ=0, PNOrder=typemax(Int), kwargs...) - (T, PNOrder, state) = prepare_system(; M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, PNOrder) - return new{T,PNOrder}(state) - end - function BBH(state; Λ₁=0, Λ₂=0, PNOrder=typemax(Int)) - @assert length(state) == 14 - @assert Λ₁ == 0 - @assert Λ₂ == 0 - return new{typeof(state),prepare_pn_order(PNOrder)}(state) - end -end -const BHBH = BBH - -""" - BHNS{T, PNOrder} - -The [`PNSystem`](@ref) subtype describing a black-hole—neutron-star binary system. - -The `state` vector is the same as for a [`BBH`](@ref). There is an additional field `Λ₂` -holding the (constant) tidal-coupling parameter of the neutron star. - -Note that the neutron star is *always* object 2 — meaning that `M₂`, `χ⃗₂`, and `Λ₂` always -refer to it; `M₁` and `χ⃗₁` always refer to the black hole. See also [`NSNS`](@ref). -""" -struct BHNS{ST,PNOrder,ET} <: PNSystem{ST,PNOrder} - state::ST - Λ₂::ET - - BHNS{T,PNOrder,ET}(state) where {T,PNOrder,ET} = new{T,PNOrder,ET}(state) - BHNS{T,PNOrder}(state) where {T,PNOrder} = new{T,PNOrder,eltype(T)}(state) - function BHNS(; - M₁, M₂, χ⃗₁, χ⃗₂, v, R=Rotor(1), Λ₂, Φ=0, PNOrder=typemax(Int), kwargs... - ) - ST, PNOrder, state = prepare_system(; M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, PNOrder) - ET = eltype(ST) - return new{ST,PNOrder,ET}(state, convert(ET, Λ₂)) - end - function BHNS(state; Λ₂, Λ₁=0, PNOrder=typemax(Int)) - @assert length(state) == 14 - ST, PNOrder = typeof(state), prepare_pn_order(PNOrder) - ET = eltype(ST) - return new{ST,PNOrder,ET}(state, convert(ET, Λ₂)) - end -end - -""" - NSNS{T, PNOrder} - -The [`PNSystem`](@ref) subtype describing a neutron-star—neutron-star binary system. - -The `state` vector is the same as for a [`BBH`](@ref). There are two additional fields `Λ₁` -and `Λ₂` holding the (constant) tidal-coupling parameters of the neutron stars. See also -[`BHNS`](@ref). -""" -struct NSNS{ST,PNOrder,ET} <: PNSystem{ST,PNOrder} - state::ST - Λ₁::ET - Λ₂::ET - - NSNS{T,PNOrder,ET}(state) where {T,PNOrder,ET} = new{T,PNOrder,ET}(state) - NSNS{T,PNOrder}(state) where {T,PNOrder} = new{T,PNOrder,eltype(T)}(state) - function NSNS(; - M₁, M₂, χ⃗₁, χ⃗₂, v, R=Rotor(1), Λ₁, Λ₂, Φ=0, PNOrder=typemax(Int), kwargs... - ) - ST, PNOrder, state = prepare_system(; M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, PNOrder) - ET = eltype(ST) - return new{ST,PNOrder,ET}(state, convert(ET, Λ₁), convert(ET, Λ₂)) - end - function NSNS(state; Λ₁, Λ₂, PNOrder=typemax(Int)) - @assert length(state) == 14 - ST, PNOrder = typeof(state), prepare_pn_order(PNOrder) - ET = eltype(state) - return new{ST,PNOrder,ET}(state, convert(ET, Λ₁), convert(ET, Λ₂)) - end -end -const BNS = NSNS - -""" - FDPNSystem{FT, PNOrder}(state, Λ₁, Λ₂) - -A `PNSystem` that contains information as variables from -[`FastDifferentiation.jl`](https://docs.juliahub.com/General/FastDifferentiation/stable/). - -See also [`fd_pnsystem`](@ref) for a particular instance of this type. Note that this type -also involves the type `FT`, which will be the float type of actual numbers that eventually -get fed into (and will be passed out from) functions that use this system. The correct type -of `FDPNSystem` is used in calculating `𝓔′`. -""" -struct FDPNSystem{FT,PNOrder} <: PNSystem{Vector{FastDifferentiation.Node},PNOrder} - state::Vector{FastDifferentiation.Node} - Λ₁::FastDifferentiation.Node - Λ₂::FastDifferentiation.Node - - function FDPNSystem(FT, PNOrder=typemax(Int)) - FastDifferentiation.@variables M₁ M₂ χ⃗₁ˣ χ⃗₁ʸ χ⃗₁ᶻ χ⃗₂ˣ χ⃗₂ʸ χ⃗₂ᶻ Rʷ Rˣ Rʸ Rᶻ v Φ Λ₁ Λ₂ - return new{FT,prepare_pn_order(PNOrder)}( - [M₁, M₂, χ⃗₁ˣ, χ⃗₁ʸ, χ⃗₁ᶻ, χ⃗₂ˣ, χ⃗₂ʸ, χ⃗₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ], Λ₁, Λ₂ - ) - end -end -Base.eltype(::FDPNSystem{FT}) where {FT} = FT - -""" - fd_pnsystem - -A symbolic `PNSystem` that contains symbolic information for all types of `PNSystem`s. - -In particular, note that this object has (essentially) infinite `PNOrder`, has nonzero -values for quantities like `Λ₁` and `Λ₂`, and assumes that the eventual output will be in -`Float64`. If you want different choices, you may need to call [`FDPNSystem`](@ref) -yourself, or even construct a different specialized subtype of `PNSystem` (it's not hard). - -# Examples -```jldoctest -julia> using PostNewtonian: M₁, M₂, χ⃗₁, χ⃗₂, FDPNSystem - -julia> fd_pnsystem = FDPNSystem(Float64) -FDPNSystem{Float64, 9223372036854775805//2}(FastDifferentiation.Node[M₁, M₂, χ⃗₁ˣ, χ⃗₁ʸ, χ⃗₁ᶻ, χ⃗₂ˣ, χ⃗₂ʸ, χ⃗₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ], Λ₁, Λ₂) - -julia> M₁(fd_pnsystem), M₂(fd_pnsystem) -(M₁, M₂) - -julia> χ⃗₁(fd_pnsystem) - + χ⃗₁ˣ𝐢 + χ⃗₁ʸ𝐣 + χ⃗₁ᶻ𝐤 - -julia> χ⃗₂(fd_pnsystem) - + χ⃗₂ˣ𝐢 + χ⃗₂ʸ𝐣 + χ⃗₂ᶻ𝐤 -``` -""" -const fd_pnsystem = FDPNSystem(Float64) - -function SVector(pnsystem::PNSystem) - return SVector{16,eltype(pnsystem)}( - pnsystem.state[1], - pnsystem.state[2], - pnsystem.state[3], - pnsystem.state[4], - pnsystem.state[5], - pnsystem.state[6], - pnsystem.state[7], - pnsystem.state[8], - pnsystem.state[9], - pnsystem.state[10], - pnsystem.state[11], - pnsystem.state[12], - pnsystem.state[13], - pnsystem.state[14], - Λ₁(pnsystem), - Λ₂(pnsystem), - ) -end -function SVector(pnsystem::FDPNSystem) - return SVector{16,FastDifferentiation.Node}( - pnsystem.state[1], - pnsystem.state[2], - pnsystem.state[3], - pnsystem.state[4], - pnsystem.state[5], - pnsystem.state[6], - pnsystem.state[7], - pnsystem.state[8], - pnsystem.state[9], - pnsystem.state[10], - pnsystem.state[11], - pnsystem.state[12], - pnsystem.state[13], - pnsystem.state[14], - Λ₁(pnsystem), - Λ₂(pnsystem), - ) -end - -@testitem "PNSystem constructors" begin - using Quaternionic - - pnA = BBH(; - M₁=1.0f0, M₂=2.0f0, χ⃗₁=Float32[3.0, 4.0, 5.0], χ⃗₂=Float32[6.0, 7.0, 8.0], v=0.23f0 - ) - @test pnA.state == - Float32[1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 1.0; 0.0; 0.0; 0.0; 0.23; 0.0] - - pnB = BBH(; - M₁=1.0f0, - M₂=2.0f0, - χ⃗₁=Float32[3.0, 4.0, 5.0], - χ⃗₂=Float32[6.0, 7.0, 8.0], - v=0.23f0, - Φ=9.0f0, - ) - @test pnB.state == - Float32[1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 1.0; 0.0; 0.0; 0.0; 0.23; 9.0] - - R = randn(RotorF32) - pn1 = BBH(; - M₁=1.0f0, - M₂=2.0f0, - χ⃗₁=Float32[3.0, 4.0, 5.0], - χ⃗₂=Float32[6.0, 7.0, 8.0], - R=R, - v=0.23f0, - ) - @test pn1.state ≈ [1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; components(R)...; 0.23; 0.0] - - pn2 = BBH(; - M₁=1.0f0, - M₂=2.0f0, - χ⃗₁=Float32[3.0, 4.0, 5.0], - χ⃗₂=Float32[6.0, 7.0, 8.0], - R=R, - v=0.23f0, - Φ=9.0f0, - ) - @test pn2.state ≈ [1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; components(R)...; 0.23; 9.0] - - pn1.state[end] = 9.0f0 - @test pn1.state == pn2.state -end diff --git a/src/pn_systems/BBH.jl b/src/pn_systems/BBH.jl new file mode 100644 index 00000000..3b9fc53f --- /dev/null +++ b/src/pn_systems/BBH.jl @@ -0,0 +1,127 @@ +""" + BBH{NT, ST, PNOrder} <: PNSystem{NT, ST, PNOrder} + +The [`PNSystem`](@ref) subtype describing a binary black hole system. + +The `state` vector here holds the fundamental state variables characterizing the masses, +spins, orientation, velocity, and orbital phase of the system. The spins unpacked into +three components each. The orientation is described by the four components of the `Rotor` +`R`. This gives us a total of 14 elements: + + M₁, M₂, χ₁ˣ, χ₁ʸ, χ₁ᶻ, χ₂ˣ, χ₂ʸ, χ₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ + +The "orbital phase" `Φ` is tracked as the 14th element of the `state` vector. This is just +the integral of the (scalar) orbital angular frequency `Ω`, and holds little interest for +general systems beyond a convenient description of how "far" the system has evolved. For +nonprecessing systems, `Φ` would be sufficient to describe the system's position, which is +more completely described by the `Rotor` `R`. However, for precessing systems, it is +difficult to extract this quantity from `R`. +""" +@export struct BBH{NT,PNOrder,ST} <: Quasispherical{NT,PNOrder,ST} + state::ST + + function BBH{NT,PNOrder,ST}(state) where {NT,PNOrder,ST} + if eachindex(state) != Base.OneTo(14) + error( + "The `state` vector for `BBH` must be indexed from 1 to 14; " * + "input is indexed `$(eachindex(state))`.", + ) + end + new{NT,PNOrder,ST}(state) + end + function BBH(; M₁, M₂, χ⃗₁, χ⃗₂, v, R=Rotor(1), Φ=0, PNOrder=typemax(Int), Λ₁=0, Λ₂=0) + if Λ₁ != 0 || Λ₂ != 0 + error( + "`BBH` does not support tidal-coupling parameters `Λ₁` or `Λ₂`; " * + "use `BHNS` or `NSNS` instead.", + ) + end + (NT, PNOrder, state) = prepare_Quasispherical(; M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, PNOrder) + return new{NT,PNOrder,typeof(state)}(state) + end +end +@public const BHBH = BBH + +# The following are methods of functions defined in `vector_interface.jl` and +# `state_variables.jl`, specialized for `BBH` systems. +Base.length(pnsystem::BBH) = 14 # Specialize this just for efficiency +state(pnsystem::BBH) = pnsystem.state +symbols(::Type{<:BBH}) = symbols(Quasispherical) +ascii_symbols(::Type{<:BBH}) = ascii_symbols(Quasispherical) +for (i, (symbol, ascii_symbol)) ∈ enumerate(zip(symbols(BBH), ascii_symbols(BBH))) + # We could do this manually, but this is more concise and less error-prone. + @eval begin + # Define, e.g., `M₁(pnsystem::BBH) = pnsystem.state[1]`. + $(symbol)(pnsystem::BBH) = @inbounds pnsystem.state[$i] + + # Specialize `symbol_index` for Val{:M₁}, Val{:M₂}, etc. + symbol_index(::Type{T}, ::Val{$(QuoteNode(symbol))}) where {T<:BBH} = $i + end + if symbol ≠ ascii_symbol + @eval begin + # Specialize `symbol_index` for Val{:M1}, Val{:M2}, etc. + symbol_index(::Type{T}, ::Val{$(QuoteNode(ascii_symbol))}) where {T<:BBH} = $i + end + end +end + +# Define any state-variable methods we may need for variables that are not actually in the +# state vector. +Λ₁(pnsystem::BBH) = zero(pnsystem) +Λ₂(pnsystem::BBH) = zero(pnsystem) + +@testitem "BBH constructors" begin + using PostNewtonian: state, constant_convert + using Quaternionic + + pnA = BBH(; + M₁=1.0f0, M₂=2.0f0, χ⃗₁=Float32[3.0, 4.0, 5.0], χ⃗₂=Float32[6.0, 7.0, 8.0], v=0.23f0 + ) + @test eltype(pnA) == Float32 + @test state(pnA) == + Float32[1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 1.0; 0.0; 0.0; 0.0; 0.23; 0.0] + @test constant_convert(pnA, π) isa Float32 + @test constant_convert(pnA, π) == Float32(π) + + pnB = BBH(; + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + v=0.23f0, + Φ=9.0f0, + ) + @test state(pnB) == + Float32[1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 1.0; 0.0; 0.0; 0.0; 0.23; 9.0] + @test constant_convert(pnB, π) isa Float32 + @test constant_convert(pnB, π) == Float32(π) + + R = randn(RotorF32) + pn1 = BBH(; + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + R=R, + v=0.23f0, + ) + @test state(pn1) ≈ [1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; components(R)...; 0.23; 0.0] + @test constant_convert(pn1, π) isa Float32 + @test constant_convert(pn1, π) == Float32(π) + + pn2 = BBH(; + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + R=R, + v=0.23f0, + Φ=9.0f0, + ) + @test state(pn2) ≈ [1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; components(R)...; 0.23; 9.0] + @test constant_convert(pn2, π) isa Float32 + @test constant_convert(pn2, π) == Float32(π) + + state(pn1)[end] = 9.0f0 + @test state(pn1) == state(pn2) +end diff --git a/src/pn_systems/BHNS.jl b/src/pn_systems/BHNS.jl new file mode 100644 index 00000000..a93d7653 --- /dev/null +++ b/src/pn_systems/BHNS.jl @@ -0,0 +1,168 @@ +""" + BHNS{NT, ST, PNOrder} <: PNSystem{NT, ST, PNOrder} + +The [`PNSystem`](@ref) subtype describing a black-hole—neutron-star binary system. + +The `state` vector is the same as for a [`BBH`](@ref), with an additional field `Λ₂` holding +the (constant) tidal-coupling parameter of the neutron star. + +Note that the neutron star is *always* object 2 — meaning that `M₂`, `χ⃗₂`, and `Λ₂` always +refer to it; `M₁` and `χ⃗₁` always refer to the black hole. (It's "BHNS", not "NSBH".) See +also [`NSNS`](@ref). +""" +@export struct BHNS{NT,PNOrder,ST} <: Quasispherical{NT,PNOrder,ST} + state::ST + + function BHNS{NT,PNOrder,ST}(state) where {NT,PNOrder,ST} + if eachindex(state) != Base.OneTo(15) + error( + "The `state` vector for `BHNS` must be indexed from 1 to 15; " * + "input is indexed `$(eachindex(state))`.", + ) + end + new{NT,PNOrder,ST}(state) + end + function BHNS(; M₁, M₂, χ⃗₁, χ⃗₂, v, R=Rotor(1), Φ=0, Λ₁=0, Λ₂, PNOrder=typemax(Int)) + if Λ₁ != 0 + error( + "`BHNS` does not support a tidal-coupling parameter `Λ₁` for object 1; " * + "use `NSNS` instead.", + ) + end + (NT, PNOrder, state) = prepare_Quasispherical(; M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, PNOrder) + state = vcat(state, Λ₂) + return new{eltype(state),PNOrder,typeof(state)}(state) + end +end + +# The following are methods of functions defined in `vector_interface.jl` and +# `state_variables.jl`, specialized for `BBH` systems. +Base.length(pnsystem::BHNS) = 15 # Specialize this just for efficiency +state(pnsystem::BHNS) = pnsystem.state +function symbols(::Type{<:BHNS}) + (symbols(Quasispherical)..., :Λ₂) +end +function ascii_symbols(::Type{<:BHNS}) + (ascii_symbols(Quasispherical)..., :Lambda2) +end +for (i, (symbol, ascii_symbol)) ∈ enumerate(zip(symbols(BHNS), ascii_symbols(BHNS))) + # We could do this manually, but this is more concise and less error-prone. + @eval begin + # Define, e.g., `M₁(pnsystem::BHNS) = pnsystem.state[1]`. + $(symbol)(pnsystem::BHNS) = @inbounds pnsystem.state[$i] + + # Specialize `symbol_index` for Val{:M₁}, Val{:M₂}, etc. + symbol_index(::Type{T}, ::Val{$(QuoteNode(symbol))}) where {T<:BHNS} = $i + end + if symbol ≠ ascii_symbol + @eval begin + # Specialize `symbol_index` for Val{:M1}, Val{:M2}, etc. + symbol_index(::Type{T}, ::Val{$(QuoteNode(ascii_symbol))}) where {T<:BHNS} = $i + end + end +end + +# Define any state-variable methods we may need for variables that are not actually in the +# state vector. +Λ₁(pnsystem::BHNS) = zero(pnsystem) + +@testitem "BHNS constructors" begin + using PostNewtonian: state, constant_convert + using Quaternionic + + # minimal constructor: default Φ=0, R=Rotor(1) + pnA = BHNS( + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + v=0.23f0, + Λ₂=4.0f0, + ) + @test eltype(pnA) == Float32 + @test state(pnA) == Float32[ + 1.0; + 2.0; + 3.0; + 4.0; + 5.0; + 6.0; + 7.0; + 8.0; + 1.0; + 0.0; + 0.0; + 0.0; + 0.23; + 0.0; + 4.0 + ] + @test constant_convert(pnA, π) isa Float32 + @test constant_convert(pnA, π) == Float32(π) + + # explicit orbital phase + pnB = BHNS( + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + v=0.23f0, + Φ=9.0f0, + Λ₂=4.0f0, + ) + @test state(pnB) == Float32[ + 1.0; + 2.0; + 3.0; + 4.0; + 5.0; + 6.0; + 7.0; + 8.0; + 1.0; + 0.0; + 0.0; + 0.0; + 0.23; + 9.0; + 4.0 + ] + @test constant_convert(pnB, π) isa Float32 + @test constant_convert(pnB, π) == Float32(π) + + # custom rotor, default Φ + R = randn(RotorF32) + pn1 = BHNS( + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + R=R, + v=0.23f0, + Λ₂=4.0f0, + ) + @test state(pn1) ≈ + [1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; components(R)...; 0.23; 0.0; 4.0] + @test constant_convert(pn1, π) isa Float32 + @test constant_convert(pn1, π) == Float32(π) + + # custom rotor and Φ + pn2 = BHNS( + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + R=R, + v=0.23f0, + Φ=9.0f0, + Λ₂=4.0f0, + ) + @test state(pn2) ≈ + [1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; components(R)...; 0.23; 9.0; 4.0] + @test constant_convert(pn2, π) isa Float32 + @test constant_convert(pn2, π) == Float32(π) + + # mutating the second-to-last element (Φ) to match pn2 + pn1[end - 1] = 9.0f0 + @test state(pn1) == state(pn2) +end diff --git a/src/pn_systems/FDPNsystem.jl b/src/pn_systems/FDPNsystem.jl new file mode 100644 index 00000000..478667b2 --- /dev/null +++ b/src/pn_systems/FDPNsystem.jl @@ -0,0 +1,111 @@ +""" + FDPNSystem{NT, PN, PNOrder} <: PNSystem{Node, Vector{Node}, PNOrder} + +A `PNSystem` that contains information as variables of type `Node` from +[`FastDifferentiation.jl`](https://docs.juliahub.com/General/FastDifferentiation/stable/). + +Note that this type also involves the type parameter `PN`, which is actually the type of a +`PNSystem`, and its type parameter `NT`, which will be the number type of actual numbers +that eventually get fed into (and will be passed out from) functions that use this system. + +One important example of what this type is used for is computing the derivative of the +orbital binding energy, `𝓔′` — and in particular, for generating the corresponding function +method to apply to a given `PNSystem`. + +!!! warning + + Because of the structure of the type parameters, most methods defined for a general + `PNSystem` will use `Node` as the number type. This may be correct in many cases, but + when `Node` is applied to an integer, for example, it will generally result in a + `Float64` value, rather than the `NT` type parameter. For this reason many methods + will need to be specialized for `FDPNSystem` types, using almost the same definition, + but with the additional `FD` prefix inserted throughout. +""" +@export struct FDPNSystem{NT,PNOrder,PN<:PNSystem{NT,PNOrder}} <: + PNSystem{FDNode,PNOrder,Vector{FDNode}} + state::Vector{FDNode} + + FDPNSystem(pnsystem::PNSystem) = FDPNSystem(typeof(pnsystem)) + function FDPNSystem(::Type{PN}) where {NT,PNOrder,PN<:PNSystem{NT,PNOrder}} + return new{NT,PNOrder,PN}([FDNode(s) for s ∈ symbols(PN)]) + end +end + +state(pnsystem::FDPNSystem) = pnsystem.state + +# This is an example of where we need to specialize the method for `FDPNSystem`, as +# explained in the docstring. +Base.eltype(::FDPNSystem{FT}) where {FT} = FT + +symbols(pnsystem::FDPNSystem{NT,PNOrder,PN}) where {NT,PNOrder,PN} = symbols(PN) +symbols(::Type{T}) where {NT,PNOrder,PN,T<:FDPNSystem{NT,PNOrder,PN}} = symbols(PN) + +function symbol_index(pnsystem::FDPNSystem{NT,PNOrder,PN}, s::Symbol) where {NT,PNOrder,PN} + symbol_index(PN, Val(s)) +end +function symbol_index(::Type{T}, ::Val{S}) where {T<:FDPNSystem,S} + index = findfirst(y -> y == S, symbols(T)) + if isnothing(index) + index = findfirst(y -> y == S, ascii_symbols(T)) + end + if isnothing(index) + error( + "Type `$(T)` has no symbol `:$(S)`.\n" * + "This type's symbols are `$(symbols(T))`.\n" * + "The ASCII equivalents are `$(ascii_symbols(T))`.\n", + ) + else + index + end +end + +# These are more examples of where we need to specialize the method for `FDPNSystem`, as +# explained in the docstring. +constant_convert(::T, x::ExactNumber) where {NT,T<:FDPNSystem{NT}} = NT(x) +constant_convert(::T, x::NT) where {NT,T<:FDPNSystem{NT}} = x + +@testitem "FDPNSystem" begin + using PostNewtonian: constant_convert + @testset "BBH" begin + PNOrder = 7//2 + for NT ∈ (Float16, Float64) + bbh = BBH(randn(NT, 14), PNOrder) + fdpnsystem = FDPNSystem(bbh) + @test fdpnsystem isa FDPNSystem{eltype(bbh),PNOrder,typeof(bbh)} + @test pn_order(fdpnsystem) == PNOrder + @test eltype(fdpnsystem) == NT + @test symbols(fdpnsystem) == symbols(bbh) + @test length(fdpnsystem) == 14 + @test constant_convert(fdpnsystem, π) isa NT + @test constant_convert(fdpnsystem, π) == NT(π) + end + end + @testset "BHNS" begin + PNOrder = typemax(Int) + for NT ∈ (Float16, Float64) + bhns = BHNS(randn(NT, 15), PNOrder) + fdpnsystem = FDPNSystem(bhns) + @test fdpnsystem isa FDPNSystem{eltype(bhns),max_pn_order,typeof(bhns)} + @test pn_order(fdpnsystem) == max_pn_order + @test eltype(fdpnsystem) == NT + @test symbols(fdpnsystem) == symbols(bhns) + @test length(fdpnsystem) == 15 + @test constant_convert(fdpnsystem, π) isa NT + @test constant_convert(fdpnsystem, π) == NT(π) + end + end + @testset "NSNS" begin + PNOrder = 3.5 + for NT ∈ (Float16, Float64) + nsns = NSNS(randn(NT, 16), PNOrder) + fdpnsystem = FDPNSystem(nsns) + @test fdpnsystem isa FDPNSystem{eltype(nsns),7//2,typeof(nsns)} + @test pn_order(fdpnsystem) == 7//2 + @test eltype(fdpnsystem) == NT + @test symbols(fdpnsystem) == symbols(nsns) + @test length(fdpnsystem) == 16 + @test constant_convert(fdpnsystem, π) isa NT + @test constant_convert(fdpnsystem, π) == NT(π) + end + end +end diff --git a/src/pn_systems/NSNS.jl b/src/pn_systems/NSNS.jl new file mode 100644 index 00000000..921af0d7 --- /dev/null +++ b/src/pn_systems/NSNS.jl @@ -0,0 +1,162 @@ +""" + NSNS{NT, PNOrder, ST} <: PNSystem{NT, PNOrder, ST} + +The [`PNSystem`](@ref) subtype describing a neutron-star—neutron-star binary system. + +The `state` vector is the same as for a [`BBH`](@ref), with two additional fields `Λ₁` +and `Λ₂` holding the (constant) tidal-coupling parameters of the neutron stars. See also +[`BHNS`](@ref). +""" +@export struct NSNS{NT,PNOrder,ST} <: Quasispherical{NT,PNOrder,ST} + state::ST + + function NSNS{NT,PNOrder,ST}(state) where {NT,PNOrder,ST} + if eachindex(state) != Base.OneTo(16) + error( + "The `state` vector for `NSNS` must be indexed from 1 to 16; " * + "input is indexed `$(eachindex(state))`.", + ) + end + new{NT,PNOrder,ST}(state) + end + function NSNS(; M₁, M₂, χ⃗₁, χ⃗₂, v, R=Rotor(1), Φ=0, Λ₁, Λ₂, PNOrder=typemax(Int)) + (NT, PNOrder, state) = prepare_Quasispherical(; M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ, PNOrder) + state = vcat(state, Λ₁, Λ₂) + return new{eltype(state),PNOrder,typeof(state)}(state) + end +end +@public const BNS = NSNS + +# The following are methods of functions defined in `vector_interface.jl` and +# `state_variables.jl`, specialized for `BBH` systems. +Base.length(pnsystem::NSNS) = 16 # Specialize this just for efficiency +state(pnsystem::NSNS) = pnsystem.state +function symbols(::Type{<:NSNS}) + (symbols(Quasispherical)..., :Λ₁, :Λ₂) +end +function ascii_symbols(::Type{<:NSNS}) + (ascii_symbols(Quasispherical)..., :Lambda1, :Lambda2) +end +for (i, (symbol, ascii_symbol)) ∈ enumerate(zip(symbols(NSNS), ascii_symbols(NSNS))) + # We could do this manually, but this is more concise and less error-prone. + @eval begin + # Define, e.g., `M₁(pnsystem::NSNS) = pnsystem.state[1]`. + $(symbol)(pnsystem::NSNS) = @inbounds pnsystem.state[$i] + + # Specialize `symbol_index` for Val{:M₁}, Val{:M₂}, etc. + symbol_index(::Type{T}, ::Val{$(QuoteNode(symbol))}) where {T<:NSNS} = $i + end + if symbol ≠ ascii_symbol + @eval begin + # Specialize `symbol_index` for Val{:M1}, Val{:M2}, etc. + symbol_index(::Type{T}, ::Val{$(QuoteNode(ascii_symbol))}) where {T<:NSNS} = $i + end + end +end + +@testitem "NSNS constructors" begin + using PostNewtonian: state, constant_convert + using Quaternionic + + # minimal constructor: default Φ=0, R=Rotor(1) + pnA = NSNS( + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + v=0.23f0, + Λ₁=5.0f0, + Λ₂=6.0f0, + ) + @test eltype(pnA) == Float32 + @test state(pnA) == Float32[ + 1.0; + 2.0; + 3.0; + 4.0; + 5.0; + 6.0; + 7.0; + 8.0; + 1.0; + 0.0; + 0.0; + 0.0; + 0.23; + 0.0; + 5.0; + 6.0 + ] + @test constant_convert(pnA, π) isa Float32 + @test constant_convert(pnA, π) == Float32(π) + + # explicit orbital phase + pnB = NSNS( + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + v=0.23f0, + Φ=9.0f0, + Λ₁=5.0f0, + Λ₂=6.0f0, + ) + @test state(pnB) == Float32[ + 1.0; + 2.0; + 3.0; + 4.0; + 5.0; + 6.0; + 7.0; + 8.0; + 1.0; + 0.0; + 0.0; + 0.0; + 0.23; + 9.0; + 5.0; + 6.0 + ] + @test constant_convert(pnB, π) isa Float32 + @test constant_convert(pnB, π) == Float32(π) + + # custom rotor, default Φ + R = randn(RotorF32) + pn1 = NSNS( + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + R=R, + v=0.23f0, + Λ₁=5.0f0, + Λ₂=6.0f0, + ) + @test state(pn1) ≈ + [1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; components(R)...; 0.23; 0.0; 5.0; 6.0] + @test constant_convert(pn1, π) isa Float32 + @test constant_convert(pn1, π) == Float32(π) + + # custom rotor and Φ + pn2 = NSNS( + M₁=1.0f0, + M₂=2.0f0, + χ⃗₁=Float32[3.0, 4.0, 5.0], + χ⃗₂=Float32[6.0, 7.0, 8.0], + R=R, + v=0.23f0, + Φ=9.0f0, + Λ₁=5.0f0, + Λ₂=6.0f0, + ) + @test state(pn2) ≈ + [1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; components(R)...; 0.23; 9.0; 5.0; 6.0] + @test constant_convert(pn2, π) isa Float32 + @test constant_convert(pn2, π) == Float32(π) + + # mutating the second-to-last element (Φ) to match pn2 + pn1[end - 2] = 9.0f0 + @test state(pn1) == state(pn2) +end diff --git a/src/pn_systems/PNSystem.jl b/src/pn_systems/PNSystem.jl new file mode 100644 index 00000000..1cb68fd6 --- /dev/null +++ b/src/pn_systems/PNSystem.jl @@ -0,0 +1,134 @@ +""" + PNSystem{NT, PNOrder, ST} + +Base type for all PN systems, such as `BBH`, `BHNS`, and `NSNS`. + +These objects encode all essential properties of the binary, including its current state. +As such, they can be used as inputs to the various [fundamental](@ref Fundamental-variables) +and [derived variables](@ref Derived-variables), as well as [PN expressions](@ref) and +[dynamics](@ref Dynamics) functions. + +The parameter `NT` is the number type of the system, such as `Float64` or `Dual{SomeTag, +Float64, 7}`. The parameter `ST <: AbstractVector{NT}` is the type returned by the `state` +function, which probably just returns the `state` vector stored in the concrete subtype. As +such, this will probably be `MVector{N, NT}` or `SVector{N, NT}`, where `N` is the number of +elements in the state. `PNOrder` is a `Rational` giving the order to which PN expansions +should be carried out when using the given object. +""" +@export abstract type PNSystem{NT<:Number,PNOrder,ST<:AbstractVector{NT}} <: + AbstractVector{NT} end + +""" + pnsystem::PNSystem(; kwargs...) + +State-modifying copy constructor for `PNSystem` objects. + +!!! warning + + This function is slow; it should not be used in performance-critical code. + +Note that this cannot modify the type's parameters — the number type `NT`, the `PNOrder` of +the system, or the state type `ST`. However, it can modify any of the state variables by +symbol or by ASCII symbol. This function will raise an AssertionError if any of the keys in +`kwargs` is not a valid symbol for the given `PNSystem` type. + +```jldoctest +julia> using PostNewtonian: BBH + +julia> pnsystem = BBH(ones(14)/2; PNOrder=7//2) +BBH{Vector{Float64}, 7//2}([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]) + +julia> pnsystem2 = pnsystem(M₁=0.2, M₂=0.8, chi1x=0.1) +BBH{Vector{Float64}, 7//2}([0.2, 0.8, 0.1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]) +``` +""" +function (pnsystem::PNSystem{NT,PNOrder,ST})(; kwargs...) where {NT,PNOrder,ST} + all_symbols = Set(symbols(pnsystem)) ∪ Set(ascii_symbols(pnsystem)) + @assert keys(kwargs) ⊆ all_symbols ( + "PNSystem of type $(typeof(pnsystem)) does not have these symbols, which were " * + "input as keyword arguments:\n $(setdiff(keys(kwargs), all_symbols))\n" * + "Maybe you passed `String`s instead of `Symbol`s?\n" * + "The available symbols for this type are\n" * + " $(symbols(pnsystem))\n" * + "and their ASCII equivalents:\n" * + " $(ascii_symbols(pnsystem))" + ) + state = Tuple( + get(kwargs, symbol, get(kwargs, ascii_symbol, pnsystem[symbol])) for + (symbol, ascii_symbol) ∈ zip(symbols(pnsystem), ascii_symbols(pnsystem)) + ) + typeof(pnsystem)(ST(SVector(state))) +end + +""" + state(pnsystem::PNSystem) + +Return the state vector of `pnsystem`, which is a vector of fundamental variables for the +given PN system. + +Note that the built-in `PNSystem` subtypes have a `state` field that is a vector, so this +function will just return that vector. However, that may not always be true for +user-defined subtypes. + +This function should have a specialized method for each concrete subtype of `PNSystem`. +""" +@public function state(::T) where {T<:PNSystem} + error("`state` is not yet defined for PNSystem subtype `$T`.") +end + +Base.eltype(::Type{PNT}) where {NT,PNT<:PNSystem{NT}} = NT +Base.one(::Type{PNT}) where {PNT<:PNSystem} = one(eltype(PNT)) +Base.one(x::T) where {T<:PNSystem} = one(T) +Base.zero(::Type{PNT}) where {PNT<:PNSystem} = zero(eltype(PNT)) +Base.zero(x::T) where {T<:PNSystem} = zero(T) +Base.float(::Type{PNT}) where {PNT<:PNSystem} = float(eltype(PNT)) +Base.float(x::T) where {T<:PNSystem} = float(T) + +""" + symbols(pnsystem::PNSystem) + symbols(::Type{<:PNSystem}) + ascii_symbols(pnsystem::PNSystem) + ascii_symbols(::Type{<:PNSystem}) + +Return a Tuple of symbols corresponding to the variables tracked by `pnsystem`, in the order +in which they are stored in the `state` vector. + +The `ascii_symbols` function returns those symbols in ASCII form, enabling interaction with +external systems (e.g., Python) that do not support many Unicode symbols. + +These functions should have specialized methods for each concrete subtype of `PNSystem`. +For example, the `BBH` system has 14 state variables, as seen in the following example: +```jldoctest +julia> using PostNewtonian: BBH + +julia> pnsystem = BBH(randn(14); PNOrder=7//2); + +julia> symbols(pnsystem) +(:M₁, :M₂, :χ₁ˣ, :χ₁ʸ, :χ₁ᶻ, :χ₂ˣ, :χ₂ʸ, :χ₂ᶻ, :Rʷ, :Rˣ, :Rʸ, :Rᶻ, :v, :Φ) + +julia> ascii_symbols(pnsystem) +(:M1, :M2, :chi1x, :chi1y, :chi1z, :chi2x, :chi2y, :chi2z, :Rw, :Rx, :Ry, :Rz, :v, :Phi) +``` +""" +@export symbols(pnsystem::PNSystem) = symbols(typeof(pnsystem)) +function symbols(::Type{T}) where {T<:PNSystem} + error("`symbols` is not yet defined for PNSystem subtype `$T`.") +end +@export ascii_symbols(pnsystem::PNSystem) = ascii_symbols(typeof(pnsystem)) +function ascii_symbols(::Type{T}) where {T<:PNSystem} + error("`ascii_symbols` is not yet defined for PNSystem subtype `$T`.") +end + +""" + constant_convert(pnsystem, x) + +Convert `x` to the type of the constant numbers to be used with `pnsystem`. Usually, this +type will be the first template parameter. However, when that parameter is a `Dual`, for +example, we don't want to bother defining constants as `Dual`, so we will just define them +as the `Dual`'s underlying type in PostNewtonianForwardDiffExt. + +You generally will not need to call this function directly; it will be used automatically by +the [`@pn_expression`](@ref) macro. +""" +@public constant_convert(::T, x::ExactNumber) where {NT,T<:PNSystem{NT}} = NT(x) +constant_convert(::T, x::NT) where {NT,T<:PNSystem{NT}} = x diff --git a/src/pn_systems/Quasispherical.jl b/src/pn_systems/Quasispherical.jl new file mode 100644 index 00000000..cb02f779 --- /dev/null +++ b/src/pn_systems/Quasispherical.jl @@ -0,0 +1,44 @@ +# NOTE: This type is documented separately, below, so that we can call +# `symbols(Quasispherical)` and `ascii_symbols(Quasispherical)` in the docstring. +@public abstract type Quasispherical{NT,PNOrder,ST} <: PNSystem{NT,PNOrder,ST} end + +function symbols(::Type{<:Quasispherical}) + (:M₁, :M₂, :χ₁ˣ, :χ₁ʸ, :χ₁ᶻ, :χ₂ˣ, :χ₂ʸ, :χ₂ᶻ, :Rʷ, :Rˣ, :Rʸ, :Rᶻ, :v, :Φ) +end +function ascii_symbols(::Type{<:Quasispherical}) + (:M1, :M2, :chi1x, :chi1y, :chi1z, :chi2x, :chi2y, :chi2z, :Rw, :Rx, :Ry, :Rz, :v, :Phi) +end + +@doc """ + Quasispherical{NT,PNOrder,ST} <: PNSystem{NT,PNOrder,ST} + +This is an abstract type for quasispherical post-Newtonian systems. The built-in `BBH`, +`BHNS`, and `NSNS` systems subtype this. + +The quantities common to all subtypes are + + $(symbols(Quasispherical)) + +which have the ASCII equivalents + + $(ascii_symbols(Quasispherical)) + +Note `BBH` has exactly these symbols, while `BHNS` and `NSNS` have additional symbols for +tidal-coupling parameters, `Λ₁` and `Λ₂` (or `Lambda1` and `Lambda2`). +""" +Quasispherical + +function (::Type{T})(state, PNOrder=typemax(Int)) where {T<:Quasispherical} + T{eltype(state),prepare_pn_order(PNOrder),typeof(state)}(state) +end + +function prepare_Quasispherical(; M₁, M₂, χ⃗₁, χ⃗₂, R, v, Φ=0, PNOrder=typemax(Int)) + χ⃗₁ = QuatVec(χ⃗₁) + χ⃗₂ = QuatVec(χ⃗₂) + state = MVector{14}( + M₁, M₂, χ⃗₁[2], χ⃗₁[3], χ⃗₁[4], χ⃗₂[2], χ⃗₂[3], χ⃗₂[4], R[1], R[2], R[3], R[4], v, Φ + ) + NT = eltype(state) + PNOrder = prepare_pn_order(PNOrder) + return (NT, PNOrder, state) +end diff --git a/src/pn_systems/pn_order.jl b/src/pn_systems/pn_order.jl new file mode 100644 index 00000000..ff452398 --- /dev/null +++ b/src/pn_systems/pn_order.jl @@ -0,0 +1,82 @@ +""" + pn_order(pnsystem::PNSystem) + +Return the PN order of the given `pnsystem`. + +This is a `Rational{Int}` that indicates the order to which the PN expansions should be +carried out when using the given object. +""" +@export pn_order(::Type{<:PNSystem{NT,PNOrder}}) where {NT,PNOrder} = PNOrder +pn_order(pnsystem::PNSystem) = pn_order(typeof(pnsystem)) + +""" + order_index(pnsystem::PNSystem) + +Return the order index of the given `pnsystem`. + +This is defined as the (one-based) index into an iterable of PN terms starting at 0pN, then +0.5pN, etc. Specifically, this is defined as `1 + Int(2pn_order(pnsystem))`. +""" +@export order_index(pnsystem::PNSystem) = 1 + Int(2pn_order(pnsystem)) + +""" + max_pn_order + +The maximum PN order that can be used without overflowing the `Int` type. +""" +@export const max_pn_order = (typemax(Int) - 2) // 2 + +""" + prepare_pn_order(PNOrder) + +Convert the input to a half-integer of type `Rational{Int}`. + +If `PNOrder` is larger than `max_pn_order`, it is set to `max_pn_order`, to avoid overflow +when computing the order index. +""" +@public function prepare_pn_order(PNOrder) + if PNOrder < max_pn_order + round(Int, 2PNOrder) // 2 + else + max_pn_order + end +end + +@testitem "PN Orders" begin + using PostNewtonian: prepare_pn_order + + @test max_pn_order == (typemax(Int) - 2) // 2 + @test max_pn_order > 4611686018427387902 + @test max_pn_order < 4611686018427387903 + + @test prepare_pn_order(0//2) == 0//2 + @test prepare_pn_order(1//2) == 1//2 + @test prepare_pn_order(2//2) == 2//2 + @test prepare_pn_order(7//2) == 7//2 + @test prepare_pn_order(31//2) == 31//2 + + @test prepare_pn_order(0.0) == 0//2 + @test prepare_pn_order(0.5) == 1//2 + for i ∈ 0:31 + @test prepare_pn_order(i/2) == i//2 + end + + @test prepare_pn_order(0) == 0//1 + @test prepare_pn_order(1) == 1//1 + @test prepare_pn_order(2) == 2//1 + @test prepare_pn_order(7) == 7//1 + @test prepare_pn_order(31) == 31//1 + + @test prepare_pn_order(typemax(Int)) == max_pn_order + @test prepare_pn_order(typemax(Int) - 1) == max_pn_order + @test prepare_pn_order(typemax(Int) - 2) == max_pn_order + @test prepare_pn_order(typemax(Int) // 2) == max_pn_order + + for i ∈ 0:31 + bbh = BBH(randn(14), i//2) + @test order_index(bbh) == 1 + i + @test pn_order(bbh) ≈ i/2 + @test pn_order(bbh) == i//2 + @test pn_order(BBH{Float16,i//2,Vector{Float16}}) == i//2 + end +end diff --git a/src/pn_systems/pn_systems.jl b/src/pn_systems/pn_systems.jl new file mode 100644 index 00000000..1479cadd --- /dev/null +++ b/src/pn_systems/pn_systems.jl @@ -0,0 +1,9 @@ +include("PNSystem.jl") +include("pn_order.jl") +include("vector_interface.jl") +include("FDPNSystem.jl") +include("state_variables.jl") +include("Quasispherical.jl") +include("BBH.jl") +include("BHNS.jl") +include("NSNS.jl") diff --git a/src/pn_systems/state_variables.jl b/src/pn_systems/state_variables.jl new file mode 100644 index 00000000..6a00e133 --- /dev/null +++ b/src/pn_systems/state_variables.jl @@ -0,0 +1,375 @@ +""" + G(pnsystem) + +Return Newton's gravitational constant for the given `pnsystem`. + +By default, the value is one *with the same number type as `pnsystem`*. It can be +overridden for subtypes of `PNSystem` that use different units or conventions. + +However, note that this function should specialize on the number type of `pnsystem`, rather +than just returning the integer `1`, because there may be expressions with factors such as +`G/3` which will immediately convert to `Float64` if `G` is just `1`, so the result will not +have the expected precision. +""" +@public G(::PNSystem{NT}) where {NT} = one(NT) +G(::FDPNSystem{NT,PN}) where {NT,PN} = one(PN) + +""" + c(pnsystem) + +Return the speed of light for the given `pnsystem`. + +By default, the value is one *with the same number type as `pnsystem`*. It can be +overridden for subtypes of `PNSystem` that use different units or conventions. + +However, note that this function should specialize on the number type of `pnsystem`, rather +than just returning the integer `1`, because there may be expressions with factors such as +`c/3` which will immediately convert to `Float64` if `c` is just `1`, so the result will not +have the expected precision. +""" +@public c(::PNSystem{NT}) where {NT} = one(NT) +c(::FDPNSystem{NT,PN}) where {NT,PN} = one(PN) + +""" + M₁(pnsystem) + M1(pnsystem) + +Mass of object 1 in this system. +""" +@public function M₁(::T) where {T<:PNSystem} + error("M₁ is not (yet) defined for PNSystem subtype `$T`.") +end +M₁(fdpnsystem::FDPNSystem) = fdpnsystem[:M₁] +@public const M1 = M₁ + +""" + M₂(pnsystem) + M2(pnsystem) + +Mass of object 2 in this system. +""" +@public function M₂(::T) where {T<:PNSystem} + error("M₂ is not (yet) defined for PNSystem subtype `$T`.") +end +M₂(fdpnsystem::FDPNSystem) = fdpnsystem[:M₂] +@public const M2 = M₂ + +""" + χ₁ˣ(pnsystem) + chi1x(pnsystem) + +`x`-component of dimensionless spin vector of object 1 in this system, as a `QuatVec`. + +See [`χ⃗₁`](@ref) for details. +""" +@public function χ₁ˣ(::T) where {T<:PNSystem} + error("χ₁ˣ is not (yet) defined for PNSystem subtype `$T`.") +end +χ₁ˣ(fdpnsystem::FDPNSystem) = fdpnsystem[:χ₁ˣ] +@public const chi1x = χ₁ˣ + +""" + χ₁ʸ(pnsystem) + chi1y(pnsystem) + +`y`-component of dimensionless spin vector of object 1 in this system, as a `QuatVec`. + +See [`χ⃗₁`](@ref) for details. +""" +@public function χ₁ʸ(::T) where {T<:PNSystem} + error("χ₁ʸ is not (yet) defined for PNSystem subtype `$T`.") +end +χ₁ʸ(fdpnsystem::FDPNSystem) = fdpnsystem[:χ₁ʸ] +@public const chi1y = χ₁ʸ + +""" + χ₁ᶻ(pnsystem) + chi1z(pnsystem) + +`z`-component of dimensionless spin vector of object 1 in this system, as a `QuatVec`. + +See [`χ⃗₁`](@ref) for details. +""" +@public function χ₁ᶻ(::T) where {T<:PNSystem} + error("χ₁ᶻ is not (yet) defined for PNSystem subtype `$T`.") +end +χ₁ᶻ(fdpnsystem::FDPNSystem) = fdpnsystem[:χ₁ᶻ] +@public const chi1z = χ₁ᶻ + +""" + χ₂ˣ(pnsystem) + chi2x(pnsystem) + +`x`-component of dimensionless spin vector of object 2 in this system, as a `QuatVec`. + +See [`χ⃗₂`](@ref) for details. +""" +@public function χ₂ˣ(::T) where {T<:PNSystem} + error("χ₂ˣ is not (yet) defined for PNSystem subtype `$T`.") +end +χ₂ˣ(fdpnsystem::FDPNSystem) = fdpnsystem[:χ₂ˣ] +@public const chi2x = χ₂ˣ + +""" + χ₂ʸ(pnsystem) + chi2y(pnsystem) + +`y`-component of dimensionless spin vector of object 2 in this system, as a `QuatVec`. + +See [`χ⃗₂`](@ref) for details. +""" +@public function χ₂ʸ(::T) where {T<:PNSystem} + error("χ₂ʸ is not (yet) defined for PNSystem subtype `$T`.") +end +χ₂ʸ(fdpnsystem::FDPNSystem) = fdpnsystem[:χ₂ʸ] +@public const chi2y = χ₂ʸ + +""" + χ₂ᶻ(pnsystem) + chi2z(pnsystem) + +`z`-component of dimensionless spin vector of object 2 in this system, as a `QuatVec`. + +See [`χ⃗₂`](@ref) for details. +""" +@public function χ₂ᶻ(::T) where {T<:PNSystem} + error("χ₂ᶻ is not (yet) defined for PNSystem subtype `$T`.") +end +χ₂ᶻ(fdpnsystem::FDPNSystem) = fdpnsystem[:χ₂ᶻ] +@public const chi2z = χ₂ᶻ + +""" + Rʷ(pnsystem) + Rw(pnsystem) + +Scalar component of the orientation `Rotor` of the binary. + +See [`R`](@ref) for details. +""" +@public function Rʷ(::T) where {T<:PNSystem} + error("Rʷ is not (yet) defined for PNSystem subtype `$T`.") +end +Rʷ(fdpnsystem::FDPNSystem) = fdpnsystem[:Rʷ] +@public const Rw = Rʷ + +""" + Rˣ(pnsystem) + Rx(pnsystem) + +`x`-component of the orientation `Rotor` of the binary. + +See [`R`](@ref) for details. +""" +@public function Rˣ(::T) where {T<:PNSystem} + error("Rˣ is not (yet) defined for PNSystem subtype `$T`.") +end +Rˣ(fdpnsystem::FDPNSystem) = fdpnsystem[:Rˣ] +@public const Rx = Rˣ + +""" + Rʸ(pnsystem) + Ry(pnsystem) + +`y`-component of the orientation `Rotor` of the binary. + +See [`R`](@ref) for details. +""" +@public function Rʸ(::T) where {T<:PNSystem} + error("Rʸ is not (yet) defined for PNSystem subtype `$T`.") +end +Rʸ(fdpnsystem::FDPNSystem) = fdpnsystem[:Rʸ] +@public const Ry = Rʸ + +""" + Rᶻ(pnsystem) + Rz(pnsystem) + +`z`-component of the orientation `Rotor` of the binary. + +See [`R`](@ref) for details. +""" +@public function Rᶻ(::T) where {T<:PNSystem} + error("Rᶻ is not (yet) defined for PNSystem subtype `$T`.") +end +Rᶻ(fdpnsystem::FDPNSystem) = fdpnsystem[:Rᶻ] +@public const Rz = Rᶻ + +@doc raw""" + v(pnsystem) + v(;Ω, M=1) + +Post-Newtonian velocity parameter. This is related to the orbital angular frequency +``\Omega`` as +```math +v \colonequals (G\,M\,\Omega)^{1/3}, +``` +where [`M`](@ref) is the total mass of the binary, and [`G`](@ref) is the gravitational +constant. This has units of speed, so it must be divided by [`c`](@ref) to be +dimensionless. In particular, it is related to the "frequency-related parameter" +[`x`](@ref) via +```math +x = \left(\frac{v}{c}\right)^{2}. +``` + +Note that if you want to pass the value ``Ω`` (rather than a `PNSystem`), you *must* pass it +as a keyword argument — as in `v(Ω=0.1)`. + +See also [`Ω`](@ref) and [`x`](@ref). +""" +@public function v(::T) where {T<:PNSystem} + error("v is not (yet) defined for PNSystem subtype `$T`.") +end +v(fdpnsystem::FDPNSystem) = fdpnsystem[:v] +v(; Ω, M=1) = ∛(M * Ω) + +""" + Φ(pnsystem) + Phi(pnsystem) + +Integrated orbital phase of the system. It is computed as the integral of [`Ω`](@ref). +""" +@public function Φ(::T) where {T<:PNSystem} + error("Φ is not (yet) defined for PNSystem subtype `$T`.") +end +Φ(fdpnsystem::FDPNSystem) = fdpnsystem[:Φ] +@public const Phi = Φ + +@doc raw""" + Λ₁(pnsystem) + Lambda1(pnsystem) + +Quadrupolar tidal-coupling parameter of object 1 in this system. + +We imagine object 1 begin placed in an (adiabatic) external field with Newtonian potential +``\phi``, resulting in a tidal field measured by ``\partial_i \partial_j \phi`` evaluated at +the center of mass of the object. This induces a quadrupole moment ``Q_{ij}`` in object 1, +which can be related to the tidal field as +```math +Q_{ij} = -\frac{G^4}{c^{10}} \Lambda_1 M_1^5 \partial_i \partial_j \phi, +``` +where ``M_1`` is the mass of object 1. This tidal-coupling parameter ``\Lambda_1`` can be +related to the Love number ``k_2`` (where the subscript 2 refers to the fact that this is +for the ``\ell=2`` quadrupole, rather than object 2) as +```math +\Lambda_1 = \frac{2}{3} \frac{c^{10}}{G^5} \frac{R_1^5}{M_1^5} k_2, +``` +where ``R_1`` is the radius of object 1. Note that ``\Lambda_1`` is dimensionless. For +black holes, it is precisely zero; for neutron stars it may range up to 1; more exotic +objects may have significantly larger values. + +Note that — as of this writing — only `NSNS` systems can have a nonzero value for this +quantity. (`BHNS` systems can only have a nonzero value for ``\Lambda_2``.) All other +types return `0`, which Julia can use to eliminate code that would then be 0. Thus, it is +safe and efficient to use this quantity in any PN expression that specializes on the type of +`pnsystem`. + +See also [`Λ₂`](@ref) and [`Λ̃`](@ref). +""" +@public function Λ₁(::T) where {T<:PNSystem} + error("Λ₁ is not (yet) defined for PNSystem subtype `$T`.") +end +Λ₁(fdpnsystem::FDPNSystem) = fdpnsystem[:Λ₁] +@public const Lambda1 = Λ₁ + +@doc raw""" + Λ₂(pnsystem) + Lambda2(pnsystem) + +Quadrupolar tidal coupling parameter of object 2 in this system. + +See [`Λ₁`](@ref) for details about the definition, swapping "object 1" with "object 2". + +Note that — as of this writing — only `BHNS` and `NSNS` systems can have a nonzero value for +this quantity. All other types return `0`, which Julia can use to eliminate code that would +then be 0. Thus, it is safe and efficient to use this quantity in any PN expression that +specializes on the type of `pnsystem`. + +See also [`Λ₁`](@ref) and [`Λ̃`](@ref). +""" +@public function Λ₂(::T) where {T<:PNSystem} + error("Λ₂ is not (yet) defined for PNSystem subtype `$T`.") +end +Λ₂(fdpnsystem::FDPNSystem) = fdpnsystem[:Λ₂] +@public const Lambda2 = Λ₂ + +################################################################# +# Not actually state variables, but aggregates of state variables + +""" + χ⃗₁(pnsystem) + chi1(pnsystem) + +Dimensionless spin vector of object 1 in this system, as a `QuatVec`. + +See also [`χ₁ˣ`](@ref), [`χ₁ʸ`](@ref), and [`χ₁ᶻ`](@ref) for the individual components. +""" +@public function χ⃗₁(::T) where {T<:PNSystem} + QuatVec(χ₁ˣ(pnsystem), χ₁ʸ(pnsystem), χ₁ᶻ(pnsystem)) +end +@public const chi1 = χ⃗₁ + +""" + χ⃗₂(pnsystem) + chi2(pnsystem) + +Dimensionless spin vector of object 2 in this system, as a `QuatVec`. + +See also [`χ₂ˣ`](@ref), [`χ₂ʸ`](@ref), and [`χ₂ᶻ`](@ref) for the individual components. +""" +@public function χ⃗₂(::T) where {T<:PNSystem} + QuatVec(χ₂ˣ(pnsystem), χ₂ʸ(pnsystem), χ₂ᶻ(pnsystem)) +end +@public const chi2 = χ⃗₂ + +""" + R(pnsystem) + +Orientation of the binary, as a `Rotor`. + +At any instant, the binary is represented by the right-handed triad ``(n̂, λ̂, ℓ̂)``, where +[``n̂``](@ref PostNewtonian.n̂) is the unit vector pointing from object 2 to object 1, and +the instantaneous velocities of the binary's elements are in the ``n̂``-``λ̂`` plane. This +`Rotor` will rotate the ``x̂`` vector to be along ``n̂``, the ``ŷ`` vector to be along +``λ̂``, and the ``ẑ`` vector to be along ``ℓ̂``. + +Note that the angular velocity associated to `R` is given by ``Ω⃗ = 2 Ṙ R̄ = Ω ℓ̂ + ϖ n̂``. +(Any component of ``Ω⃗`` along ``λ̂`` would violate the condition that the velocities be in +the ``n̂``-``λ̂`` plane.) Here, the scalar quantity ``Ω`` is the orbital angular frequency, +and ``ϖ`` is the precession angular frequency. + +See also [`n̂`](@ref PostNewtonian.n̂), [`λ̂`](@ref PostNewtonian.λ̂), [`ℓ̂`](@ref +PostNewtonian.ℓ̂), [`Ω`](@ref PostNewtonian.Ω), and [`𝛡`](@ref PostNewtonian.𝛡)``=ϖ n̂``. +""" +@public function R(pnsystem::T) where {NT,T<:PNSystem{NT}} + # We use this explicit constructor (with type parameter) to avoid normalization + # that would probably just complicate derivatives. + Rotor{NT}(Rʷ(pnsystem), Rˣ(pnsystem), Rʸ(pnsystem), Rᶻ(pnsystem)) +end +R(fdpnsystem::FDPNSystem) = fdpnsystem[:R] + +@testitem "State variables" begin + # Test BBH, BHNS, and NSNS state variables + for pnsystem ∈ (BBH(randn(14)), BHNS(randn(15)), NSNS(randn(16))) + for (i, (s, a)) ∈ enumerate(zip(symbols(pnsystem), ascii_symbols(pnsystem))) + @test PostNewtonian.eval(s)(pnsystem) == pnsystem.state[i] + @test PostNewtonian.eval(a)(pnsystem) == pnsystem.state[i] + end + end + bbh = BBH(randn(14)) + @test PostNewtonian.Λ₁(bbh) == 0 + @test PostNewtonian.Λ₂(bbh) == 0 + @test PostNewtonian.Lambda1(bbh) == 0 + @test PostNewtonian.Lambda2(bbh) == 0 + bhns = BHNS(randn(15)) + @test PostNewtonian.Λ₁(bhns) == 0 + @test PostNewtonian.Lambda1(bhns) == 0 + + # Test FDPNSystem state variables + for pnsystem ∈ (BBH(randn(14)), BHNS(randn(15)), NSNS(randn(16))) + fdpnsystem = FDPNSystem(pnsystem) + for (i, (s, a)) ∈ enumerate(zip(symbols(pnsystem), ascii_symbols(pnsystem))) + @test PostNewtonian.eval(s)(fdpnsystem).node_value == s + @test PostNewtonian.eval(a)(fdpnsystem).node_value == s + end + end +end diff --git a/src/pn_systems/vector_interface.jl b/src/pn_systems/vector_interface.jl new file mode 100644 index 00000000..8cd0a744 --- /dev/null +++ b/src/pn_systems/vector_interface.jl @@ -0,0 +1,292 @@ +function Base.ismutable(pnsystem::PNSystem{NT,PNOrder,ST}) where {NT,PNOrder,ST} + ismutable(state(pnsystem)) +end +function Base.ismutabletype(::Type{<:PNSystem{NT,PNOrder,ST}}) where {NT,PNOrder,ST} + ismutabletype(ST) +end + +### Symbol-based indexing +""" + symbol_index(::Type{T}, s::Symbol) where {T<:PNSystem} + symbol_index(::Type{T}, ::Val{S}) where {T<:PNSystem,S} + +Return the index of the symbol `s` in the state vector of the given `PNSystem` type `T`. + +Note that the default implementation is slow; `symbol_index(::Type{T}, ::Val{s})` should be +overridden for every symbol (and ASCII equivalent, if desired) for concrete `PNSystem` +types. +""" +@export function symbol_index(::Type{T}, ::Val{S}) where {T<:PNSystem,S} + index = findfirst(y -> y == S, symbols(T)) + if isnothing(index) + index = findfirst(y -> y == S, ascii_symbols(T)) + end + if isnothing(index) + error( + "Type `$(T)` has no symbol `:$(S)`.\n" * + "This type's symbols are `$(symbols(T))`.\n" * + "The ASCII equivalents are `$(ascii_symbols(T))`.\n", + ) + else + @warn "Please define `PostNewtonian.symbol_index(::Type{$T}, ::Val{$S})`" + index + end +end +Base.getindex(pnsystem::PNSystem, s::Symbol) = getindex(pnsystem, Val(s)) +function Base.getindex(pnsystem::T, s::Val{S}) where {T<:PNSystem,S} + # If `S` is not actually a symbol in `pnsystem`, `symbol_index` will error, so we know + # that the `index` is inbounds if it returns. + index = symbol_index(T, s) + @inbounds state(pnsystem)[index] +end +Base.setindex!(pnsystem::PNSystem, v, s::Symbol) = setindex!(pnsystem, v, Val(s)) +function Base.setindex!(pnsystem::T, v, ::Val{S}) where {T<:PNSystem,S} + index = symbol_index(T, Val(S)) + @inbounds setindex!(state(pnsystem), v, index) +end + +### Interfaces: https://docs.julialang.org/en/v1/manual/interfaces +# Iteration +# Base.iterate(pnsystem::PNSystem) = iterate(state(pnsystem)) +# Base.iterate(pnsystem::PNSystem, state) = iterate(state(pnsystem), state) +Base.IteratorSize(::Type{T}) where {T<:PNSystem} = Base.HasShape{1}() +Base.length(pnsystem::PNSystem) = length(state(pnsystem)) +Base.ndims(pnsystem::PNSystem) = ndims(state(pnsystem)) +Base.size(pnsystem::PNSystem) = size(state(pnsystem)) +Base.size(pnsystem::PNSystem, dim) = size(state(pnsystem), dim) +Base.IteratorEltype(::Type{T}) where {T<:PNSystem} = Base.HasEltype() +# Base.eltype(::Type{<:PNSystem{NT}}) where {NT} = NT ## Already defined in `PNSystem.jl` +Base.isdone(pnsystem::PNSystem) = Base.isdone(state(pnsystem)) +Base.isdone(pnsystem::PNSystem, iterstate) = Base.isdone(state(pnsystem), iterstate) +# Indexing +@propagate_inbounds Base.getindex(pnsystem::PNSystem, i::T) where {T} = getindex( + state(pnsystem), i +) +@propagate_inbounds Base.setindex!(pn::PNSystem, v, i::T) where {T} = setindex!( + state(pn), v, i +) +@propagate_inbounds Base.getindex(pnsystem::PNSystem, i...) = getindex( + state(pnsystem), i... +) +@propagate_inbounds Base.setindex!(pn::PNSystem, v, i...) = setindex!(state(pn), v, i...) +Base.firstindex(pnsystem::PNSystem) = firstindex(state(pnsystem)) +Base.lastindex(pnsystem::PNSystem) = lastindex(state(pnsystem)) +Base.eachindex(pnsystem::PNSystem) = eachindex(state(pnsystem)) +# Abstract arrays +Base.IndexStyle(::Type{T}) where {T<:PNSystem} = Base.IndexLinear() +# Base.length(pnsystem::PNSystem) = length(state(pnsystem)) ## Already defined above +# Base.similar(pnsystem::PNSystem) = similar(state(pnsystem)) +Base.axes(pnsystem::PNSystem) = axes(state(pnsystem)) +# Strided Arrays +Base.strides(pnsystem::PNSystem) = strides(state(pnsystem)) +function Base.unsafe_convert(::Type{Ptr{ST}}, pnsystem::PNSystem{ST}) where {ST} + Base.unsafe_convert(Ptr{ST}, state(pnsystem)) +end +Base.elsize(::Type{<:PNSystem{T}}) where {T} = sizeof(T) +Base.stride(pnsystem::PNSystem, k::Int) = stride(state(pnsystem), k) + +# NamedTuple interface +function Base.convert(::Type{NamedTuple}, pnsystem::PNSystem{N,P,S}) where {N,P,S} + NamedTuple{symbols(pnsystem),NTuple{length(pnsystem),N}}(state(pnsystem)) +end +Base.keys(pnsystem::PNSystem) = symbols(pnsystem) +function Base.pairs(pnsystem::PNSystem{N,P,S}) where {N,P,S} + (s=>v for (s, v) ∈ zip(symbols(pnsystem), state(pnsystem))) +end + +Base.@propagate_inbounds function Base.getindex( + pnsystem::PNSystem, s::AbstractVector{Symbol} +) + # We trick broadcasting into treating `pnsystem` as a scalar by putting it into a + # 1-tuple. + getindex.((pnsystem,), s) +end + +Base.copy(pnsystem::PNSystem) = typeof(pnsystem)(copy(state(pnsystem))) +Base.copyto!(x::PNSystem, y::PNSystem) = copyto!(state(x), state(y)) + +# ##################################### +# # Broadcast +# ##################################### +# struct LAStyle{T,N,L} <: Broadcast.AbstractArrayStyle{N} end +# LAStyle{T,N,L}(x::Val{i}) where {T,N,L,i} = LAStyle{T,N,L}() +# Base.BroadcastStyle(::Type{LArray{T,N,D,L}}) where {T,N,D,L} = LAStyle{T,N,L}() +# function Base.BroadcastStyle( +# ::LabelledArrays.LAStyle{T,N,L}, ::LabelledArrays.LAStyle{E,N,L} +# ) where {T,E,N,L} +# LAStyle{promote_type(T, E),N,L}() +# end + +# @generated function labels2axes(::Val{t}) where {t} +# if t isa NamedTuple && all(x -> x isa Union{Integer,UnitRange}, values(t)) # range labelling +# (Base.OneTo(maximum(Iterators.flatten(v for v ∈ values(t)))),) +# elseif t isa NTuple{<:Any,Symbol} +# axes(t) +# else +# error( +# "$t label isn't supported for broadcasting. Try to formulate it in terms of linear indexing.", +# ) +# end +# end +# function Base.similar( +# bc::Broadcast.Broadcasted{LAStyle{T,N,L}}, ::Type{ElType} +# ) where {T,N,L,ElType} +# tmp = similar(Array{ElType}, axes(bc)) +# if axes(bc) != labels2axes(Val(L)) +# return tmp +# else +# return LArray{ElType,N,typeof(tmp),L}(tmp) +# end +# end + +# Broadcasting checks for aliasing with Base.dataids but the fallback +# for AbstractArrays is very slow. Instead, we just call dataids on the +# wrapped state +Base.dataids(pnsystem::PNSystem) = Base.dataids(state(pnsystem)) + +## Misc + +# function ArrayInterface.restructure( +# x::LArray{T,N,D,Syms}, y::LArray{T2,N2,D2,Syms} +# ) where {T,N,D,T2,N2,D2,Syms} +# reshape(y, size(x)...) +# end + +# function PreallocationTools.get_tmp( +# dc::PreallocationTools.DiffCache, u::LArray{T,N,D,Syms} +# ) where {T<:ForwardDiff.Dual,N,D,Syms} +# nelem = div(sizeof(T), sizeof(eltype(dc.dual_du))) * length(dc.du) +# if nelem > length(dc.dual_du) +# PreallocationTools.enlargedualcache!(dc, nelem) +# end +# _x = ArrayInterface.restructure(dc.du, reinterpret(T, view(dc.dual_du, 1:nelem))) +# LabelledArrays.LArray{T,N,D,Syms}(_x) +# end + +# function RecursiveArrayTools.recursive_unitless_eltype( +# a::Type{LArray{T,N,D,Syms}} +# ) where {T,N,D,Syms} +# LArray{typeof(one(T)),N,D,Syms} +# end + +@testitem "Vector interface" begin + using PostNewtonian: state + using LinearAlgebra + + for pnsystem ∈ (BBH(randn(14), 7//2), BHNS(randn(15), 7//2), NSNS(randn(16), 7//2)) + @test_throws ErrorException symbol_index(typeof(pnsystem), Val(:nonexistent_symbol)) + @test symbol_index(typeof(pnsystem), Val(:M₁)) == 1 + @test symbol_index(typeof(pnsystem), Val(:M1)) == 1 + @test pnsystem[:M₁] == pnsystem[:M1] == pnsystem[1] == pnsystem.state[1] + @test symbol_index(typeof(pnsystem), Val(:M₂)) == 2 + @test symbol_index(typeof(pnsystem), Val(:M2)) == 2 + @test pnsystem[:M₂] == pnsystem[:M2] == pnsystem[2] == pnsystem.state[2] + @test symbol_index(typeof(pnsystem), Val(:χ₁ˣ)) == 3 + @test symbol_index(typeof(pnsystem), Val(:chi1x)) == 3 + @test pnsystem[:χ₁ˣ] == pnsystem[:chi1x] == pnsystem[3] == pnsystem.state[3] + @test symbol_index(typeof(pnsystem), Val(:χ₁ʸ)) == 4 + @test symbol_index(typeof(pnsystem), Val(:chi1y)) == 4 + @test pnsystem[:χ₁ʸ] == pnsystem[:chi1y] == pnsystem[4] == pnsystem.state[4] + @test symbol_index(typeof(pnsystem), Val(:χ₁ᶻ)) == 5 + @test symbol_index(typeof(pnsystem), Val(:chi1z)) == 5 + @test pnsystem[:χ₁ᶻ] == pnsystem[:chi1z] == pnsystem[5] == pnsystem.state[5] + @test symbol_index(typeof(pnsystem), Val(:χ₂ˣ)) == 6 + @test symbol_index(typeof(pnsystem), Val(:chi2x)) == 6 + @test pnsystem[:χ₂ˣ] == pnsystem[:chi2x] == pnsystem[6] == pnsystem.state[6] + @test symbol_index(typeof(pnsystem), Val(:χ₂ʸ)) == 7 + @test symbol_index(typeof(pnsystem), Val(:chi2y)) == 7 + @test pnsystem[:χ₂ʸ] == pnsystem[:chi2y] == pnsystem[7] == pnsystem.state[7] + @test symbol_index(typeof(pnsystem), Val(:χ₂ᶻ)) == 8 + @test symbol_index(typeof(pnsystem), Val(:chi2z)) == 8 + @test pnsystem[:χ₂ᶻ] == pnsystem[:chi2z] == pnsystem[8] == pnsystem.state[8] + @test symbol_index(typeof(pnsystem), Val(:Rʷ)) == 9 + @test symbol_index(typeof(pnsystem), Val(:Rw)) == 9 + @test pnsystem[:Rʷ] == pnsystem[:Rw] == pnsystem[9] == pnsystem.state[9] + @test symbol_index(typeof(pnsystem), Val(:Rˣ)) == 10 + @test symbol_index(typeof(pnsystem), Val(:Rx)) == 10 + @test pnsystem[:Rˣ] == pnsystem[:Rx] == pnsystem[10] == pnsystem.state[10] + @test symbol_index(typeof(pnsystem), Val(:Rʸ)) == 11 + @test symbol_index(typeof(pnsystem), Val(:Ry)) == 11 + @test pnsystem[:Rʸ] == pnsystem[:Ry] == pnsystem[11] == pnsystem.state[11] + @test symbol_index(typeof(pnsystem), Val(:Rᶻ)) == 12 + @test symbol_index(typeof(pnsystem), Val(:Rz)) == 12 + @test pnsystem[:Rᶻ] == pnsystem[:Rz] == pnsystem[12] == pnsystem.state[12] + @test symbol_index(typeof(pnsystem), Val(:v)) == 13 + @test pnsystem[:v] == pnsystem[13] == pnsystem.state[13] + @test symbol_index(typeof(pnsystem), Val(:Φ)) == 14 + @test symbol_index(typeof(pnsystem), Val(:Phi)) == 14 + @test pnsystem[:Φ] == pnsystem[:Phi] == pnsystem[14] == pnsystem.state[14] + end + let + pnsystem = BHNS(randn(15), 7//2) + @test symbol_index(typeof(pnsystem), Val(:Λ₂)) == 15 + @test symbol_index(typeof(pnsystem), Val(:Lambda2)) == 15 + # @test pnsystem[:Λ₂] == pnsystem[:Lambda2] == pnsystem[15] == pnsystem.state[15] + end + let + pnsystem = NSNS(randn(16), 7//2) + @test symbol_index(typeof(pnsystem), Val(:Λ₁)) == 15 + @test symbol_index(typeof(pnsystem), Val(:Lambda1)) == 15 + @test pnsystem[:Λ₁] == pnsystem[:Lambda1] == pnsystem[15] == pnsystem.state[15] + @test symbol_index(typeof(pnsystem), Val(:Λ₂)) == 16 + @test symbol_index(typeof(pnsystem), Val(:Lambda2)) == 16 + @test pnsystem[:Λ₂] == pnsystem[:Lambda2] == pnsystem[16] == pnsystem.state[16] + end + + for FT ∈ (Float16, Float32, Float64) + for PNOrder ∈ (0, 1, 3//2, 2, 5//2, 3, 7//2, 4) + pnsystem = BBH(randn(FT, 14), PNOrder) + @test Base.ismutable(pnsystem) + @test Base.ismutabletype(typeof(pnsystem)) + @test collect(pnsystem) == state(pnsystem) + @test length(pnsystem) == 14 + @test ndims(pnsystem) == 1 + @test size(pnsystem) == (14,) + @test size(pnsystem, 1) == 14 + @test axes(pnsystem) == (Base.OneTo(14),) + @test Base.eltype(pnsystem) == FT + @test Base.eltype(typeof(pnsystem)) == FT + @test Base.eltype(state(pnsystem)) == FT + for (i, v) ∈ enumerate(pnsystem) + @test v == pnsystem[i] == pnsystem.state[i] + end + for (i, v) ∈ enumerate(symbols(pnsystem)) + pnsystem[i] = 2 + @test pnsystem[v] == 2 + @test pnsystem.state[i] == 2 + pnsystem[v] = 3 + @test pnsystem[i] == 3 + @test pnsystem.state[i] == 3 + end + @test [pnsystem[i] for i ∈ firstindex(pnsystem):lastindex(pnsystem)] == pnsystem.state + @test [pnsystem[i] for i ∈ eachindex(pnsystem)] == pnsystem.state + @test eachindex(pnsystem) == axes(pnsystem, 1) + if FT ≠ Float16 + @test state(LinearAlgebra.BLAS.scal(FT(1.2), pnsystem)) ≈ 1.2state(pnsystem) atol=0 rtol=4eps( + FT + ) + end + @test stride(pnsystem, 1) == strides(state(pnsystem))[1] + @test Base.elsize(pnsystem) == sizeof(FT) + @test Base.elsize(typeof(pnsystem)) == sizeof(FT) + nt = convert(NamedTuple, pnsystem) + for symbol ∈ symbols(pnsystem) + @test haskey(nt, symbol) + @test nt[symbol] == pnsystem[symbol] + end + @test keys(pnsystem) == symbols(pnsystem) + @test collect(pairs(pnsystem)) == + collect(k=>v for (k, v) ∈ zip(symbols(pnsystem), state(pnsystem))) + @test pnsystem[collect(symbols(pnsystem))] == state(pnsystem) + pnsystem2 = BBH(randn(FT, 14), PNOrder) + pnsystem3 = copy(pnsystem2) + @test typeof(pnsystem2) == typeof(pnsystem3) + @test pnsystem2 == pnsystem3 + @test state(pnsystem2) == state(pnsystem3) + copyto!(pnsystem, pnsystem2) + @test typeof(pnsystem) == typeof(pnsystem2) + @test pnsystem == pnsystem2 + @test state(pnsystem) == state(pnsystem2) + end + end +end diff --git a/src/predefinitions_Symbolics.jl b/src/predefinitions_Symbolics.jl index c92eb0f2..951a5b9b 100644 --- a/src/predefinitions_Symbolics.jl +++ b/src/predefinitions_Symbolics.jl @@ -37,7 +37,7 @@ julia> using Symbolics julia> using PostNewtonian: M₁, M₂, χ⃗₁, χ⃗₂, SymbolicPNSystem julia> symbolic_pnsystem = SymbolicPNSystem() -SymbolicPNSystem{Vector{Num}, 9223372036854775805//2, Num}(Num[M₁, M₂, χ⃗₁ˣ, χ⃗₁ʸ, χ⃗₁ᶻ, χ⃗₂ˣ, χ⃗₂ʸ, χ⃗₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ], Λ₁, Λ₂) +SymbolicPNSystem{Vector{Num}, 9223372036854775805//2, Num}(Num[M₁, M₂, χ₁ˣ, χ₁ʸ, χ₁ᶻ, χ₂ˣ, χ₂ʸ, χ₂ᶻ, Rʷ, Rˣ, Rʸ, Rᶻ, v, Φ], Λ₁, Λ₂) julia> M₁(symbolic_pnsystem), M₂(symbolic_pnsystem) (M₁, M₂) diff --git a/src/utilities.jl b/src/utilities.jl deleted file mode 100644 index 615a5069..00000000 --- a/src/utilities.jl +++ /dev/null @@ -1,9 +0,0 @@ -include("utilities/mathconstants.jl") -include("utilities/misc.jl") -include("utilities/truncated_series_monoid.jl") -include("utilities/truncated_series_inversion.jl") -include("utilities/combine_solutions.jl") -include("utilities/termination_criteria.jl") - -# Don't include macros.jl yet; we need to get contents of `FundamentalVariables` and -# `DerivedVariables`, so that's included by `pn_expressions.jl`. diff --git a/src/utilities/macros.jl b/src/utilities/macros.jl deleted file mode 100644 index 264079da..00000000 --- a/src/utilities/macros.jl +++ /dev/null @@ -1,198 +0,0 @@ -""" - type_converter(pnsystem, x) - -Convert `x` to a type appropriate for the float type of `pnsystem`. - -This is sort of an expansion of the `convert` function, but with nicer syntax for types from -this package, including the ability to do really weird things for `SymbolicPNSystem`. It's -needed to ensure that the types of variables and constants are correct when we use them in -expressions, rather than just assuming everything is a `Float64`. -""" -function type_converter(pnsystem, x) - return convert(eltype(pnsystem), x) -end -function type_converter(::FDPNSystem{FT}, x) where {FT} - return x -end -function type_converter(::FDPNSystem{FT}, x::Integer) where {FT} - return convert(FT, x) -end -function type_converter(::FDPNSystem{FT}, x::Rational) where {FT} - return convert(FT, x) -end -function type_converter(::FDPNSystem{FT}, x::AbstractIrrational) where {FT} - return convert(FT, x) -end - -fundamental_variables = methodswith(PNSystem, FundamentalVariables) -fundamental_quaternionic_variables = [ - m for m ∈ methodswith(AbstractVector, FundamentalVariables) if m.name ∈ [:χ⃗₁, :χ⃗₂, :R] -] -derived_variables = methodswith(VecOrPNSystem, DerivedVariables) -pnvariables = map(v -> v.name, [fundamental_variables; derived_variables]) - -irrationals = unique( - [ - find_symbols_of_type(Base.MathConstants, Irrational) - find_symbols_of_type(MathConstants, Irrational) - ], -) - -# This should include all the unary functions that we want to use in any PN expression. -unary_funcs = [:√, :sqrt, :log, :ln, :sin, :cos] -# unary_funcs = Dict( -# :√ => :(Base.sqrt), -# :sqrt => :(Base.sqrt), -# :log => :(Base.log), -# :ln => :(Base.log), -# ) - -# for (expr, f) ∈ pairs(unary_funcs) -# if expr ∈ (:sqrt, :ln) # These are just aliases, so avoid redefinitions -# continue -# end -# @eval begin -# $f(::Type{T}, x) where T = $f(x) -# $f(::Type{T}, x::Int) where T = $f(T(x)) -# $f(::Type{T}, x::Rational) where T = $f(T(x)) -# $f(::Type{T}, x::Irrational) where T = $f(T(x)) -# end -# end - -function pn_expression(pnsystem::Symbol, body) - # Look for variables in `body` that we need to treat specially, and write exprs to do - # so. These three are described as bullet points in the docstring of `@pn_expression`. - pnvariables_exprs = [ - :($v = $v($pnsystem)) for v ∈ filter(v -> MacroTools.inexpr(body, v), pnvariables) - ] - irrationals_exprs = [ - :($v = type_converter($pnsystem, $v)) for - v ∈ filter(v -> MacroTools.inexpr(body, v), irrationals) - ] - unary_funcs_exprs = [ - :($v = (x -> $v(type_converter($pnsystem, x)))) for - v ∈ filter(v -> MacroTools.inexpr(body, v), unary_funcs) - ] - - exprs = [ - pnvariables_exprs - irrationals_exprs - unary_funcs_exprs - ] - - # Next, add pnsystem as the argument to each @pn_expansion call - new_body = MacroTools.unblock( - macroexpand( - @__MODULE__, - MacroTools.postwalk(body) do x - if MacroTools.isexpr(x, :macrocall) && - x.args[1] == Symbol("@pn_expansion") && - !isa(x.args[end - 1], Symbol) - x′ = deepcopy(x) - insert!(x′.args, length(x′.args), pnsystem) - x′ - else - x - end - end; - recursive=true, - ), - ) - - # Finally, just wrap `new_body` in a `let` block, where we include exprs created above. - # Also include the definitions `c=G=1` (to be overwritten inside any `@pn_expansion`). - full_body = MacroTools.unblock(quote - let c=G=one(pnsystem) - #@fastmath - let $(exprs...) - $(new_body) - end - end - end) - return full_body -end - -function pn_expression(arg_index::Integer, func) - splitfunc = MacroTools.splitdef(func) - pnsystem = MacroTools.namify(splitfunc[:args][arg_index]) - splitfunc[:kwargs] = [ - splitfunc[:kwargs] - :($(Expr(:kw, :(pn_expansion_reducer::Val{PNExpansionReducer}), :(Val(sum))))) - ] - splitfunc[:whereparams] = (splitfunc[:whereparams]..., :PNExpansionReducer) - splitfunc[:body] = pn_expression(pnsystem, splitfunc[:body]) - return MacroTools.combinedef(splitfunc) -end - -""" - @pn_expression [arg_index=1] func - -This macro takes the function `func`, looks for various symbols inside that function, and if -present defines them appropriately inside that function. - -The first argument to this macro is `arg_index`, which just tells us which argument to the -function `func` is a `PNSystem`. For example, the variables defined in -[`PostNewtonian.FundamentalVariables`](@ref "Fundamental variables") all take a single -argument of `pnsystem`, which is used to compute the values for those variables; this macro -just needs to know where to find `pnsystem`. - -Once it has this information, there are five types of transformations it will make: - - 1. Adds a keyword argument `pn_expansion_reducer::Val{PNExpansionReducer}=Val(sum)` to the - function signature. This is used to determine how to reduce the PN expansion terms. - The default is `Val(sum)`, which will just return a single number, but `Val(identity)` - can be used to return the expansion. This should be used inside the function as - `PNExpansionReducer`, and will be automatically used inside any `@pn_expansion`. - 2. For every [fundamental](@ref "Fundamental variables") or [derived](@ref "Derived - variables") variable, the name of that variable used in the body of `func` will be - replaced by its value when called with `pnsystem`. For example, you can simply use the - symbols `M₁` or `μ` in your code, rather than calling them as [`M₁(pnsystem)`](@ref M₁) - or [`μ(pnsystem)`](@ref μ) every time they appear. - 3. Every `Irrational` defined in `Base.MathConstants` or `PostNewtonian.MathConstants` will - be transformed to the `eltype` of `pnsystem`. This lets you naturally use such - constants in expressions like `2π/3` without automatically converting to `Float64`. - 4. Each of a short list of functions given by `unary_funcs` in `utilities/macros.jl` will - first convert their arguments to the `eltype` of `pnsystem`. In particular, you can use - expressions like `√10` or `ln(2)` without the result being converted to a `Float64`. - 5. Insert the `pnsystem` argument as the first argument to each occurrence of - `@pn_expansion` that needs it. - -To be more explicit, the first three are achieved by defining the relevant quantities in a -`let` block placed around the body of `func`, so that the values may be used efficiently -without recomputation. - -If you need to use one of the fundamental- or derived-variable functions as arguments of -values other than those encapsulated in `pnsystem`, you'll need to address them explicitly -with the module name — as in `PostNewtonian.v(;Ω, M)`. -""" -macro pn_expression(func) - return esc(pn_expression(1, func)) -end - -macro pn_expression(arg_index, func) - return esc(pn_expression(arg_index, func)) -end - -""" - @pn_expansion [pnsystem] expansion - -Gather terms in `expansion` by the powers of ``1/c`` involved, zeroing out any terms with -powers of ``1/c`` higher than the `pnsystem`'s `PNOrder` parameter, and combine the terms -using the `PNExpansionReducer` specified in argument of the function that includes this -macro call. - -This expansion is achieved by setting — inside a `let` block created by this macro — - -Note that the `pnsystem` argument can be inserted automatically by [`@pn_expression`](@ref). -""" -macro pn_expansion(pnsystem, expr) - return esc(pn_expansion(pnsystem, expr)) -end - -function pn_expansion(pnsystem, expr) - quote - let c = PNExpansionParameter($pnsystem) - PNExpansionReducer($expr) - end - end -end diff --git a/src/utilities/mathconstants.jl b/src/utilities/mathconstants.jl deleted file mode 100644 index df235b82..00000000 --- a/src/utilities/mathconstants.jl +++ /dev/null @@ -1,183 +0,0 @@ -module MathConstants - -export log2, - ln2, - log3, - ln3, - log5, - ln5, - log3halves, - log³╱₂, - ln³╱₂, - log5halves, - log⁵╱₂, - ln⁵╱₂, - apery, - ζ3, - γₑ, - 𝒾 - -Base.@irrational ln2 0.6931471805599453 log2 -Base.@irrational γₑ 0.57721566490153286061 euler -Base.@irrational ln3 1.0986122886681097 big"1.098612288668109691395245236922525704647490557822749451734694333637494293218608966873615754813732088787970029" -Base.@irrational ln5 1.6094379124341003 big"1.60943791243410037460075933322618763952560135426851772191264789147417898770765776463013387809317961" -Base.@irrational ln³╱₂ 0.4054651081081644 big"0.40546510810816438197801311546434913657199042346249419761401432414410067124891425126775242781731340" -Base.@irrational ln⁵╱₂ 0.9162907318741551 big"0.91629073187415506518352721176801107145010121990826246779196788198078536573796304902427055109676092" -Base.@irrational ζ3 1.2020569031595942 big"1.20205690315959428539973816151144999076498629234049888179227155534183820578631309018645587360933525814619915" -const 𝒾 = im - -# When defining @irrationals, if the third argument is a symbol, it is expected to name an -# existing constant compiled into MPFR, with prefix `mpfr_const_`, which is a very limited -# set. All MPFR constants except `log2` already exist in `Base.MathConstants`. Otherwise, -# that third argument should be a literal BigFloat; it cannot be a variable name. - -@doc raw""" - γₑ - -[Euler's constant](https://en.wikipedia.org/wiki/Euler%27s_constant) (also known as the -Euler–Mascheroni constant) is defined as the limit as ``n \to \infty`` of the difference -between the ``n``th partial sum of the harmonic series and ``\log(n)``. This is OEIS -sequence [A001620](https://oeis.org/A001620). - -```julia-repl -julia> PostNewtonian.γₑ -γₑ = 0.5772156649015... - -julia> n=10_000_000; sum(1 ./ (1:n))-log(n) -0.5772157149015307 -``` -""" -γₑ - -""" - ζ3 - apery - -[Apéry's constant](https://en.wikipedia.org/wiki/Ap%C3%A9ry%27s_constant) is -defined as ``ζ(3)``, where ``ζ`` is the Riemann zeta function. This is OEIS -sequence [A002117](https://oeis.org/A002117). - -```julia-repl -julia> PostNewtonian.apery -ζ3 = 1.2020569031595... - -julia> PostNewtonian.ζ3 -ζ3 = 1.2020569031595... - -julia> sum((1:10_000_000).^-3) -1.2020569031595896 -``` -""" -ζ3 -const apery = ζ3 - -""" - ln2 - log2 - -The natural logarithm of 2. This is OEIS sequence -[A002162](https://oeis.org/A002162). - -```julia-repl -julia> PostNewtonian.ln2 -ln2 = 0.6931471805599... - -julia> exp(PostNewtonian.ln2) -2.0 - -julia> exp(big(PostNewtonian.ln2)) -2.0 -``` -""" -ln2 -const log2 = ln2 - -""" - ln3 - log3 - -The natural logarithm of 3. This is OEIS sequence -[A002391](https://oeis.org/A002391). - -```julia-repl -julia> PostNewtonian.ln3 -ln3 = 1.0986122886681... - -julia> exp(PostNewtonian.ln3) -3.0000000000000004 - -julia> exp(big(PostNewtonian.ln3)) -3.0 -``` -""" -ln3 -const log3 = ln3 - -""" - ln5 - log5 - -The natural logarithm of 5. This is OEIS sequence -[A016628](https://oeis.org/A016628). - -```julia-repl -julia> PostNewtonian.ln5 -ln5 = 1.6094379124341... - -julia> exp(PostNewtonian.ln5) -4.999999999999999 - -julia> exp(big(PostNewtonian.ln5)) -5.0 -``` -""" -ln5 -const log5 = ln5 - -""" - ln³╱₂ - log³╱₂ - log3halves - -The natural logarithm of 3//2. This is OEIS sequence -[A016578](https://oeis.org/A016578). - -```julia-repl -julia> PostNewtonian.ln³╱₂ -ln³╱₂ = 0.4054651081081... - -julia> exp(PostNewtonian.ln³╱₂) -1.5 - -julia> exp(big(PostNewtonian.ln³╱₂)) -1.5 -``` -""" -ln³╱₂ -const log³╱₂ = ln³╱₂ -const log3halves = ln³╱₂ - -""" - ln⁵╱₂ - log⁵╱₂ - log5halves - -The natural logarithm of 5//2. This is OEIS sequence -[A016579](https://oeis.org/A016579). - -```julia-repl -julia> PostNewtonian.ln⁵╱₂ -ln⁵╱₂ = 0.9162907318741... - -julia> exp(PostNewtonian.ln⁵╱₂) -2.5 - -julia> exp(big(PostNewtonian.ln⁵╱₂)) -2.5 -``` -""" -ln⁵╱₂ -const log⁵╱₂ = ln⁵╱₂ -const log5halves = ln⁵╱₂ - -end diff --git a/src/utilities/misc.jl b/src/utilities/misc.jl deleted file mode 100644 index 2f8671d1..00000000 --- a/src/utilities/misc.jl +++ /dev/null @@ -1,76 +0,0 @@ -""" - value(x) - -Return `x` or the value wrapped by the `Dual` number `x` -""" -value(x) = hasproperty(x, :value) ? getproperty(x, :value) : x - -""" - find_symbols_of_type(mod, T) - -Given a module `mod` (not just its name, but the actual imported module), find all objects -inside that module that are instances of the given type `T`. The returned quantity is a -vector of `Symbol`s. -""" -function find_symbols_of_type(mod, T) - return filter(n -> getproperty(mod, n) isa T, names(mod)) -end - -""" - iscall(x, symbols) - -Return `true` if the `Expr` `x` is a call to any element of `symbols`. -""" -iscall(x, symbols) = MacroTools.isexpr(x, :call) && x.args[1] ∈ symbols - -""" - isadd(x) - -Return `true` if the `Expr` `x` is a call to `(+)` or `:+`. -""" -isadd(x) = iscall(x, ((+), :+)) - -""" - ismul(x) - -Return `true` if the `Expr` `x` is a call to `(*)` or `:*`. -""" -ismul(x) = iscall(x, ((*), :*)) - -""" - flatten_binary!(expr, symbols) - -Flatten nested binary operations — that is, apply associativity repeatedly. -""" -function flatten_binary!(expr, symbols) - while iscall(expr, symbols) && any(x -> iscall(x, symbols), expr.args[2:end]) - args = expr.args[2:end] - i₊ = findfirst(x -> iscall(x, symbols), args) - args′ = [first(symbols); args[1:(i₊ - 1)]; args[i₊].args[2:end]; args[(i₊ + 1):end]] - expr.args[:] = args′[1:length(expr.args)] - append!(expr.args, args′[(1 + length(expr.args)):end]) - end - return expr -end - -flatten_add!(expr) = flatten_binary!(expr, ((+), :+)) -flatten_mul!(expr) = flatten_binary!(expr, ((*), :*)) - -""" - apply_to_first_add!(expr, func) - -Apply `func` to the first sub-expression found in a "prewalk"-traversal of `expr` that -satisfies [`isadd`](@ref). If `func` acts in place, so does this function. In either case, -the expression should be returned. -""" -function apply_to_first_add!(expr, func) - found_add = false - MacroTools.prewalk(expr) do x - if !found_add && isadd(x) - found_add = true - func(x) - else - x - end - end -end diff --git a/src/utilities/truncated_series_monoid.jl b/src/utilities/truncated_series_monoid.jl deleted file mode 100644 index 97615e9c..00000000 --- a/src/utilities/truncated_series_monoid.jl +++ /dev/null @@ -1,214 +0,0 @@ -@doc raw""" - truncated_series_inverse(a) - truncated_series_inverse!(b, a) - -Given the coefficients `a` of a series, find the coefficients `b` of the *multiplicative* -inverse of that series, up to the order of the original series. That is, if -```math -A \colonequals \sum_{i=0}^n a_{i-1} v^i, -``` -then we return the coefficients `b` of the series -```math -B \colonequals \sum_{i=0}^n b_{i-1} v^i -``` -such that -```math -A\, B = 1 + \mathcal{O}(v^{n+1}). -``` - -See [`lagrange_inversion`](@ref) for the *compositional* inverse (a.k.a. reversion), which -returns the coefficients of ``f^{-1}`` such that ``f^{-1}(f(v)) = v + -\mathcal{O}(v^{n+1})``. - -Note that this function returns the *coefficients* of the inverse, rather than its value. -This is relevant for use in [`truncated_series_product`](@ref) and -[`truncated_series_ratio`](@ref) — the latter of which just combines the former with this -function. - -For example, suppose the input coefficients represent the series -```math -A \colonequals \sum_{i=0}^n a_{i-1} v^i. -``` -(Remember that Julia's indexing is 1-based, so we subtract 1 to get the index of the -coefficient of ``v^i``.) Then we return the coefficients `b` of the series -```math -B \colonequals \sum_{i=0}^n b_{i-1} v^i -``` -such that -```math -A\, B = 1 + \mathcal{O}(v^{n+1}). -``` - -!!! note - This function requires that `a[1]` be nonzero. If you have a series that starts at - a higher term — say, ``v^n`` for ``n>0`` — you should factor out the ``v^n``, and - multiply the series resulting from this function by ``v^{-n}``. - -## Explanation - -The inverse coefficients can be computed fairly easily by induction. Start by defining -```math -b_0 = 1/a_0. -``` -Now, assuming that we've computed all coefficients up to and including ``b_{i}``, we can -compute ``b_{i+1}`` from the condition that the term proportional to ``v^{i+1}`` in the -product of the series and its inverse must be zero. This gives -```math -b_{i+1} = -b_0\sum_{j=1}^{i} a_j b_{i-j}. -``` -""" -function truncated_series_inverse(a::AbstractVector) - b = similar(a) - return truncated_series_inverse!(b, a) -end - -function truncated_series_inverse(a::NTuple{N,T}) where {N,T} - b = MVector{N,T}(undef) - truncated_series_inverse!(b, SVector{N,T}(a)) - return Tuple(b) -end - -function truncated_series_inverse!(b, a) - @assert length(b) == length(a) - n = length(a) - @inbounds @fastmath if n > 0 - b[0 + 1] = inv(a[0 + 1]) - end - @inbounds @fastmath for i ∈ 0:(n - 2) - b[i + 1 + 1] = - -b[0 + 1] * - sum((a[j + 1] * b[i + 1 - j + 1] for j ∈ 1:(i + 1)); init=zero(eltype(a))) - end - return b -end - -@doc raw""" - truncated_series_product(a, b, v) - -Evaluate the truncated product of the series `a` and `b`, which are expanded in powers of -`v`. - -Note that this function returns the *value* of the summation, rather than its coefficients. - -Here we define the series in terms of the coefficients `a` and `b` as -```math -A \colonequals \sum_{i=0}^n a_{i-1} v^i -\qquad -B \colonequals \sum_{i=0}^n b_{i-1} v^i, -``` -and return the *value* of the product ``A\, B`` truncated at ``v^n``. - -Internally, the sums are performed using `evalpoly`. - -See also [`truncated_series_ratio`](@ref). -""" -function truncated_series_product(a, b, v) - @assert length(a) == length(b) - N = length(a) - 1 - if N < 0 - return zero(v) - end - ex = b[N + 1] * a[1] - for n ∈ (N - 1):-1:0 - ex = muladd(v, ex, b[n + 1] * evalpoly(v, @view a[1:((N - n) + 1)])) - end - return ex -end - -function truncated_series_product(a::NTuple{N,T}, b, v) where {N,T} - @assert length(a) == length(b) - if N < 1 - return zero(v) - end - ex = b[N] * a[1] - for n ∈ (N - 2):-1:0 - ex = muladd(v, ex, b[n + 1] * evalpoly(v, a[1:((N - n - 1) + 1)])) - end - return ex -end - -@doc raw""" - truncated_series_ratio(a, b, v) - -Evaluate the truncated ratio of the series `a` and `b`, which are expanded in powers of `v`. - -Note that this function returns the *value* of the summation, rather than its coefficients. - -Here we define the series in terms of the coefficients `a` and `b` as -```math -A \colonequals \sum_{i=0}^n a_{i-1} v^i -\qquad -B \colonequals \sum_{i=0}^n b_{i-1} v^i, -``` -and return the *value* of the ratio ``A / B`` truncated at ``v^n``. - -This function simply combines [`truncated_series_product`](@ref) and -[`truncated_series_inverse`](@ref). -""" -function truncated_series_ratio(a, b, v) - return truncated_series_product(a, truncated_series_inverse(b), v) -end - -@doc raw""" - truncated_series_ratio(a, b) - -Evaluate the truncated ratio of the series `a` and `b`, evaluated at expansion value 1. -This is relevant when the expansion is not in the dynamic variable `v`, for example, but in -powers of ``1/c`` as in post-Newtonian expansions. (That is, when the `v` dependence is -already include in the input coefficients.) -""" -function truncated_series_ratio(a::NTuple{N1,T1}, b::NTuple{N2,T2}) where {N1,N2,T1,T2} - N = max(N1, N2) - T = promote_type(T1, T2) - if N2 == 0 - throw(DomainError("truncated_series_ratio(a,b): b must have at least one term")) - elseif N1 == 0 - return zero(T) - end - b⁻¹ = MVector{N,T}(undef) - - @inbounds @fastmath begin - b⁻¹[0 + 1] = inv(b[0 + 1]) - for i ∈ 0:(N2 - 2) - b⁻¹[i + 1 + 1] = - -b⁻¹[0 + 1] * - sum((b[j + 1] * b⁻¹[i + 1 - j + 1] for j ∈ 1:(i + 1)); init=zero(T)) - end - for i ∈ (N2 - 1):(N - 2) - b⁻¹[i + 1 + 1] = - -b⁻¹[0 + 1] * - sum((b[j + 1] * b⁻¹[i + 1 - j + 1] for j ∈ 1:(N2 - 1)); init=zero(T)) - end - - a╱b = zero(T) - for i1 ∈ 1:N1 - a╱b += a[i1] * sum((b⁻¹[i2] for i2 ∈ 1:(N - i1 + 1)); init=zero(T)) - end - a╱b - end -end - -@testitem "truncated_series_ratio(a,b)" begin - using Random - using DoubleFloats - import PostNewtonian: truncated_series_inverse, truncated_series_ratio - Random.seed!(123) - for T ∈ [Float32, Float64, Double64] - for N ∈ 1:20 - A = rand(T, N) - A[1] = one(T) + rand(T) / 100 - a = Tuple(A) - x = rand(T) - ϵ = sum(a) * N * eps(T) - for N1 ∈ 1:N - expected = sum(truncated_series_inverse(a)) - unit = zeros(T, N1) - unit[1] = one(T) - @test truncated_series_ratio(Tuple(unit), a) ≈ expected rtol = ϵ - end - @test truncated_series_ratio(a, a) ≈ 1 rtol = ϵ - @test truncated_series_ratio(a, x .* a) ≈ 1 / x rtol = ϵ - @test truncated_series_ratio(x .* a, a) ≈ x rtol = ϵ - end - end -end diff --git a/test/aqua.jl b/test/aqua.jl index 9308612c..7c4d8fd6 100644 --- a/test/aqua.jl +++ b/test/aqua.jl @@ -9,9 +9,9 @@ end @testitem "ExplicitImports tests" begin using ExplicitImports: ExplicitImports - @test ExplicitImports.check_no_implicit_imports(PostNewtonian) === nothing - @test ExplicitImports.check_all_explicit_imports_via_owners(PostNewtonian) === nothing - @test_broken ExplicitImports.check_all_explicit_imports_are_public(PostNewtonian) === + @test ExplicitImports.check_no_implicit_imports(PostNewtonian) ≡ nothing + @test ExplicitImports.check_all_explicit_imports_via_owners(PostNewtonian) ≡ nothing + @test_broken ExplicitImports.check_all_explicit_imports_are_public(PostNewtonian) ≡ nothing @test ExplicitImports.check_no_stale_explicit_imports( PostNewtonian; @@ -32,9 +32,6 @@ end :χ⃗₂, :ℳ, :ln, - :ln2, - :ln3, - :ln5, :order_index, :γₑ, :ζ3, @@ -44,11 +41,10 @@ end :SVector, :Node, ), - ) === nothing - @test ExplicitImports.check_all_qualified_accesses_via_owners(PostNewtonian) === nothing - @test_broken ExplicitImports.check_all_qualified_accesses_are_public(PostNewtonian) === + ) ≡ nothing + @test ExplicitImports.check_all_qualified_accesses_via_owners(PostNewtonian) ≡ nothing + @test_broken ExplicitImports.check_all_qualified_accesses_are_public(PostNewtonian) ≡ + nothing + @test ExplicitImports.check_no_self_qualified_accesses(PostNewtonian; ignore=(:Ω, :v)) ≡ nothing - @test ExplicitImports.check_no_self_qualified_accesses( - PostNewtonian; ignore=(:Ω, :v) - ) === nothing end diff --git a/test/binding_energy_reference.jl b/test/binding_energy_reference.jl index cc7a89c4..2618c20f 100644 --- a/test/binding_energy_reference.jl +++ b/test/binding_energy_reference.jl @@ -36,8 +36,8 @@ function be(pnsystem, deriv) λ₊ = PostNewtonian.λ₊(pnsystem), λ₋ = PostNewtonian.λ₋(pnsystem), π = PostNewtonian.type_converter(pnsystem, π), - ln2 = PostNewtonian.type_converter(pnsystem, PostNewtonian.ln2), - ln3 = PostNewtonian.type_converter(pnsystem, PostNewtonian.ln3), + ln2 = PostNewtonian.type_converter(pnsystem, PostNewtonian.ln(2)), + ln3 = PostNewtonian.type_converter(pnsystem, PostNewtonian.ln(3)), γₑ = PostNewtonian.type_converter(pnsystem, PostNewtonian.γₑ), ln = (x -> log(PostNewtonian.type_converter(pnsystem, x))), pn_order = PostNewtonian.pn_order(pnsystem) @@ -55,7 +55,7 @@ function be(pnsystem, deriv) 77ν^4 / 31104 + 301ν^3 / 1728 + (-498449//3456 + 3157π^2 / 576)ν^2 + - (-123671//5760 + 1792ln2 / 15 + 9037π^2 / 1536 + 896γₑ / 15)ν + (-123671//5760 + 1792ln(2) / 15 + 9037π^2 / 1536 + 896γₑ / 15)ν ) eˡⁿ[8] = (448ν / 15) diff --git a/test/orbital_evolution.jl b/test/orbital_evolution.jl index 8bddeb76..603e8976 100644 --- a/test/orbital_evolution.jl +++ b/test/orbital_evolution.jl @@ -81,7 +81,7 @@ sol_np = orbital_evolution( M₁, M₂, QuatVec(0, 0, χ⃗₁.z), QuatVec(0, 0, χ⃗₂.z), Ωᵢ; Ω₁, Rᵢ, quiet=true ) - for c ∈ [:χ⃗₁ˣ, :χ⃗₁ʸ, :χ⃗₂ˣ, :χ⃗₂ʸ, :Rˣ, :Rʸ] + for c ∈ [:χ₁ˣ, :χ₁ʸ, :χ₂ˣ, :χ₂ʸ, :Rˣ, :Rʸ] @test all(sol_np[c] .== 0) end diff --git a/test/pn_expansion.jl b/test/pn_expansion.jl deleted file mode 100644 index 8497a302..00000000 --- a/test/pn_expansion.jl +++ /dev/null @@ -1,120 +0,0 @@ -@testitem "PNTerm algebra" begin - using DoubleFloats - using PostNewtonian: PNExpansion - - for T ∈ [Float64, Float16, Double64] - pn = rand(BBH; v=T(1) / 5, PNOrder=9//2) - c = PNExpansionParameter(pn) - z = zero(T) - x = T(6) / 5 - y = T(17) / 5 - w = T(28) / 5 - v = T(27) / 13 - - # Test behavior of `c` as the basic PNTerm - for (term, c⁻¹exponent, coeff) ∈ ( - (c, -1, 1), - (c^2, -2, 1), - (x * c^2, -2, x), - (c^2 * x, -2, x), - (c^2 / x, -2, 1 / x), - ((x * c)^2, -2, x^2), - ((x * c^2) / c^4, 2, x), - ((x * c^2) / c^-4, -6, x), - ((x / c^2) / c^4, 6, x), - ((x / c^2) * (y / c^4), 6, x * y), - ) - @test PostNewtonian.c⁻¹exp(term) == c⁻¹exponent - @test term.coeff == coeff - @test term.coeff isa eltype(pn) - @test length(term) == 1 - @test eltype(term) === T - end - - # Test PNExpressions - @test_throws ArgumentError PNExpansion((), 0) - for (expr, expected) ∈ ( - (w - (x - y / c), (w - x, y)), - (w - (x / c - y), (w + y, -x)), - (x - y / c, (x, -y)), - (x / c - y, (-y, x)), - (x / c^6 + y / c, (z, y, z, z, z, z, x)), - (x / c^6 + y / c + w / c^10, (z, y, z, z, z, z, x, z, z, z)), - (x / c^6 - y / c, (z, -y, z, z, z, z, x)), - (x / c^6 - y / c - w, (-w, -y, z, z, z, z, x)), - (x / c^6 - y / c - w / c^10, (z, -y, z, z, z, z, x, z, z, z)), - (x / c^6 - (y / c - w), (w, -y, z, z, z, z, x)), - (x / c^6 - (y / c - w / c^10), (z, -y, z, z, z, z, x, z, z, z)), - (-(x / c^6) - y / c, (z, -y, z, z, z, z, -x)), - (-(x / c^6) - y / c - w, (-w, -y, z, z, z, z, -x)), - (-(x / c^6) - y / c - w / c^10, (z, -y, z, z, z, z, -x, z, z, z)), - ((x * c^2) / c^4 + y / c, (z, y, x)), - ((x * c^2) / c^4 + y / c + w, (w, y, x)), - ((x * c^2) / c^9 + y / c + w, (w, y, z, z, z, z, z, x)), - (w + (x * c^2) / c^4 + y / c, (w, y, x)), - (w + (x * c^2) / c^9 + y / c, (w, y, z, z, z, z, z, x)), - (w + ((x * c^2) / c^4 + y / c), (w, y, x)), - (w + ((x * c^2) / c^9 + y / c), (w, y, z, z, z, z, z, x)), - (((x * c^2) / c^4 + y / c + w) / c^3, (z, z, z, w, y, x)), - (((x * c^2) / c^4 + y / c + w) / c^5, (z, z, z, z, z, w, y, x)), - (((x * c^2) / c^7 + y / c + w) / c^5, (z, z, z, z, z, w, y, z, z, z)), - (v * (((x * c^2) / c^4 + y / c + w) / c^3), v .* (z, z, z, w, y, x)), - ((((x * c^2) / c^4 + y / c + w) / c^3) * v, v .* (z, z, z, w, y, x)), - ((((x * c^2) / c^4 + y / c + w) / c^3) / v, (z, z, z, w, y, x) .* (1 / v)), - ) - @test expr.coeffs == expected - @test pn_order(expr) == pn_order(pn) - @test sum(expr) == sum(expected) - @test eltype(expr) === T - end - - # Can't make a PNExpression with positive exponents - @test_throws ArgumentError x * c + y - @test_throws ArgumentError x * c + y / c - @test_throws ArgumentError x * c^2 + y - @test_throws ArgumentError x * c^2 + y / c - @test_throws ArgumentError y + x * c - @test_throws ArgumentError y / c + x * c - @test_throws ArgumentError y + x * c^2 - @test_throws ArgumentError y / c + x * c^2 - @test_throws ArgumentError x * c^2 + (y / c + z / c^2) - end -end - -@testitem "PNExpansion algebra" begin - using Symbolics - using PostNewtonian: PNExpansion - - for N1 ∈ 1:9 - for N2 ∈ 1:9 - for NMax ∈ max(N1, N2):(N1 + N2 + 3) - @variables c⁻¹ x[1:N1] y[1:N2] z - poly(e::PNExpansion) = sum(e[i] * c⁻¹^(i - 1) for i ∈ 1:length(e)) - eˣ = PNExpansion(tuple(x...), NMax) - eʸ = PNExpansion(tuple(y...), NMax) - - # Test sums - polysum = simplify(poly(eˣ + eʸ); expand=true) - sumpoly = simplify(poly(eˣ) + poly(eʸ); expand=true) - Δ = simplify(polysum - sumpoly; expand=true) - @test iszero(Δ) - @test_throws ArgumentError eˣ + PNExpansion(tuple(z, x...), NMax + 1) - @test_throws ArgumentError PNExpansion(tuple(z, x...), NMax + 1) + eˣ - - # Test products - polyprod = simplify(poly(eˣ * eʸ); expand=true) - prodpoly = simplify( - substitute( - simplify(poly(eˣ) * poly(eʸ); expand=true), - Dict([c⁻¹^n => 0 for n ∈ NMax:(2NMax + 3)]), - ); - expand=true, - ) - Δ = simplify(polyprod - prodpoly; expand=true) - @test iszero(Δ) - @test_throws ArgumentError eˣ * PNExpansion(tuple(z, x...), NMax + 1) - @test_throws ArgumentError PNExpansion(tuple(z, x...), NMax + 1) * eˣ - end - end - end -end