diff --git a/tracks/mps/solutions/Ranger-123/.gitignore b/tracks/mps/solutions/Ranger-123/.gitignore
new file mode 100644
index 000000000..94ec4eaa6
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/.gitignore
@@ -0,0 +1,15 @@
+.venv*/
+__pycache__/
+*.py[cod]
+.pytest_cache/
+.mypy_cache/
+.ruff_cache/
+.omx/
+work/
+build/
+dist/
+*.egg-info/
+/results/
+/docs/plans/
+/docs/superpowers/
+/julia/Manifest.toml
diff --git a/tracks/mps/solutions/Ranger-123/CITATION.cff b/tracks/mps/solutions/Ranger-123/CITATION.cff
new file mode 100644
index 000000000..7786cfbfb
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/CITATION.cff
@@ -0,0 +1,29 @@
+cff-version: 1.2.0
+title: "Floquet-IF Many-body: N=2,3"
+message: "If you use this research implementation, cite this software and the upstream methods."
+type: software
+authors:
+ - family-names: "Wang"
+ given-names: "Thomas"
+version: 0.1.0
+date-released: 2026-07-29
+license: AGPL-3.0-or-later
+references:
+ - type: article
+ title: "Exact Floquet Dynamics of Strongly Damped Driven Quantum Systems"
+ authors:
+ - family-names: Mickiewicz
+ given-names: Konrad
+ - family-names: Link
+ given-names: Valentin
+ - family-names: Strunz
+ given-names: Walter T.
+ year: 2026
+ doi: 10.1103/5z1m-122d
+ - type: software
+ title: "UniformTEMPO.jl"
+ url: "https://github.com/uniformTEMPO/UniformTEMPO.jl"
+ version: "b76a018c32e5415989761d902b1b0e95f1a337da"
+ - type: software
+ title: "OQuPy"
+ url: "https://github.com/tempoCollaboration/OQuPy"
diff --git a/tracks/mps/solutions/Ranger-123/LICENSE b/tracks/mps/solutions/Ranger-123/LICENSE
new file mode 100644
index 000000000..0ad25db4b
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/LICENSE
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/tracks/mps/solutions/Ranger-123/README.md b/tracks/mps/solutions/Ranger-123/README.md
new file mode 100644
index 000000000..458ebf1e2
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/README.md
@@ -0,0 +1,146 @@
+# Floquet-IF Many-body: N=1--4 validation and N=2,3 production
+
+## Submission
+
+- Team: Ranger
+- Members: Chenxi Wan, Yedi Shen, Junkai Wang
+- Challenge: #123
+- Track: MPS
+- Completed scope: published single-spin validation, reproducible collective
+ common-bath calculations for \(N=2,3\), a convergence-gated \(N=4\) point,
+ and quantitative non-Markovian--Floquet-Markov benchmarks.
+
+This repository is a reproducible implementation of the two- and three-spin
+part of [QuantumBFS/quantum.harness issue #123](https://github.com/QuantumBFS/quantum.harness/issues/123).
+It combines exact symmetry reduction, a public uniform influence-functional
+solver, frequency-resolved bath heat currents, and a Floquet-Markov benchmark.
+
+The production backend is
+[UniformTEMPO.jl](https://github.com/uniformTEMPO/UniformTEMPO.jl), pinned to
+revision `b76a018c32e5415989761d902b1b0e95f1a337da`. The Python layer projects
+the physical model into its symmetry sectors, runs Julia, caches the uniform
+process tensor atomically, inserts operators into the extended process-tensor
+state, separates coherent delta peaks from the decaying correlation, and
+records every convergence comparison in JSON.
+
+## Completed results
+
+- Exact \(N=2\) singlet/triplet reduction, dark singlet, bright gaps, and
+ transition weights.
+- Exact \(N=3\) reflection \(6\oplus2\) reduction and the
+ \(J\)-independent embedded single-spin odd sector.
+- A converged six-point \(N=3\) heat-spectrum grid for
+ \(J/\Omega=0.25,0.5,1\) in both reflection sectors.
+- A converged \(3\times3\) \(N=2\) calibration grid comparing uniform TEMPO
+ with Floquet-Markov/QRT using state, correlation, and heat-spectrum errors.
+- A converged 6/6 same-model \(N=3\) benchmark comparing each existing
+ reflection-sector UniformTEMPO point directly to Floquet-Markov/QRT.
+- Floquet matrix-element, collective-variance, counterterm, and normalization
+ diagnostics.
+- Full convergence of the two bounded-normalization model variants.
+- Compression convergence of both Kac-normalized variants, with their
+ remaining timestep/phase refinement explicitly marked as cluster work.
+- An independent 3/3 reproduction of the published transversal-drive Fig. 3
+ bottom panel, plus a coarse UniformTEMPO--OQuPy cross-check.
+- A converged reflection-odd \(N=4\) pilot with a same-model
+ Floquet-Markov/QRT heat-spectrum error of 3.405 and resolved collective
+ spectral peaks.
+- A converged reflection-even \(N=4\) pilot using an automatically extended
+ six-period correlation window; its same-model heat-spectrum error is 5.494.
+- A pole-resolved, fixed-frequency \(N=1,2,3\) heat-valve pre-scan and
+ three-point \(N=3\) UniformTEMPO go/no-go pilot. The pilot rejects—not
+ confirms—the dark-channel hypothesis: the quasienergy gap collapses while
+ the observable transfer-pole residue increases.
+
+The main \(N=2\) and \(N=3\) results do **not** require a cluster. The failed
+heat-valve pilot does not justify a cluster-scale nine-point continuation.
+Only the optional full Kac refinement does. Reflection-resolved \(N=4\)
+support is implemented and both sector pilots pass all declared gates; the
+even sector records the required six-period tail-window extension explicitly.
+The project makes no thermodynamic-limit, continuum, or critical-exponent
+claim.
+
+## Reproduce
+
+Python 3.12 and Julia 1.12 are the recorded production versions.
+
+```bash
+python3.12 -m venv .venv
+.venv/bin/python -m pip install -e '.[dev,nonmarkov]'
+julia --project=julia -e 'using Pkg; Pkg.instantiate()'
+
+# Exact and legacy validation baselines
+PYTHON_BIN=.venv/bin/python scripts/run_baselines.sh
+PYTHON_BIN=.venv/bin/python scripts/run_pt_baselines.sh
+
+# Resumable production calculation and strict audit
+PYTHON_BIN=.venv/bin/python scripts/run_paper_extension.sh all
+
+# Independent backend checks
+.venv/bin/python scripts/run_uniform_validation.py
+.venv/bin/python scripts/run_fig3_validation.py --drive-frequency 1
+.venv/bin/python scripts/run_fig3_validation.py --drive-frequency 1.5
+.venv/bin/python scripts/run_fig3_validation.py --drive-frequency 2
+.venv/bin/python scripts/run_fig3_validation.py --plot-summary
+
+# Convergence-gated N=4 sector points
+.venv/bin/python -m floquet_if_manybody.cli n4-pilot --sector odd --j 0.25
+.venv/bin/python -m floquet_if_manybody.cli n4-pilot --sector even --j 0.25
+
+# Software and result verification
+.venv/bin/python -m pytest -q
+.venv/bin/python -m ruff check src tests scripts/run_uniform_validation.py scripts/run_fig3_validation.py
+.venv/bin/python -m mypy src scripts/run_fig3_validation.py
+.venv/bin/python -m floquet_if_manybody.cli audit results
+.venv/bin/python -m floquet_if_manybody.cli paper-audit results/paper
+
+# Pole-resolved heat-valve pilot. The audit intentionally exits nonzero
+# because the dark-channel claim gates are not met.
+.venv/bin/python -m floquet_if_manybody.cli heat-valve --pilot
+.venv/bin/python -m floquet_if_manybody.cli \
+ heat-valve-audit results/heat-valve
+```
+
+The production command is resumable. Its cache is content-addressed by the
+physical model, numerical controls, projected operators, solver revision, and
+source revision. Cache files are excluded from the research archive.
+
+The upstream harness excludes machine-generated `results/` data from Git.
+The commands above reproduce those local files. This submission commits the
+publication figures, reports, test suite, and compact validation snapshots;
+`validation/ARTIFACT_PROVENANCE.json` records hashes for the audited local
+artifact set.
+
+To continue the Kac variants on a cluster:
+
+```bash
+FULL_KAC=1 PYTHON_BIN=.venv/bin/python \
+ scripts/run_paper_extension.sh models
+```
+
+## Result guide
+
+| Artifact | Meaning | Status |
+|---|---|---|
+| `figures/n2_exact.*` | Interacting-triplet gaps and bright weights | Exact |
+| `figures/n3_exact.*` | Collective cat gap and weight | Exact |
+| `figures/paper/n3_sector_heat.*` | \(N=3\) even/odd heat spectra | 6/6 converged |
+| `figures/paper/n3_odd_difference.*` | Odd-sector \(J\)-invariance residual | Exact zero on the projected grid |
+| `figures/paper/error_maps.*` | Uniform TEMPO vs Floquet-Markov/QRT | 9/9 converged |
+| `figures/paper/n3_error_maps.*` | Same-parameter \(N=3\) UniformTEMPO vs Floquet-Markov/QRT | 6/6 converged |
+| `figures/validation/fig3_transversal_summary.*` | Published Fig. 3 bottom data vs independent calculation | 3/3 physical gates passed |
+| `figures/paper/n4_odd_j0p25_comparison.*` | Same-model \(N=4\) odd-sector comparison | Converged; heat error 3.405 |
+| `figures/paper/n4_even_j0p25_comparison.*` | Same-model \(N=4\) even-sector comparison | Converged; heat error 5.494 |
+| `figures/paper/dark_diagnostics.*` | Floquet matrix elements, heat, and \(\mathrm{Var}(S)\) | Converged heat plus exact Floquet diagnostic |
+| `figures/paper/model_variants.*` | Bounded/Kac and counterterm comparison | Bounded converged; Kac compression-audited |
+| `figures/heat-valve/heat_valve_hero.*` | Quasienergy collapse tested against exact transfer-pole residues | Pilot complete; dark-channel claim rejected |
+| `docs/heat-valve-result-zh.md` | Fixed-frequency go/no-go evidence and independent claim audit | 3/3 \(N=3\) pilot points; full grid intentionally not run |
+| `validation/*.json` | Artifact provenance and independent backend checks | Diagnostic validation |
+
+See [the Chinese report](docs/report-zh.md),
+[the heat-valve pilot result](docs/heat-valve-result-zh.md),
+[theory conventions](docs/theory.md), [numerical methods](docs/methods.md), and
+the [completion matrix](docs/completion-matrix.md).
+
+This integrated project is distributed under the repository's
+AGPL-3.0-or-later license. Third-party solvers retain their own licenses.
diff --git a/tracks/mps/solutions/Ranger-123/configs/n2_baseline.yaml b/tracks/mps/solutions/Ranger-123/configs/n2_baseline.yaml
new file mode 100644
index 000000000..bd55efec0
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/configs/n2_baseline.yaml
@@ -0,0 +1,13 @@
+model:
+ n: 2
+ j: 0.5
+ omega: 1.0
+ drive_amplitude: 0.2
+ drive_frequency: 0.6180339887498949
+ normalization: bounded
+bath:
+ alpha: 0.05
+ cutoff: 2.5
+ temperature: 0.0
+sector: triplet
+method: finite_memory_if
diff --git a/tracks/mps/solutions/Ranger-123/configs/n3_even_baseline.yaml b/tracks/mps/solutions/Ranger-123/configs/n3_even_baseline.yaml
new file mode 100644
index 000000000..c6aadd299
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/configs/n3_even_baseline.yaml
@@ -0,0 +1,13 @@
+model:
+ n: 3
+ j: 0.5
+ omega: 1.0
+ drive_amplitude: 0.2
+ drive_frequency: 0.4450418679126287
+ normalization: bounded
+bath:
+ alpha: 0.05
+ cutoff: 2.5
+ temperature: 0.0
+sector: even
+method: floquet_markov
diff --git a/tracks/mps/solutions/Ranger-123/configs/n3_odd_check.yaml b/tracks/mps/solutions/Ranger-123/configs/n3_odd_check.yaml
new file mode 100644
index 000000000..bf9cbefb1
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/configs/n3_odd_check.yaml
@@ -0,0 +1,9 @@
+model:
+ n: 3
+ j: 1.0
+ omega: 1.0
+ drive_amplitude: 0.2
+ drive_frequency: 1.0
+ normalization: bounded
+sector: odd
+method: closed
diff --git a/tracks/mps/solutions/Ranger-123/docs/completion-matrix.md b/tracks/mps/solutions/Ranger-123/docs/completion-matrix.md
new file mode 100644
index 000000000..e94fc7dee
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/docs/completion-matrix.md
@@ -0,0 +1,70 @@
+# Completion matrix
+
+| Requirement | Evidence | Status |
+|---|---|---|
+| Reproducible Python/Julia package | `pyproject.toml`, `uv.lock`, pinned source in `julia/Project.toml` | Complete |
+| \(N=2\) singlet dark sector | `tests/test_symmetry_n2.py` | Complete |
+| \(N=2\) exact gaps and weights | `tests/test_spectra_n2.py`, `figures/n2_exact.*` | Complete |
+| \(N=3\) \(6\oplus2\) reflection split | `tests/test_symmetry_n3.py` | Complete |
+| \(N=3\) odd-sector \(J\)-independence | projected operator hashes and zero curve difference | Complete |
+| \(N=3\) cat-gap coefficient | `tests/test_spectra_n3.py` | Complete |
+| Closed Floquet solver | `tests/test_floquet.py` | Complete |
+| Public uniform process-tensor backend | pinned UniformTEMPO revision, Julia runner | Complete |
+| Extended-state multi-time insertions | Julia runner and backend tests | Complete |
+| Delta/continuum separation | correlation and heat-current tests | Complete |
+| Atomic, content-addressed cache | convergence/backend tests | Complete |
+| Nested compression/timestep/phase controller | adaptive tests and per-point evidence | Complete |
+| \(N=3\) even/odd heat grid | `figures/paper/n3_sector_heat.*`, audited local manifest | 6/6 converged |
+| Odd-sector spectral invariance | relative maximum difference 0 | Complete |
+| \(N=2\) exact-vs-Markov grid | `error_map_manifest.json` | 9/9 converged |
+| Three Markov-error metrics | all nine cells | Complete |
+| \(N=3\) same-model exact-vs-Markov grid | `validation/n3_same_model_error_map.json`, `figures/paper/n3_error_maps.*` | 6/6 converged |
+| Floquet dark-channel diagnostics | \(|m|\le40\), Parseval tests | Complete diagnostic |
+| Independent drive/bath normalization | model and projected-sector regression tests | Complete |
+| Floquet transfer eigenvalues and residuals | Julia Krylov extraction plus real \(N=1\) smoke | Complete |
+| Observable pole-residue fit and mode tracking | synthetic exact-recovery and matching tests | Complete |
+| Fixed-frequency \(N=1,2,3\) coherent-destruction scan | `docs/heat-valve-result-zh.md`, hero figure | Complete |
+| \(N=3\) pole-resolved heat-valve pilot | report, hero figure, and audited local manifest | 3/3 executed; claim gates rejected |
+| Nine-point \(N=1,2,3\) heat-valve grid | go/no-go required threefold heat and residue suppression | Intentionally not run: pilot failed |
+| Bounded normalization/counterterm variants | full adaptive evidence | 2/2 converged |
+| Kac normalization/counterterm variants | passed compression evidence | Local endpoint complete; full timestep/phase requires cluster |
+| Independent single-spin validation | `validation/uniform_tempo_single_spin.json` | Passed |
+| Published Fig. 3 bottom-panel reproduction | `validation/fig3_transversal_summary.json`, `figures/validation/fig3_transversal_summary.*` | 3/3 physical gates passed |
+| Independent OQuPy cross-check | `validation/uniform_tempo_oqupy_crosscheck.json` | Diagnostic, not convergence |
+| Publication PNG/PDF figures | `figures/paper` | Visually checked |
+| Pole-resolved hero figure | `figures/heat-valve/heat_valve_hero.{png,pdf}` | Visually checked; labeled candidate/rejected |
+| Chinese report | `docs/report-zh.md` | Complete |
+| Heat-valve negative-result report | `docs/heat-valve-result-zh.md` | Complete |
+| \(N=4\) reflection implementation | `tests/test_symmetry_n4.py`, convergence-gated `n4-pilot` command | Complete, \(10\oplus6\) blocks |
+| \(N=4\) reflection-odd pilot and same-model benchmark | `figures/paper/n4_odd_j0p25_comparison.*` | Converged; \(\epsilon_j=3.405\) |
+| \(N=4\) reflection-even pilot and same-model benchmark | six-period tail-window evidence, comparison figure | Converged; \(\epsilon_j=5.494\) |
+| Continuum and critical exponent | Outside finite-system scope | Not claimed |
+
+## Final gates
+
+```bash
+.venv/bin/python -m pytest -q
+.venv/bin/ruff check src tests scripts/run_uniform_validation.py
+.venv/bin/mypy src
+.venv/bin/python -m floquet_if_manybody.cli audit results
+.venv/bin/python -m floquet_if_manybody.cli paper-audit results/paper
+```
+
+`paper-audit` requires all six \(N=3\) points and all nine error-grid points to
+be converged. It also requires both bounded model variants to be fully
+converged. The two Kac variants are accepted only as an explicitly declared
+timestep resource ceiling after a passed compression comparison; they are
+never re-labeled as converged.
+
+The additional command
+
+```bash
+.venv/bin/python -m floquet_if_manybody.cli \
+ heat-valve-audit results/heat-valve
+```
+
+is expected to return nonzero for the archived pilot. This is a scientific
+result, not a software failure: heat is not suppressed against both flanks,
+the visible pole residue increases, the full nine-point grid was therefore
+not authorized by the predeclared resource gate, and the figure is labeled
+`candidate; claim gates not met`.
diff --git a/tracks/mps/solutions/Ranger-123/docs/heat-valve-result-zh.md b/tracks/mps/solutions/Ranger-123/docs/heat-valve-result-zh.md
new file mode 100644
index 000000000..1580a332d
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/docs/heat-valve-result-zh.md
@@ -0,0 +1,207 @@
+# Floquet pole heat-valve pilot:准能隙塌缩不等于暗通道
+
+## 结论
+
+本轮新增实验完成了一个固定频率、固定浴、可由 transfer poles 独立审计的
+\(N=1,2,3\) Floquet heat-valve 搜索。结果是否定性的:
+
+\[
+\boxed{
+\text{闭系统 quasienergy/cat gap 的深极小}
+\;\not\Rightarrow\;
+\text{开放系统 heat 或 observable residue 变暗}
+}
+\]
+
+在 \(N=3\) 的闭系统扫描中,
+
+\[
+\omega_d=3\Omega,\qquad J=\Omega,\qquad
+\xi=\frac{2A}{\omega_d},
+\]
+
+于 \(\xi=3.05\) 得到
+
+\[
+\Delta_{\rm cat}=5.85\times10^{-5}\Omega.
+\]
+
+但是同一点的 UniformTEMPO 结果显示:
+
+- integrated absolute continuous heat 只从左侧的 0.009806 降到
+ 0.008976,之后在右侧继续降到 0.008747;
+- visible transfer-pole residue weight 从 0.4547 增至 0.9812,并继续
+ 增至 1.5278;
+- dominant residue 同样从 0.2411 增至 0.5370,再增至 0.8276。
+
+所以 \(\xi=3.05\) 既不是双侧 heat minimum,也不是 residue minimum。
+独立审计器正确拒绝 `dark channel` 文字。根据预先规定的 go/no-go gate,
+没有扩展到九个 \(N=1,2,3\) UniformTEMPO 点,也没有提交集群。
+
+
+
+## 1. 为什么要把 drive 和 bath normalization 分开
+
+旧基准使用同一算符同时表示纵向驱动和共同浴耦合:
+
+\[
+S_N=\frac1N M_z.
+\]
+
+这会让“相同 drive amplitude”实际对应不同的每自旋驱动力。新实验明确
+使用
+
+\[
+H_{\rm drive}(t)=A\cos(\omega_dt)M_z,
+\qquad
+H_{SB}=\frac{M_z}{N}\otimes B.
+\]
+
+因此不同 \(N\) 之间保持物理驱动 \(A\) 相同,同时继续使用 bounded bath
+coupling。代码默认仍为旧的 `drive_normalization="coupling"`,只有本实验
+选择 `per_spin`,所以历史结果语义没有改变。
+
+## 2. 预先规定的判据
+
+只有同时满足以下条件,结果才允许称为 dark channel:
+
+1. \(\omega_d,J,\alpha,\omega_c,T_B\) 和 bath normalization 在扫描中固定;
+2. minimum 相对左右两个 flank 的 continuous heat 均至少降低十倍;
+3. 相应 observable transfer-pole residue 相对两个 flank 均至少降低十倍;
+4. transfer eigenpair residual 不超过 \(10^{-8}\);
+5. 所有物理 poles 满足 \(|\lambda|\le1+10^{-6}\);
+6. pole reconstruction 的 normalized \(L^1\) residual 不超过 5%;
+7. trace、Hermiticity、fixed point 和 connected tail 通过物理门槛。
+
+在 pilot 阶段,只有 heat 和 residue 都至少降低三倍,才值得分配资源给完整
+九点网格。这个 pilot gate 远未满足。
+
+## 3. 闭系统预扫描
+
+预扫描固定
+
+\[
+\Omega=1,\quad J=1,\quad\omega_d=3,\quad
+\xi\in[1.8,4.0],
+\]
+
+采用步长 0.05。每个点用 240 个 midpoint Floquet steps。\(N=2\) 投影到
+triplet,\(N=3\) 投影到 reflection-even 六维 sector。
+
+| \(N\) | fitted \(\xi_\ast\) | cat gap | cat-subspace overlap | \(M_z/N\) brightness |
+|---:|---:|---:|---:|---:|
+| 1 | 2.35 | \(1.1402\times10^{-2}\) | 1.0000 | 1.8813 |
+| 2 | 3.65 | \(6.5304\times10^{-2}\) | 0.9378 | 1.8800 |
+| 3 | 3.05 | \(5.8516\times10^{-5}\) | 0.8638 | 1.7279 |
+
+\(N=1\) minimum 靠近第一 Bessel 零点 \(x_1=2.4048256\)。相互作用把
+\(N=2,3\) 的 minima 明显推移。尤其 \(N=3\) gap 很深,但 bath operator 的
+闭系统 brightness 仍为 \(O(1)\),已经预示它可能不是 selection-rule dark
+channel。
+
+## 4. UniformTEMPO transfer-pole pilot
+
+只运行 \(N=3\) 的三点:
+
+\[
+\xi=2.85,\quad3.05,\quad3.20.
+\]
+
+统一数值控制为:
+
+\[
+M=60,\quad \epsilon=10^{-6},\quad N_\phi=3,\quad
+\tau_{\max}=12T,\quad K=8.
+\]
+
+共同浴参数为
+
+\[
+\alpha=0.05,\qquad\omega_c=2.5,\qquad T_B=0.
+\]
+
+UniformTEMPO 固定在 revision
+`b76a018c32e5415989761d902b1b0e95f1a337da`,生产代码 snapshot 为
+`b42725363a01e2ca88b951c3d28026df8104aa40`。
+
+| \(\xi\) | \(\int d\omega\,|\bar j|\) | visible residue | dominant residue | pole fit residual | connected tail |
+|---:|---:|---:|---:|---:|---:|
+| 2.85 | 0.0098063 | 0.45465 | 0.24109 | 0.04171 | 0.12827 |
+| 3.05 | 0.0089765 | 0.98121 | 0.53697 | 0.04452 | 0.19073 |
+| 3.20 | 0.0087470 | 1.52779 | 0.82761 | 0.06341 | 0.20993 |
+
+三点 bond dimension 均为 13。trace error 约 \(8\times10^{-5}\),
+Hermiticity error 约 \(10^{-10}\),fixed-point residual 约
+\(1.2\times10^{-4}\)。最大 eigenpair residual 为
+\(7.04\times10^{-11}\),最大 pole modulus 为 0.99087;因此 Krylov
+eigenpairs 和单位圆检查通过。
+
+三点的 connected tail 均未降到 0.05 以下,右侧点的 pole reconstruction
+也略高于 5%。所以这些数据被诚实标为 pilot / unconverged,而不是最终
+精确热谱。
+
+## 5. 为什么当前证据足以停止扩展
+
+长时间窗可能改变有限窗口 Fourier 积分的精确数值,因此本项目不把三点热谱
+称为完全收敛的负结果。但停止九点扩展不依赖这种细节:
+
+1. \(\xi=3.05\) 相对右侧的 heat ratio 为 1.026,不存在 minimum;
+2. \(\xi=3.05\) 相对较弱 residue flank 的 ratio 为 2.158,方向与
+ suppression 相反;
+3. dominant residue 也单调增大,不是多个小 residues 求和造成的假象;
+4. 前两个点的 pole reconstruction 已低于 5%,但 residue 增强已经超过
+ 两倍。
+
+要从这些数据得到十倍 residue suppression,需要的不是数值微调,而是改变
+物理机制。因此继续延长三点的 correlation window,或把相同假设扩到
+\(N=1,2\) 的六个昂贵点,不能通过 go/no-go 的资源合理性门槛。
+
+## 6. 物理解读
+
+高频纵向驱动给出近似
+
+\[
+\Omega_{\rm eff}\simeq \Omega J_0(2A/\omega_d).
+\]
+
+在铁磁 cluster 中,cat tunneling gap 可以比单自旋 gap 更快塌缩。但共同浴
+同样通过 \(M_z\) 耦合;在 cat basis 中,\(M_z\) 并不会因 tunneling gap
+变小而自动失去矩阵元。这个 pilot 直接展示了两件事必须分开:
+
+\[
+\text{quasienergy collapse}
+\quad\text{与}\quad
+\text{bath-dark observable residue}.
+\]
+
+本例中前者极强,后者反而增强。这是比单纯画一条低热流曲线更有价值的
+诊断:它排除了“看到小 gap 就宣称 many-body dark channel”的常见误判。
+
+## 7. 当前最合理的后续方向
+
+不建议为同一 heat-valve 假设提交集群。若继续 Issue #123,优先级应改为:
+
+1. 把 transfer-pole/residue decomposition 用于已经收敛的 \(N=3\)
+ even/odd 热谱,建立 peak–pole 对应;
+2. 搜索真正满足
+ \(S_{\alpha\beta}^{(m)}=0\) 的 symmetry-protected operator/drive
+ 组合,而不是只搜索 quasienergy crossing;
+3. 只有新的闭系统预扫描同时显示 bright matrix element suppression,才运行
+ 新的 UniformTEMPO pilot;
+4. 不扩展 \(N=4\),也不做 thermodynamic 或 critical claim。
+
+## 8. 可复现命令
+
+```bash
+.venv/bin/python -m floquet_if_manybody.cli heat-valve \
+ --pilot \
+ --output results/heat-valve \
+ --cache results/cache/uniform_tempo \
+ --figures figures/heat-valve
+
+.venv/bin/python -m floquet_if_manybody.cli \
+ heat-valve-audit results/heat-valve
+```
+
+第二条命令预期返回非零,因为 scientific claim gates 被正确拒绝。完整输入、
+三点结果、manifest、PNG/PDF 和审计失败原因均已保留。
diff --git a/tracks/mps/solutions/Ranger-123/docs/methods.md b/tracks/mps/solutions/Ranger-123/docs/methods.md
new file mode 100644
index 000000000..eb2df3a0a
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/docs/methods.md
@@ -0,0 +1,203 @@
+# Numerical methods and evidence labels
+
+## Exact finite-system layer
+
+`exact_diagonalization` constructs the operators in the full computational
+basis and projects them with orthonormal isometries obtained from the exact
+swap/reflection operators. Tests require sector leakage below \(10^{-13}\).
+The resulting physical dimensions are \(d=3\) for the \(N=2\) triplet,
+\(d=6\) for the \(N=3\) reflection-even sector, and \(d=2\) for the
+reflection-odd sector.
+
+`closed_unitary` uses midpoint time ordering,
+
+\[
+U(T)\approx\prod_n\exp[-iH(t_{n+1/2})\delta t],
+\]
+
+and supplies Floquet modes and Fourier matrix elements. Tests cover unitarity,
+the static limit, quasienergy-zone placement, and second-order timestep
+convergence.
+
+## Uniform influence-functional backend
+
+The production method label is `uniform_tempo_floquet_multitime`.
+[UniformTEMPO.jl](https://github.com/uniformTEMPO/UniformTEMPO.jl) is pinned in
+`julia/Project.toml` pins the package source to revision
+`b76a018c32e5415989761d902b1b0e95f1a337da`.
+
+For the zero-temperature Ohmic bath,
+
+\[
+J_B(\omega)=\alpha\omega e^{-\omega/\omega_c},\qquad
+C_B(t)=\frac{\alpha\omega_c^2}{(1+i\omega_ct)^2}.
+\]
+
+The Julia runner builds or reloads a serialized uniform process tensor, forms
+the periodic influence-functional transfer sequence, solves its extended
+Floquet fixed point, and evaluates two-time correlations by inserting
+left-acting system operators into the extended state. It does not apply the
+quantum regression theorem to a reduced density matrix.
+
+The period average uses phase samples across one drive cycle. The correlation
+is decomposed as
+
+\[
+\bar C(\tau)=C_{\rm dec}(\tau)+C_{\rm coh}(\tau).
+\]
+
+Only \(C_{\rm dec}\) is numerically Fourier integrated. Fourier coefficients
+of \(\langle S(t)\rangle\) are stored separately as analytic coherent delta
+weights, preventing finite-window broadening.
+
+## Nested convergence controller
+
+The publication schedule is:
+
+| control | ladder |
+|---|---|
+| steps per period | \(60,90,120\) |
+| uniform compression tolerance | \(3\times10^{-7},10^{-7},3\times10^{-8}\) |
+| phase samples | \(3,15\) |
+
+The inexpensive \(N=2\) error grid may continue the tolerance ladder through
+\(10^{-8}\) and \(3\times10^{-9}\).
+
+At each timestep grid the controller first establishes compression
+convergence. A timestep comparison is accepted only if compression passed on
+both participating grids. Phase refinement is performed only after a
+timestep comparison passes. The residual limits are
+
+\[
+r_\rho\le0.05,\qquad r_C\le0.08,\qquad r_j\le0.08.
+\]
+
+Final physical gates require:
+
+- fixed-point residual \(\le10^{-3}\);
+- trace and Hermiticity errors \(\le5\times10^{-3}\);
+- connected-correlation tail \(\le0.05\);
+- minimum density eigenvalue \(\ge-5\times10^{-3}\).
+
+Every comparison records the coarse/refined fingerprints, steps, tolerance,
+phase count, bond dimensions, three residuals, and pass/fail status. The cache
+uses atomic replacement so interrupted calculations can be resumed safely.
+
+## Production outcomes
+
+### \(N=3\) sector grid
+
+All six points pass the nested controller and physical gates:
+
+| sector | \(J/\Omega\) | final steps | bond | timestep \(r_j\) | tail |
+|---|---:|---:|---:|---:|---:|
+| even | 0.25 | 90 | 40 | 0.00844 | 0.02792 |
+| even | 0.50 | 90 | 43 | 0.02799 | 0.00562 |
+| even | 1.00 | 120 | 46 | 0.04890 | 0.01077 |
+| odd | 0.25, 0.50, 1.00 | 90 | 16 | 0.00151 | 0.03986 |
+
+The projected odd-sector Hamiltonian and coupling are exactly \(J\)
+independent; the three production spectra have relative maximum difference
+zero.
+
+### \(N=2\) exact-vs-Markov grid
+
+The calibration grid contains all nine combinations of
+\(\alpha=0.025,0.05,0.1\) and
+\(\omega_d/\Delta_g=0.75,1,1.25\). All nine exact points pass the production
+gates. The weak-coupling delay window grows as
+\(\max(4,\lceil0.3/\alpha\rceil)\) periods.
+
+The three reported errors are:
+
+\[
+D_\rho=\tfrac12\|\rho_{\rm IF}-\rho_{\rm ME}\|_1,
+\]
+
+\[
+\epsilon_C=\frac{\int d\tau\,|C_{\rm IF}-C_{\rm ME}|}
+{\int d\tau\,|C_{\rm IF}|},\qquad
+\epsilon_j=\frac{\int d\omega\,|\bar j_{\rm IF}-\bar j_{\rm ME}|}
+{\int d\omega\,|\bar j_{\rm IF}|}.
+\]
+
+Across the grid, \(D_\rho=0.9968\)–\(0.9997\),
+\(\epsilon_C=1.10\)–\(1.86\), and
+\(\epsilon_j=5.03\)–\(68.84\). These large values are a result, not a
+convergence failure: the uniform-TEMPO reference points themselves are
+converged.
+
+### \(N=3\) same-model exact-vs-Markov grid
+
+The six converged \(N=3\) sector points are also compared to
+Floquet-Markov/QRT without changing the Hamiltonian, drive, bath, sector, or
+frequency and delay grids. In the even sector, the heat-spectrum error is
+9.02–11.72 and the trace distance is 0.992–1.000. In the exactly
+\(J\)-independent odd sector, all three rows reproduce the same errors:
+\(D_\rho=0.4753\), \(\epsilon_C=0.5666\), and \(\epsilon_j=0.3920\).
+This closes the same-model comparison required by Tier 3 rather than using the
+\(N=2\) calibration as a proxy.
+
+### Model-definition variants
+
+At \(N=3,J/\Omega=0.5,\alpha=0.1\), the bounded variants
+\(S=M_z/3\), with and without \(+\alpha\omega_cS^2\), pass compression,
+timestep, phase, and physical gates (final bond dimension 45).
+
+The Kac variants \(S=M_z/\sqrt3\) pass the compression comparison:
+
+| variant | refined bond | compression \(r_j\) |
+|---|---:|---:|
+| Kac, no counterterm | 82 | 0.02373 |
+| Kac, counterterm | 81 | 0.00502 |
+
+Their next timestep and phase layers are intentionally not run by the local
+default because the larger coupling raises the process-tensor cost sharply.
+They are labeled `local_resource_ceiling`, not converged. `--full-kac`
+continues the same auditable ladder on a cluster.
+
+## Independent validation
+
+`scripts/run_fig3_validation.py` downloads the immutable author archive from
+Zenodo, verifies MD5 `0f3f9d9d8538aa96aee089973df7d9c2`, and independently
+recomputes all three transversal-drive curves in Fig. 3 (bottom) at
+\(\omega_d/\Omega=1,1.5,2\). All three points pass the same density, fixed-point,
+Hermiticity, trace, and correlation-tail gates. The normalized shape
+\(L^1\) discrepancies are 0.0562, 0.2736, and 0.3718 respectively; these are
+reported as quantitative structural reproduction, not bitwise identity.
+
+`scripts/run_uniform_validation.py` performs:
+
+- a single-spin UniformTEMPO smoke calculation that passes its declared
+ physical gates (bond 19, fixed-point residual \(1.40\times10^{-4}\));
+- a coarse reflection-odd UniformTEMPO–OQuPy comparison.
+
+The latter has heat \(L^1\) difference 0.517 and is retained as an independent
+implementation diagnostic, not as a convergence claim. It also verifies the
+projected odd-sector \(J\)-invariance exactly.
+
+## Benchmark and legacy backends
+
+`floquet_markov` / `floquet_markov_qr` implement a Born-Markov, fully secular
+periodic Lindblad benchmark with QRT correlations. They are never labeled
+non-Markovian.
+
+The in-repository finite-memory QUAPI code exposes the exponential
+\(O[(d^2)^{K+1}]\) wall and is used for regression tests. OQuPy 0.5.0 remains
+available as an independent PT-TEMPO validation backend. Neither supplies the
+production values in `results/paper`.
+
+## N=4 convergence-gated extension
+
+The generic reflection projector produces \(10\oplus6\) blocks for \(N=4\).
+At \(J/\Omega=0.25\), the odd-sector point passes nested compression,
+timestep, phase, and physical gates at 60 steps per period, tolerance
+\(3\times10^{-6}\), and 15 phases (bond 8, connected tail 0.0368). Its same-model
+Floquet-Markov/QRT heat-spectrum error is 3.405. The exact continuous spectrum
+has its three largest peaks at 0.4725, 0.9600, and 1.4400 \(\Omega\), whereas
+the selected drive frequency is 0.9256 \(\Omega\).
+
+The even-sector three-period endpoint missed only the connected-tail gate
+(0.0552 against 0.05). Without weakening the gate, the production point was
+rerun with six delay periods. It then passed every layer at bond 13 with tail
+0.0213; its same-model heat-spectrum error is 5.494.
diff --git a/tracks/mps/solutions/Ranger-123/docs/report-zh.md b/tracks/mps/solutions/Ranger-123/docs/report-zh.md
new file mode 100644
index 000000000..898fb2775
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/docs/report-zh.md
@@ -0,0 +1,295 @@
+# Issue #123:\(N=2,3\) 完整实施与数值结果
+
+## 1. 最终结论
+
+本项目已经把 Issue #123 的 \(N=2,3\) 部分做成可运行、可恢复、可审计的
+研究实现。生产计算使用公开的
+[UniformTEMPO.jl](https://github.com/uniformTEMPO/UniformTEMPO.jl),固定在
+revision `b76a018c32e5415989761d902b1b0e95f1a337da`;OQuPy 只作为独立粗粒度
+交叉检查。
+
+完成状态如下:
+
+1. \(N=2,3\) 的解析对称性、暗 sector、能隙和谱权重已由精确对角化与单元
+ 测试验证。
+2. \(N=3\) 的 reflection-even/odd 六个热谱点全部通过 compression、
+ timestep、15 相位以及 density-matrix 物理性门槛。
+3. \(N=2\) 的 \(3\times3\) exact-vs-Floquet-Markov 网格九个点全部收敛,
+ 同时给出稳态、两时间关联和热谱三种误差。
+4. bounded normalization 的有/无 counterterm 两个模型全部收敛。
+5. Kac normalization 的两个模型已通过压缩收敛,但完整 timestep/phase
+ 认证需要集群;结果明确标成 `local_resource_ceiling`。
+6. 论文 Fig. 3 底图的三个横向驱动频率全部由独立 UniformTEMPO 计算通过
+ 物理门槛,并与作者公开数据做了定量谱形和面积比较。
+7. \(N=4\) reflection-odd 点通过完整收敛阶梯,并完成同模型
+ Floquet-Markov/QRT 对照;heat error 为 3.405。
+8. \(N=4\) reflection-even 点在不放宽尾门槛的情况下将关联窗从三周期
+ 扩展到六周期并收敛;heat error 为 5.494。
+
+所以,对“需要提交集群吗”的答案是:
+
+- 核心 \(N=2,N=3\) 结论不需要,已经在本地完成;
+- 只有可选的 Kac 全收敛扩展需要集群;
+- \(N=4\) odd-sector 的有限尺寸试算已经完成;热力学连续谱和临界幂律
+ 不属于这次完成范围,也没有被暗示为已解决。
+
+## 2. 模型与数值方法
+
+系统 Hamiltonian 为
+
+\[
+H_0=-J\sum_{i=1}^{N-1}Z_iZ_{i+1}
+ +\frac{\Omega}{2}\sum_iX_i,
+\]
+
+驱动和共同浴通过
+
+\[
+S_N=\eta_N\sum_i Z_i
+\]
+
+耦合。基准采用 \(\Omega=1\)、零温 Ohmic bath
+
+\[
+J_B(\omega)=\alpha\omega e^{-\omega/\omega_c},\qquad \omega_c=2.5.
+\]
+
+生产 backend 构造 uniform influence tensor,并在扩展的
+system-Liouville × environment-memory 空间中求 Floquet fixed point。两时间
+关联通过在扩展态中插入左作用算符得到,不使用 reduced-state quantum
+regression theorem。
+
+周期平均关联拆成
+
+\[
+\bar C(\tau)=C_{\rm dec}(\tau)+C_{\rm coh}(\tau).
+\]
+
+\(C_{\rm dec}\) 数值 Fourier 积分得到连续热谱;\(\langle S(t)\rangle\) 的
+Fourier 系数单独转成解析 delta 权重,避免有限时间窗制造假展宽。
+
+### 收敛规则
+
+uniform 计算采用嵌套阶梯:
+
+\[
+M=60,90,120,\qquad
+\epsilon=3\times10^{-7},10^{-7},3\times10^{-8},\qquad
+N_\phi=3,15.
+\]
+
+每个 timestep 网格必须先通过 compression 收敛,之后才能参与 timestep
+比较;最后再做相位细化。门槛为
+
+\[
+r_\rho\le0.05,\qquad r_C\le0.08,\qquad r_j\le0.08.
+\]
+
+最终还要求 fixed-point residual \(\le10^{-3}\)、迹与厄米误差
+\(\le5\times10^{-3}\)、关联尾 \(\le0.05\)、最小 density eigenvalue
+\(\ge-5\times10^{-3}\)。
+
+## 3. \(N=2\):解析结构
+
+交换对称性将四维 Hilbert space 分成三维 triplet 与一维 singlet。
+
+\[
+S_2|s\rangle=0
+\]
+
+且 Hamiltonian 不泄漏 singlet,因此 singlet 是 collective drive 和 common
+bath 下的严格暗态。生产热谱直接投影到 triplet,避免完整空间中 steady
+state 非唯一。
+
+triplet 的两条 collective gaps 为
+
+\[
+\Delta_{\rm low/high}=\sqrt{J^2+\Omega^2}\mp J,
+\]
+
+权重为
+
+\[
+W_{\rm low/high}=2\eta_2^2
+\left(1\pm\frac{J}{\sqrt{J^2+\Omega^2}}\right).
+\]
+
+数值与解析式的最大偏差为 \(1.55\times10^{-15}\)。强铁磁区出现强的低频
+collective-cat transition 和逐渐变暗的高频支路。
+
+
+
+## 4. \(N=3\):最小 many-body onset
+
+open chain 的 edge reflection 给出
+
+\[
+\mathcal H=\mathcal H_{R=+}^{(6)}\oplus\mathcal H_{R=-}^{(2)}.
+\]
+
+odd sector 是 edge singlet 与中央自旋组成的嵌入单自旋模型,投影后的
+Hamiltonian 和耦合算符严格独立于 \(J\)。even sector 则等价于一个
+spin-1 edge 与中央 spin-\(\tfrac12\) 的六维模型。
+
+在强铁磁区,even sector 的主 gap 满足
+
+\[
+\Delta_{\rm cat}^{(3)}\simeq\frac{\Omega^3}{4J^2}.
+\]
+
+在 \(J=16\Omega\) 时,
+
+\[
+\frac{4J^2\Delta_g}{\Omega^3}=0.999023,
+\]
+
+bright weight 为 0.999267。
+
+
+
+### 六点热谱
+
+\(J/\Omega=0.25,0.5,1\) 的 even/odd 六点全部收敛:
+
+| sector | \(J/\Omega\) | 最终 \(M\) | bond | timestep \(r_j\) | 关联尾 |
+|---|---:|---:|---:|---:|---:|
+| even | 0.25 | 90 | 40 | 0.00844 | 0.02792 |
+| even | 0.50 | 90 | 43 | 0.02799 | 0.00562 |
+| even | 1.00 | 120 | 46 | 0.04890 | 0.01077 |
+| odd | 0.25, 0.50, 1.00 | 90 | 16 | 0.00151 | 0.03986 |
+
+even 主峰随 \(J\) 增大向低频移动并出现更多结构;odd 三条曲线完全重合,
+相对最大差为 0。这同时验证了 sector 推导和数值实现。
+
+
+
+## 5. Floquet-Markov 在哪里失败
+
+\(N=2\) interacting triplet 的校准网格为
+
+\[
+\alpha=0.025,0.05,0.1,\qquad
+\omega_d/\Delta_g=0.75,1,1.25.
+\]
+
+弱耦合时相关时间窗按
+
+\[
+N_{\rm delay}=\max(4,\lceil0.3/\alpha\rceil)
+\]
+
+增长;必要时 compression tolerance 深化到 \(10^{-8}\) 或
+\(3\times10^{-9}\)。九个 UniformTEMPO 点全部通过最终审计。
+
+三种误差范围为:
+
+\[
+D_\rho=0.9968\text{--}0.9997,
+\]
+
+\[
+\epsilon_C=1.10\text{--}1.86,
+\qquad
+\epsilon_j=5.03\text{--}68.84.
+\]
+
+这些值说明在所选参数层中 Floquet-Markov/QRT 与非马尔可夫参考严重不符。
+特别是热谱误差远大于 reduced-state 指标能够直观表达的差异,因此仅比较
+单时 observables 不能验证 calorimetry。
+
+
+
+为消除“Tier 2 是 \(N=3\),但误差图只在 \(N=2\)”的尺寸错位,现进一步
+对六个已经收敛的 \(N=3\) sector 点逐一运行完全相同模型和参数的
+Floquet-Markov/QRT。六点全部完成:even sector 的
+\(D_\rho=0.9921\text{--}0.9999\)、\(\epsilon_C=1.024\text{--}1.153\)、
+\(\epsilon_j=9.02\text{--}11.72\);odd sector 因投影模型严格
+\(J\)-不变,三点均给出 \(D_\rho=0.4753\)、\(\epsilon_C=0.5666\)、
+\(\epsilon_j=0.3920\)。这构成 Tier 3 所要求的 same-model 定量闭环。
+
+
+
+## 6. 暗通道与模型定义
+
+Floquet matrix elements 计算到 \(|m|\le40\),Parseval 残差保持在机器精度。
+结合 \(\bar j(\omega)\) 与 \(\overline{\mathrm{Var}(S)}\) 可以区分小矩阵元
+候选、collective fluctuation 与真正的 heat suppression;不能简单以“纠缠
+较强”等价于“暗”。
+
+
+
+对 \(N=3,J/\Omega=0.5,\alpha=0.1\),比较
+
+\[
+S=M_z/3,\qquad S=M_z/\sqrt3
+\]
+
+以及有/无
+
+\[
+H_{\rm ct}=+\alpha\omega_c S^2.
+\]
+
+bounded 两点完整收敛,最终 bond 均为 45。Kac 两点的压缩比较通过:
+
+- no counterterm:bond 63→82,热残差 0.02373;
+- counterterm:bond 63→81,热残差 0.00502。
+
+Kac 曲线仍以虚线显示,表示 timestep/phase 未完成,而不是表示压缩失败。
+这已经证明 normalization 和 counterterm 会改变数值难度与谱形,不能只在
+画图阶段重标度。
+
+
+
+## 7. 独立验证
+
+对于原论文 Fig. 3 底图,脚本先校验 Zenodo 归档 MD5,再在
+\(\omega_d/\Omega=1,1.5,2\) 上独立运行。三个点的归一化谱形 \(L^1\) 误差
+分别为 0.0562、0.2736、0.3718,积分强度比分别为 1.0268、1.1622、
+1.3119;全部通过 fixed-point、迹、厄米性、正定性和关联尾门槛。这是
+定量结构复现,而不是逐点完全相同的声明。
+
+
+
+单自旋 UniformTEMPO smoke test 的 bond 为 19,fixed-point residual 为
+\(1.40\times10^{-4}\),关联尾为 0.00555,全部通过物理门槛。
+
+粗粒度 UniformTEMPO–OQuPy 对照得到 phase-state Frobenius difference
+0.374、correlation \(L^1\) difference 0.282、heat \(L^1\) difference
+0.517。由于两边离散化和压缩设置都很粗,该结果只作为独立实现诊断,不作为
+两种 backend 已收敛一致的声明。投影后的 odd-sector \(J\) 不变性在该检查中
+仍精确成立。
+
+## 8. \(N=4\) 收敛门控结果
+
+通用 reflection projector 将 \(N=4\) 分成 even 10 维和 odd 6 维子空间。
+在 \(J/\Omega=0.25\) 上,odd sector 通过 compression、30→60 步时间网格、
+3→15 相位和全部物理门槛;最终 bond 为 8,关联尾为 0.0368。同模型
+Floquet-Markov/QRT 的 \(\epsilon_j=3.405\)。连续谱三个最强峰位于
+0.4725、0.9600、1.4400 \(\Omega\),相对于 0.9256 \(\Omega\) 驱动呈现
+多峰 collective structure。
+
+even sector 的三周期计算仅关联尾 0.0552 未过 0.05 门槛。保持原门槛并将
+关联窗扩展到六周期后,最终 bond 为 13、尾幅为 0.0213,全部自适应证据
+通过;同模型 \(\epsilon_j=5.494\)。
+
+
+
+
+
+## 9. 如何彻底续跑
+
+本地默认命令已经完成论文主网格。若有集群,只需继续 Kac 阶梯:
+
+```bash
+FULL_KAC=1 PYTHON_BIN=.venv/bin/python \
+ scripts/run_paper_extension.sh models
+```
+
+cache key 包含全部物理/数值参数与 solver revision,已有点会被安全复用。
+下一阶段若扩大研究范围,推荐顺序为:
+
+1. 完成 Kac 的 \(M=90,120\) 与 15 相位认证;
+2. 再考虑 \(N=4\) 的 matrix-free / Krylov 实现;
+3. 只有具备多个尺寸的 finite-size scaling 后,才讨论 continuum 或临界
+ power law。
diff --git a/tracks/mps/solutions/Ranger-123/docs/theory.md b/tracks/mps/solutions/Ranger-123/docs/theory.md
new file mode 100644
index 000000000..e63883886
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/docs/theory.md
@@ -0,0 +1,115 @@
+# Theory and conventions
+
+## Model
+
+All baselines use an open chain and \(\hbar=k_B=1\):
+
+\[
+H_0=-J\sum_{i=1}^{N-1}Z_iZ_{i+1}
+ +\frac{\Omega}{2}\sum_{i=1}^N X_i ,
+\qquad
+H(t)=H_0+\epsilon_d\cos(\omega_dt)S_N .
+\]
+
+The bath couples through
+
+\[
+S_N=\eta_N\sum_iZ_i.
+\]
+
+The default `bounded` normalization is \(\eta_N=1/N\). `kac` means
+\(\eta_N=1/\sqrt N\), and `collective` means \(\eta_N=1\).
+An optional counterterm is specified by its explicit coefficient
+`counterterm_strength`; setting it to \(\Lambda\) adds \(+\Lambda S_N^2\).
+
+The zero-temperature Ohmic convention is
+
+\[
+J_B(\omega)=\alpha\omega e^{-\omega/\omega_c},\qquad
+C_B(t)=\frac{\alpha\omega_c^2}{(1+i\omega_ct)^2}.
+\]
+
+OQuPy defines its power-law spectral density with a factor of two. The wrapper
+therefore passes `alpha/2`; this is tested and recorded in every PT-TEMPO result.
+
+## N=2
+
+Exchange symmetry decomposes the Hilbert space as
+
+\[
+\mathcal H=\mathcal H_{\rm triplet}\oplus\mathcal H_{\rm singlet}.
+\]
+
+The singlet is dark:
+
+\[
+S_2|s\rangle=0,\qquad H(t)|s\rangle=J|s\rangle.
+\]
+
+In the triplet, define \(E=\sqrt{J^2+\Omega^2}\). The three energies are
+\(-E,-J,+E\), so the two allowed gaps and weights are
+
+\[
+\Delta_{\rm low/high}=E\mp J,
+\]
+
+\[
+W_{\rm low/high}=2\eta_2^2(1\pm J/E).
+\]
+
+All four formulas are compared with numerical diagonalization for multiple
+values of \(J\) at machine precision.
+
+## N=3
+
+Reflection \(1\leftrightarrow3\) gives
+
+\[
+\mathcal H=\mathcal H_{R=+}\oplus\mathcal H_{R=-},\qquad 8=6+2.
+\]
+
+The odd sector is the edge singlet times the central spin. The Ising term
+vanishes in this sector, so its gap is exactly \(\Omega\) for every \(J\). The
+even sector contains the collective physics. At strong ferromagnetic coupling,
+the lowest bright transition obeys
+
+\[
+\Delta_{\rm cat}=\frac{\Omega^3}{4J^2}+O(J^{-4}),
+\]
+
+and its normalized bright weight tends to one.
+
+## Heat-current convention
+
+For the period-averaged collective correlation
+
+\[
+\bar C(\tau)=T^{-1}\int_0^Tdt\,
+\langle S(t+\tau)S(t)\rangle ,
+\]
+
+the continuous heat-current density is
+
+\[
+\bar j_{\rm con}(\omega)=2J_B(\omega)\omega
+\int_0^\infty d\tau\left[
+\cos(\omega\tau)\operatorname{Re}C_{\rm con}(\tau)
++(1+2n_B)\sin(\omega\tau)\operatorname{Im}C_{\rm con}(\tau)
+\right].
+\]
+
+The factorized asymptotic part is never windowed into fake finite-width peaks.
+If
+
+\[
+\langle S(t)\rangle=\sum_nm_ne^{-in\omega_dt},
+\]
+
+its positive-frequency coherent correlation weight is \(2|m_n|^2\), and the
+heat delta weight is
+
+\[
+\pi J_B(n\omega_d)n\omega_d\,2|m_n|^2.
+\]
+
+The JSON schema stores these peaks separately under `delta_peaks`.
diff --git a/tracks/mps/solutions/Ranger-123/figures/backend_comparison.pdf b/tracks/mps/solutions/Ranger-123/figures/backend_comparison.pdf
new file mode 100644
index 000000000..11d74060d
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/backend_comparison.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/backend_comparison.png b/tracks/mps/solutions/Ranger-123/figures/backend_comparison.png
new file mode 100644
index 000000000..e43e67158
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/backend_comparison.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/heat-valve/heat_valve_hero.pdf b/tracks/mps/solutions/Ranger-123/figures/heat-valve/heat_valve_hero.pdf
new file mode 100644
index 000000000..1d9c0dc10
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/heat-valve/heat_valve_hero.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/heat-valve/heat_valve_hero.png b/tracks/mps/solutions/Ranger-123/figures/heat-valve/heat_valve_hero.png
new file mode 100644
index 000000000..9eb9c166c
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/heat-valve/heat_valve_hero.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n2_exact.pdf b/tracks/mps/solutions/Ranger-123/figures/n2_exact.pdf
new file mode 100644
index 000000000..f13067195
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n2_exact.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n2_exact.png b/tracks/mps/solutions/Ranger-123/figures/n2_exact.png
new file mode 100644
index 000000000..e8b208a48
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n2_exact.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n2_markov_heat.pdf b/tracks/mps/solutions/Ranger-123/figures/n2_markov_heat.pdf
new file mode 100644
index 000000000..6a7525172
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n2_markov_heat.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n2_markov_heat.png b/tracks/mps/solutions/Ranger-123/figures/n2_markov_heat.png
new file mode 100644
index 000000000..2a68cda89
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n2_markov_heat.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n2_pt_tempo_heat.pdf b/tracks/mps/solutions/Ranger-123/figures/n2_pt_tempo_heat.pdf
new file mode 100644
index 000000000..c3b3fa058
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n2_pt_tempo_heat.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n2_pt_tempo_heat.png b/tracks/mps/solutions/Ranger-123/figures/n2_pt_tempo_heat.png
new file mode 100644
index 000000000..b940d3f52
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n2_pt_tempo_heat.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n3_exact.pdf b/tracks/mps/solutions/Ranger-123/figures/n3_exact.pdf
new file mode 100644
index 000000000..b34439ada
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n3_exact.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n3_exact.png b/tracks/mps/solutions/Ranger-123/figures/n3_exact.png
new file mode 100644
index 000000000..b34b479b3
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n3_exact.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n3_pt_tempo_dynamics.pdf b/tracks/mps/solutions/Ranger-123/figures/n3_pt_tempo_dynamics.pdf
new file mode 100644
index 000000000..76eea5e45
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n3_pt_tempo_dynamics.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/n3_pt_tempo_dynamics.png b/tracks/mps/solutions/Ranger-123/figures/n3_pt_tempo_dynamics.png
new file mode 100644
index 000000000..ac0989334
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/n3_pt_tempo_dynamics.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/dark_diagnostics.pdf b/tracks/mps/solutions/Ranger-123/figures/paper/dark_diagnostics.pdf
new file mode 100644
index 000000000..11ed00059
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/dark_diagnostics.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/dark_diagnostics.png b/tracks/mps/solutions/Ranger-123/figures/paper/dark_diagnostics.png
new file mode 100644
index 000000000..8b9997947
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/dark_diagnostics.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/error_maps.pdf b/tracks/mps/solutions/Ranger-123/figures/paper/error_maps.pdf
new file mode 100644
index 000000000..c4288bc9a
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/error_maps.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/error_maps.png b/tracks/mps/solutions/Ranger-123/figures/paper/error_maps.png
new file mode 100644
index 000000000..87b75bf6e
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/error_maps.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/model_variants.pdf b/tracks/mps/solutions/Ranger-123/figures/paper/model_variants.pdf
new file mode 100644
index 000000000..25c9c7a6a
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/model_variants.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/model_variants.png b/tracks/mps/solutions/Ranger-123/figures/paper/model_variants.png
new file mode 100644
index 000000000..91425722b
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/model_variants.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n3_error_maps.pdf b/tracks/mps/solutions/Ranger-123/figures/paper/n3_error_maps.pdf
new file mode 100644
index 000000000..f4e7acb65
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n3_error_maps.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n3_error_maps.png b/tracks/mps/solutions/Ranger-123/figures/paper/n3_error_maps.png
new file mode 100644
index 000000000..1484af2d4
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n3_error_maps.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n3_odd_difference.pdf b/tracks/mps/solutions/Ranger-123/figures/paper/n3_odd_difference.pdf
new file mode 100644
index 000000000..484712bc2
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n3_odd_difference.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n3_odd_difference.png b/tracks/mps/solutions/Ranger-123/figures/paper/n3_odd_difference.png
new file mode 100644
index 000000000..c78891d5f
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n3_odd_difference.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n3_sector_heat.pdf b/tracks/mps/solutions/Ranger-123/figures/paper/n3_sector_heat.pdf
new file mode 100644
index 000000000..bedb5708b
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n3_sector_heat.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n3_sector_heat.png b/tracks/mps/solutions/Ranger-123/figures/paper/n3_sector_heat.png
new file mode 100644
index 000000000..0d31de66a
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n3_sector_heat.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n4_even_j0p25_comparison.pdf b/tracks/mps/solutions/Ranger-123/figures/paper/n4_even_j0p25_comparison.pdf
new file mode 100644
index 000000000..30443f6df
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n4_even_j0p25_comparison.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n4_even_j0p25_comparison.png b/tracks/mps/solutions/Ranger-123/figures/paper/n4_even_j0p25_comparison.png
new file mode 100644
index 000000000..1c6764ab3
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n4_even_j0p25_comparison.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n4_odd_j0p25_comparison.pdf b/tracks/mps/solutions/Ranger-123/figures/paper/n4_odd_j0p25_comparison.pdf
new file mode 100644
index 000000000..c9cfc242a
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n4_odd_j0p25_comparison.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/paper/n4_odd_j0p25_comparison.png b/tracks/mps/solutions/Ranger-123/figures/paper/n4_odd_j0p25_comparison.png
new file mode 100644
index 000000000..4a8908cda
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/paper/n4_odd_j0p25_comparison.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_summary.pdf b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_summary.pdf
new file mode 100644
index 000000000..be3b857f7
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_summary.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_summary.png b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_summary.png
new file mode 100644
index 000000000..bd13c1236
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_summary.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1.pdf b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1.pdf
new file mode 100644
index 000000000..50188e07d
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1.png b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1.png
new file mode 100644
index 000000000..44247f7d6
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1p5.pdf b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1p5.pdf
new file mode 100644
index 000000000..93a6d8645
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1p5.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1p5.png b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1p5.png
new file mode 100644
index 000000000..5f9e67487
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd1p5.png differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd2.pdf b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd2.pdf
new file mode 100644
index 000000000..d30928045
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd2.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd2.png b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd2.png
new file mode 100644
index 000000000..52ac2f4b4
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/figures/validation/fig3_transversal_wd2.png differ
diff --git a/tracks/mps/solutions/Ranger-123/julia/Project.toml b/tracks/mps/solutions/Ranger-123/julia/Project.toml
new file mode 100644
index 000000000..41450d12f
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/julia/Project.toml
@@ -0,0 +1,14 @@
+[deps]
+JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
+KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77"
+OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
+UniformTEMPO = "df6cb18e-c722-4276-9e4b-1aef7d428362"
+
+[sources]
+UniformTEMPO = {url = "https://github.com/uniformTEMPO/UniformTEMPO.jl.git", rev = "b76a018c32e5415989761d902b1b0e95f1a337da"}
+
+[compat]
+JSON3 = "1"
+KrylovKit = "0.10"
+OrdinaryDiffEq = "6"
+julia = "1.12"
diff --git a/tracks/mps/solutions/Ranger-123/julia/run_uniform_tempo.jl b/tracks/mps/solutions/Ranger-123/julia/run_uniform_tempo.jl
new file mode 100644
index 000000000..d8f1163b3
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/julia/run_uniform_tempo.jl
@@ -0,0 +1,359 @@
+#!/usr/bin/env julia
+
+if length(ARGS) != 2
+ println(stderr, "UniformTEMPO input error: expected input JSON path and output JSON path")
+ exit(2)
+end
+if !isfile(ARGS[1])
+ println(stderr, "UniformTEMPO input error: input JSON does not exist: $(ARGS[1])")
+ exit(2)
+end
+
+using JSON3
+using KrylovKit
+using LinearAlgebra
+using OrdinaryDiffEq
+using SHA
+using Serialization
+using UniformTEMPO
+
+const METHOD = "uniform_tempo_floquet_multitime"
+const UNIFORM_TEMPO_REVISION = "b76a018c32e5415989761d902b1b0e95f1a337da"
+
+function fail(message::AbstractString)
+ println(stderr, "UniformTEMPO input error: " * message)
+ exit(2)
+end
+
+function required(object, key::Symbol)
+ haskey(object, key) || fail("missing input field: $(key)")
+ return object[key]
+end
+
+function decode_real_matrix(raw, label::AbstractString)
+ rows = [Float64.(collect(row)) for row in raw]
+ isempty(rows) && fail("$(label) must not be empty")
+ width = length(first(rows))
+ width > 0 || fail("$(label) must not have empty rows")
+ all(length(row) == width for row in rows) ||
+ fail("$(label) rows have inconsistent lengths")
+ return reduce(vcat, permutedims.(rows))
+end
+
+function decode_complex_matrix(raw, label::AbstractString)
+ real_part = decode_real_matrix(required(raw, :real), "$(label).real")
+ imag_part = decode_real_matrix(required(raw, :imag), "$(label).imag")
+ size(real_part) == size(imag_part) ||
+ fail("$(label) real and imaginary shapes differ")
+ return ComplexF64.(real_part, imag_part)
+end
+
+encode_complex(values) = Dict(
+ "real" => real.(values),
+ "imag" => imag.(values),
+ "shape" => collect(size(values)),
+)
+
+function finite_complex(values)
+ return all(isfinite, real.(values)) && all(isfinite, imag.(values))
+end
+
+function validate_hermitian(matrix, label::AbstractString)
+ size(matrix, 1) == size(matrix, 2) || fail("$(label) must be square")
+ norm(matrix - matrix') <= 1e-10 || fail("$(label) must be Hermitian")
+end
+
+function atomic_json_write(path::AbstractString, payload)
+ directory = dirname(path)
+ mkpath(directory)
+ temporary = path * ".tmp-" * string(getpid())
+ open(temporary, "w") do io
+ JSON3.pretty(io, payload)
+ write(io, '\n')
+ end
+ mv(temporary, path; force=true)
+end
+
+function load_or_build_process_tensor(
+ coupling,
+ dt,
+ bcf,
+ tolerance;
+ auto_nc,
+ memory_cutoff,
+ truncation,
+ cap_rank,
+ low_rank_svd,
+ max_rank,
+ cache_path,
+ cache_key,
+)
+ if cache_path !== nothing && isfile(cache_path)
+ record = deserialize(cache_path)
+ record isa AbstractDict ||
+ fail("process tensor cache record is invalid")
+ get(record, :key, nothing) == cache_key ||
+ fail("process tensor cache key does not match")
+ get(record, :uniform_tempo_revision, nothing) == UNIFORM_TEMPO_REVISION ||
+ fail("process tensor cache revision does not match")
+ get(record, :system_dimension, nothing) == size(coupling, 1) ||
+ fail("process tensor cache dimension does not match")
+ cached_dt = get(record, :dt, nothing)
+ cached_dt isa Real && isapprox(cached_dt, dt; rtol=1e-13, atol=1e-15) ||
+ fail("process tensor cache timestep does not match")
+ haskey(record, :process_tensor) ||
+ fail("process tensor cache has no tensor")
+ return record[:process_tensor], true
+ end
+
+ pt = uniTEMPO(
+ coupling,
+ dt,
+ bcf,
+ tolerance;
+ auto_nc=auto_nc,
+ n_c=memory_cutoff,
+ truncation=truncation,
+ cap_rank=cap_rank,
+ low_rank_svd=low_rank_svd,
+ max_rank=max_rank,
+ )
+ if cache_path !== nothing
+ mkpath(dirname(cache_path))
+ temporary = cache_path * ".tmp-" * string(getpid())
+ record = Dict(
+ :key => cache_key,
+ :uniform_tempo_revision => UNIFORM_TEMPO_REVISION,
+ :system_dimension => size(coupling, 1),
+ :dt => dt,
+ :process_tensor => pt,
+ )
+ open(temporary, "w") do io
+ serialize(io, record)
+ end
+ mv(temporary, cache_path; force=true)
+ end
+ return pt, false
+end
+
+function main()
+ input_path, output_path = ARGS
+
+ input = JSON3.read(read(input_path, String))
+ h0 = decode_complex_matrix(required(input, :h0), "h0")
+ coupling = decode_complex_matrix(required(input, :coupling), "coupling")
+ drive = decode_complex_matrix(required(input, :drive), "drive")
+ validate_hermitian(h0, "h0")
+ validate_hermitian(coupling, "coupling")
+ validate_hermitian(drive, "drive")
+ size(h0) == size(coupling) ||
+ fail("h0 and coupling dimensions differ")
+ size(h0) == size(drive) ||
+ fail("h0 and drive dimensions differ")
+
+ model = required(input, :model)
+ drive_amplitude = Float64(required(model, :drive_amplitude))
+ drive_frequency = Float64(required(model, :drive_frequency))
+ drive_frequency > 0 || fail("drive_frequency must be positive")
+
+ bath = required(input, :bath)
+ alpha = Float64(required(bath, :alpha))
+ cutoff = Float64(required(bath, :cutoff))
+ temperature = Float64(required(bath, :temperature))
+ alpha >= 0 || fail("alpha must be nonnegative")
+ cutoff > 0 || fail("cutoff must be positive")
+ temperature == 0 ||
+ fail("the current analytic bath correlation supports temperature=0 only")
+
+ controls = required(input, :controls)
+ period_steps = Int(required(controls, :steps_per_period))
+ tolerance = Float64(required(controls, :tolerance))
+ phase_offsets = Int.(collect(required(controls, :phase_offsets)))
+ delay_steps = Int(required(controls, :delay_steps))
+ auto_nc = Bool(required(controls, :auto_nc))
+ memory_cutoff = Int(required(controls, :memory_cutoff))
+ low_rank_svd = Bool(required(controls, :low_rank_svd))
+ truncation = Symbol(String(required(controls, :truncation)))
+ cap_rank = Int(required(controls, :cap_rank))
+ max_rank = Int(required(controls, :max_rank))
+ pole_count = Int(required(controls, :pole_count))
+ pole_tolerance = Float64(required(controls, :pole_tolerance))
+ pole_maxiter = Int(required(controls, :pole_maxiter))
+ process_tensor_cache_path = if haskey(controls, :process_tensor_cache_path)
+ String(controls[:process_tensor_cache_path])
+ else
+ nothing
+ end
+ process_tensor_cache_key = if haskey(controls, :process_tensor_cache_key)
+ String(controls[:process_tensor_cache_key])
+ else
+ nothing
+ end
+
+ period_steps >= 2 || fail("steps_per_period must be at least two")
+ 0 < tolerance < 1 || fail("tolerance must lie between zero and one")
+ delay_steps >= 1 || fail("delay_steps must be positive")
+ memory_cutoff >= 1 || fail("memory_cutoff must be positive")
+ cap_rank >= 1 || fail("cap_rank must be positive")
+ max_rank >= cap_rank || fail("max_rank must be at least cap_rank")
+ pole_count >= 0 || fail("pole_count must be nonnegative")
+ pole_tolerance > 0 || fail("pole_tolerance must be positive")
+ pole_maxiter >= 1 || fail("pole_maxiter must be positive")
+ truncation in (:rel, :abs) || fail("truncation must be rel or abs")
+ length(phase_offsets) >= 2 ||
+ fail("at least two phase offsets are required")
+ length(unique(phase_offsets)) == length(phase_offsets) ||
+ fail("phase offsets must be unique")
+ all(0 .<= phase_offsets .< period_steps) ||
+ fail("phase offsets must lie within one period")
+ (process_tensor_cache_path === nothing) ==
+ (process_tensor_cache_key === nothing) ||
+ fail("process tensor cache path and key must be supplied together")
+ process_tensor_cache_key === nothing ||
+ occursin(r"^[0-9a-f]{64}$", process_tensor_cache_key) ||
+ fail("process tensor cache key must be a SHA-256 digest")
+
+ period = 2π / drive_frequency
+ dt = period / period_steps
+ h_s(time) = h0 + drive_amplitude * cos(drive_frequency * time) * drive
+ bcf(time) = alpha * (cutoff / (1 + im * cutoff * time))^2
+
+ pt, process_tensor_cache_hit = load_or_build_process_tensor(
+ coupling,
+ dt,
+ bcf,
+ tolerance;
+ auto_nc=auto_nc,
+ memory_cutoff=memory_cutoff,
+ truncation=truncation,
+ cap_rank=cap_rank,
+ low_rank_svd=low_rank_svd,
+ max_rank=max_rank,
+ cache_path=process_tensor_cache_path,
+ cache_key=process_tensor_cache_key,
+ )
+ ptf = floquet_process_tensor(pt, h_s, period)
+ extended_floquet_state = steadystate(ptf; return_full=true)
+ floquet_state = reshape(
+ ptf.v_l * extended_floquet_state,
+ size(h0),
+ )
+ floquet_state ./= tr(floquet_state)
+ floquet_transfer = reshape(
+ ptf.q,
+ size(ptf.q, 1) * size(ptf.q, 2),
+ size(ptf.q, 1) * size(ptf.q, 2),
+ )
+ floquet_transfer_residual = norm(
+ floquet_transfer * extended_floquet_state[:] -
+ extended_floquet_state[:]
+ ) / max(norm(extended_floquet_state), eps())
+ transfer_eigenvalues = ComplexF64[]
+ transfer_eigenpair_residuals = Float64[]
+ if pole_count > 0
+ requested = min(pole_count, size(floquet_transfer, 1) - 1)
+ values_raw, vectors, _ = eigsolve(
+ floquet_transfer,
+ requested,
+ :LM;
+ tol=pole_tolerance,
+ maxiter=pole_maxiter,
+ )
+ order = sortperm(abs.(values_raw); rev=true)
+ length(order) >= requested ||
+ error("KrylovKit returned fewer transfer poles than requested")
+ selected = order[1:requested]
+ transfer_eigenvalues = ComplexF64.(values_raw[selected])
+ transfer_eigenpair_residuals = [
+ norm(
+ floquet_transfer * vectors[index] -
+ values_raw[index] * vectors[index]
+ ) / max(norm(vectors[index]), eps())
+ for index in selected
+ ]
+ end
+
+ micromotion = evolve(pt, extended_floquet_state, period_steps; h_s=h_s)
+ extended_after_period = evolve(
+ pt,
+ extended_floquet_state,
+ period_steps;
+ h_s=h_s,
+ return_full=true,
+ )
+ fixed_point_residual = norm(
+ extended_after_period - extended_floquet_state
+ ) / max(norm(extended_floquet_state), eps())
+
+ selected_states = [micromotion[offset + 1] for offset in phase_offsets]
+ one_point = [real(tr(coupling * state)) for state in selected_states]
+ correlation_records = Vector{Vector{ComplexF64}}()
+ for offset in phase_offsets
+ extended_phase_state = if offset == 0
+ extended_floquet_state
+ else
+ evolve(
+ pt,
+ extended_floquet_state,
+ offset;
+ h_s=h_s,
+ return_full=true,
+ )
+ end
+ h_shifted(time) = h_s(time + offset * dt)
+ record = two_point_correlations(
+ pt,
+ extended_phase_state,
+ 0,
+ delay_steps,
+ coupling,
+ coupling;
+ h_s=h_shifted,
+ )
+ push!(correlation_records, ComplexF64.(record))
+ end
+ total_correlation = reduce(+, correlation_records) / length(correlation_records)
+
+ trace_error = maximum(abs(tr(state) - 1) for state in selected_states)
+ hermiticity_error = maximum(norm(state - state') for state in selected_states)
+ minimum_density_eigenvalue = minimum(
+ minimum(eigvals(Hermitian((state + state') / 2)))
+ for state in selected_states
+ )
+ finite_complex(floquet_state) || error("non-finite Floquet state")
+ finite_complex(total_correlation) || error("non-finite correlation")
+ finite_complex(transfer_eigenvalues) || error("non-finite transfer eigenvalue")
+ all(isfinite, transfer_eigenpair_residuals) ||
+ error("non-finite transfer eigenpair residual")
+
+ manifest_path = joinpath(dirname(Base.active_project()), "Manifest.toml")
+ payload = Dict(
+ "method" => METHOD,
+ "dt" => dt,
+ "period_steps" => period_steps,
+ "bond_dimension" => bond_dim(pt),
+ "floquet_state" => encode_complex(floquet_state),
+ "phase_states" => encode_complex(cat(selected_states...; dims=3)),
+ "one_point" => one_point,
+ "phase_offsets" => phase_offsets,
+ "delay" => collect(0:delay_steps) .* dt,
+ "correlation" => encode_complex(total_correlation),
+ "diagnostics" => Dict(
+ "trace_error" => trace_error,
+ "hermiticity_error" => hermiticity_error,
+ "minimum_density_eigenvalue" => minimum_density_eigenvalue,
+ "fixed_point_residual" => fixed_point_residual,
+ "floquet_transfer_residual" => floquet_transfer_residual,
+ ),
+ "julia_version" => string(VERSION),
+ "uniform_tempo_revision" => UNIFORM_TEMPO_REVISION,
+ "manifest_sha256" => bytes2hex(sha256(read(manifest_path))),
+ "process_tensor_cache_hit" => process_tensor_cache_hit,
+ "transfer_eigenvalues" => encode_complex(transfer_eigenvalues),
+ "transfer_eigenpair_residuals" => transfer_eigenpair_residuals,
+ "transfer_dimension" => size(floquet_transfer, 1),
+ )
+ atomic_json_write(output_path, payload)
+end
+
+main()
diff --git a/tracks/mps/solutions/Ranger-123/julia/smoke_input.json b/tracks/mps/solutions/Ranger-123/julia/smoke_input.json
new file mode 100644
index 000000000..e6984ab15
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/julia/smoke_input.json
@@ -0,0 +1,31 @@
+{
+ "h0": {
+ "real": [[0.0, 0.5], [0.5, 0.0]],
+ "imag": [[0.0, 0.0], [0.0, 0.0]]
+ },
+ "coupling": {
+ "real": [[1.0, 0.0], [0.0, -1.0]],
+ "imag": [[0.0, 0.0], [0.0, 0.0]]
+ },
+ "model": {
+ "drive_amplitude": 0.2,
+ "drive_frequency": 1.0
+ },
+ "bath": {
+ "alpha": 0.01,
+ "cutoff": 2.5,
+ "temperature": 0.0
+ },
+ "controls": {
+ "steps_per_period": 8,
+ "tolerance": 0.001,
+ "phase_offsets": [0, 4],
+ "delay_steps": 4,
+ "auto_nc": false,
+ "memory_cutoff": 6,
+ "low_rank_svd": false,
+ "truncation": "rel",
+ "cap_rank": 100,
+ "max_rank": 1000
+ }
+}
diff --git a/tracks/mps/solutions/Ranger-123/output/pdf/Ranger-123-technical-report.pdf b/tracks/mps/solutions/Ranger-123/output/pdf/Ranger-123-technical-report.pdf
new file mode 100644
index 000000000..4941a2c86
Binary files /dev/null and b/tracks/mps/solutions/Ranger-123/output/pdf/Ranger-123-technical-report.pdf differ
diff --git a/tracks/mps/solutions/Ranger-123/pyproject.toml b/tracks/mps/solutions/Ranger-123/pyproject.toml
new file mode 100644
index 000000000..b2658d6b5
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/pyproject.toml
@@ -0,0 +1,51 @@
+[build-system]
+requires = ["hatchling>=1.27"]
+build-backend = "hatchling.build"
+
+[project]
+name = "floquet-if-manybody"
+version = "0.1.0"
+description = "Reproducible N=2,3 study for quantum.harness issue 123"
+readme = "README.md"
+requires-python = ">=3.11"
+license = {text = "AGPL-3.0-or-later"}
+dependencies = [
+ "numpy>=1.26,<2.0",
+ "scipy>=1.14",
+ "matplotlib>=3.9",
+ "PyYAML>=6.0",
+]
+
+[project.optional-dependencies]
+dev = [
+ "pytest>=8.3",
+ "ruff>=0.9",
+ "mypy>=1.14",
+]
+nonmarkov = [
+ "oqupy==0.5.0",
+]
+
+[project.scripts]
+floquet-if = "floquet_if_manybody.cli:main"
+
+[tool.hatch.build.targets.wheel]
+packages = ["src/floquet_if_manybody"]
+
+[tool.pytest.ini_options]
+testpaths = ["tests"]
+addopts = "-ra"
+
+[tool.ruff]
+line-length = 100
+target-version = "py311"
+
+[tool.ruff.lint]
+select = ["E", "F", "I", "UP", "B"]
+
+[tool.mypy]
+python_version = "3.12"
+strict = true
+ignore_missing_imports = true
+disallow_any_generics = false
+packages = ["floquet_if_manybody"]
diff --git a/tracks/mps/solutions/Ranger-123/report/data-summary.txt b/tracks/mps/solutions/Ranger-123/report/data-summary.txt
new file mode 100644
index 000000000..bc3258ea0
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/report/data-summary.txt
@@ -0,0 +1,47 @@
+Quantum Harness Issue #123 - Ranger machine-readable summary companion
+Generated: 2026-07-30 Asia/Shanghai
+UniformTEMPO revision: b76a018c32e5415989761d902b1b0e95f1a337da
+
+TIER 1 - PUBLISHED FIG. 3 BOTTOM REPRODUCTION
+Reference: https://zenodo.org/records/19593671
+Archive MD5: 0f3f9d9d8538aa96aee089973df7d9c2
+All points use dt = pi/60 and delay_periods = 12.
+
+wd/Omega converged bond tolerance phases tail_amplitude fixed_point_residual hermiticity_error shape_L1 area_ratio
+1.0 true 26 1e-7 15 0.0016272564 0.0000808715 0.0036099263 0.0562435 1.0267712
+1.5 true 14 1e-6 4 0.0023604904 0.0005313577 0.0042726147 0.2735650 1.1622298
+2.0 true 14 1e-6 4 0.0156057456 0.0003084472 0.0032007799 0.3718315 1.3118951
+
+TIER 2 - N=3 COLLECTIVE HEAT GRID
+Six of six reflection-sector points converged for J/Omega = 0.25, 0.5, 1.0.
+The reflection-odd projected model and heat curve are exactly J-independent.
+
+TIER 3 - N=3 SAME-MODEL UNIFORMTEMPO VS FLOQUET-MARKOV/QRT
+sector J/Omega trace_distance correlation_error heat_error
+even 0.25 0.9996997 1.1529658 9.0167068
+even 0.50 0.9999011 1.0341251 11.7157802
+even 1.00 0.9920892 1.0243259 9.0772348
+odd 0.25 0.4752510 0.5666192 0.3920114
+odd 0.50 0.4752510 0.5666192 0.3920114
+odd 1.00 0.4752510 0.5666192 0.3920114
+
+N=4 CONVERGENCE-GATED EXTENSION AT J/OMEGA=0.25
+sector dimension status bond tail_amplitude markov_heat_error
+odd 6 converged 8 0.0367791 3.4047954
+even 10 converged 13 0.0213318 5.4937769
+
+N=4 odd largest continuous-spectrum peaks (omega/Omega, jbar):
+(0.4725, 0.00176277), (0.9600, 0.01938817), (1.4400, 0.00510966)
+Selected drive frequency: 0.9256058858 Omega
+
+Verification at this snapshot:
+pytest: 110 passed
+ruff: passed
+mypy: passed
+root result audit: passed (6 files)
+paper audit: passed
+
+Compact JSON evidence:
+validation/fig3_transversal_summary.json
+validation/n3_same_model_error_map.json
+validation/ARTIFACT_PROVENANCE.json
diff --git a/tracks/mps/solutions/Ranger-123/report/generated-results.tex b/tracks/mps/solutions/Ranger-123/report/generated-results.tex
new file mode 100644
index 000000000..e7d40f4ce
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/report/generated-results.tex
@@ -0,0 +1,12 @@
+\newcommand{\TierOneStatus}{3/3 通过物理门槛}
+\newcommand{\TierTwoStatus}{$N=3$ 六点、$N=4$ 两 sector 均收敛}
+\newcommand{\FigThreeRows}{%
+1.0 & 26 & $1.63\times10^{-3}$ & 0.056 & 1.027 \\
+1.5 & 14 & $2.36\times10^{-3}$ & 0.274 & 1.162 \\
+2.0 & 14 & $1.56\times10^{-2}$ & 0.372 & 1.312 \\
+}
+\newcommand{\NFourRows}{%
+even & 10 & 收敛 & 13 & 0.0213 & 5.494 \\
+odd & 6 & 收敛 & 8 & 0.0368 & 3.405 \\
+}
+\newcommand{\NFourConclusion}{两个 sector 的 compression、时间步、相位和物理性门槛全部通过。odd sector 使用三周期关联窗;even sector 的三周期尾幅为 0.0552,因此按门槛扩展到六周期并降至 0.0213。两点均完成同模型 Markov 对照。}
diff --git a/tracks/mps/solutions/Ranger-123/report/technical-report.tex b/tracks/mps/solutions/Ranger-123/report/technical-report.tex
new file mode 100644
index 000000000..b0c1eaace
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/report/technical-report.tex
@@ -0,0 +1,184 @@
+\documentclass[11pt,a4paper]{ctexart}
+\usepackage[margin=2.15cm]{geometry}
+\usepackage{amsmath,amssymb,booktabs,graphicx,hyperref,longtable,microtype,xcolor}
+\usepackage{fancyhdr}
+\hypersetup{colorlinks=true,linkcolor=blue!45!black,urlcolor=blue!55!black,citecolor=blue!45!black}
+\graphicspath{{../figures/paper/}{../figures/validation/}{../figures/heat-valve/}}
+\setlength{\parindent}{2em}
+\setlength{\parskip}{0.25em}
+\setlength{\headheight}{14pt}
+\pagestyle{fancy}
+\fancyhf{}
+\lhead{Quantum Harness Issue \#123}
+\rhead{Team Ranger}
+\cfoot{\thepage}
+\newcommand{\code}[1]{\texttt{#1}}
+\InputIfFileExists{generated-results.tex}{}{\errmessage{generated-results.tex is required}}
+
+\title{\textbf{共同非马尔可夫浴中的多体 Floquet 热输运}\\
+\large Quantum Harness Issue \#123 技术报告}
+\author{Team Ranger\\Chenxi Wan \quad Yedi Shen \quad Junkai Wang}
+\date{2026 年 7 月 30 日}
+
+\begin{document}
+\maketitle
+
+\begin{abstract}
+本项目将单自旋 Floquet influence functional 方法扩展到共同浴耦合的相互作用自旋链,给出可恢复、可审计的 uniform TEMPO 数值流程。我们完成原题 Tier 1 的三频率单自旋 Fig.~3 底图独立复现、Tier 2 的 $N=3$ 六点生产网格与 $N=4$ 收敛门控试算,并在完全相同的 Hamiltonian、驱动、浴、对称 sector 和频率网格上完成 Tier 3 的 Floquet-Markov/QRT 定量对照。核心结果是:$N=3$ even sector 的热谱相对误差达到 $9.02$--$11.72$,而 odd sector 为 $0.3920$;这表明弱耦合、无记忆近似的失效具有显著 sector 依赖性。项目同时记录一个预注册的暗通道负结果,避免把能隙塌缩误判为热抑制。所有声明均绑定到机器可读 JSON、图件哈希和自动化门槛。
+\end{abstract}
+
+\section{赛题要求与完成边界}
+Issue \#123 的三级路线分别要求:(i) 复现 Mickiewicz 等人单自旋横向驱动 Fig.~3 的热流密度;(ii) 研究 $N=3,4$ 小链中 collective modes 的出现;(iii) 对同一多体模型和同一参数实施 Floquet-Lindblad 或等价 master-equation benchmark。表~\ref{tab:tier} 按原题而非提交者自定义口径列出证据。
+
+\begin{table}[htbp]
+\centering
+\caption{原题三级路线与本项目证据。}
+\label{tab:tier}
+\begin{tabular}{p{0.10\linewidth}p{0.54\linewidth}p{0.25\linewidth}}
+\toprule
+级别 & 交付证据 & 状态 \\
+\midrule
+Tier 1 & 公开 Zenodo 曲线的校验下载;$\omega_d/\Omega=1,1.5,2$ 三个独立 UniformTEMPO 点;连续谱和解析 $\delta$ 峰分离 & \TierOneStatus \\
+Tier 2 & $N=3$ even/odd 六点收敛热谱;$N=4$ reflection 分块、回归测试及收敛门控点 & \TierTwoStatus \\
+Tier 3 & $N=3$ 六点在同模型、同参数下与 Floquet-Markov/QRT 比较 $D_\rho,\epsilon_C,\epsilon_j$ & 6/6 收敛 \\
+\bottomrule
+\end{tabular}
+\end{table}
+
+本报告不声称热力学极限、连续相变或临界指数。可选 Kac normalization 的完整时间步和相位细化也不被重新标记为已收敛。
+
+\section{模型与算法}
+系统 Hamiltonian 为
+\begin{equation}
+H_0=-J\sum_{i=1}^{N-1}Z_iZ_{i+1}+\frac{\Omega}{2}\sum_{i=1}^{N}X_i,
+\qquad
+H_{\mathrm d}(t)=\epsilon_{\mathrm d}\cos(\omega_{\mathrm d}t)S_N,
+\end{equation}
+共同零温 Ohmic 浴经 $S_N=\eta_N\sum_i Z_i$ 耦合,谱密度为
+\begin{equation}
+J_B(\omega)=\alpha\omega\exp(-\omega/\omega_c),\qquad \omega_c=2.5\Omega.
+\end{equation}
+生产后端固定到 UniformTEMPO.jl revision \code{b76a018c32e5}(完整哈希见机器数据)。Python 层完成对称投影、内容寻址缓存、自适应收敛阶梯、扩展 process-tensor state 中的多时间算符插入,以及连续谱与相干 $\delta$ 峰的分离。
+
+本实现包含三项面向本题的算法性改进:
+\begin{enumerate}
+\item 在 system-Liouville 与环境记忆的扩展态中直接插入算符,避免用 reduced-state QRT 冒充非马尔可夫两时间关联;
+\item 对 reflection symmetry 做精确分块,$N=3$ 化为 $6\oplus2$,$N=4$ 化为 $10\oplus6$,并把投影算符哈希写入缓存键;
+\item 用 compression、时间步、相位和物理性四层门槛控制计算,只有全部通过的点才进入定量图和误差图。
+\end{enumerate}
+
+\section{Tier 1:单自旋 Fig.~3 独立复现}
+公开作者数据来自 Zenodo record \href{https://zenodo.org/records/19593671}{19593671},下载归档 MD5 为 {\scriptsize\texttt{0f3f9d9d8538aa96aee089973df7d9c2}}。独立计算采用论文参数 $\Omega=\epsilon_d=1$、$\alpha=0.05$、$\omega_c=2.5$、$\Delta t=\pi/60$,并将 connected correlation 的 Fourier 连续部分与驱动谐波的解析 $\delta$ 权重分别处理。
+
+\begin{table}[htbp]
+\centering
+\caption{Fig.~3 底图三频率独立计算。$L^1_{\rm shape}$ 比较归一化谱形,$R_{\rm area}$ 为积分强度比。}
+\label{tab:fig3}
+\begin{tabular}{ccccc}
+\toprule
+$\omega_d/\Omega$ & bond & 尾幅 & $L^1_{\rm shape}$ & $R_{\rm area}$ \\
+\midrule
+\FigThreeRows
+\bottomrule
+\end{tabular}
+\end{table}
+
+\begin{figure}[htbp]
+\centering
+\includegraphics[width=\linewidth]{fig3_transversal_summary.png}
+\caption{论文 Fig.~3 底图公开数据与独立 UniformTEMPO 连续谱。竖线标出独立计算得到的相干峰位置;比较不把 $\delta$ 峰伪装成有限宽峰。}
+\label{fig:fig3}
+\end{figure}
+
+这些曲线是定量的结构复现而非逐点相同。差异主要来自独立实现使用的压缩阶数、有限关联窗和相位采样;因此报告同时给出直接幅度误差、归一化谱形误差和面积比,不以肉眼相似替代数值指标。
+
+\section{Tier 2:\texorpdfstring{$N=3$}{N=3} collective heat spectrum}
+$N=3$ reflection-even/odd 两个 sector 在 $J/\Omega=0.25,0.5,1$ 上共六点全部通过收敛门槛。odd sector 的投影 Hamiltonian 与耦合算符对 $J$ 严格不变,因此三条曲线在机器精度内重合;even sector 则显示随 $J$ 移动的 collective features。
+
+\begin{figure}[htbp]
+\centering
+\includegraphics[width=0.88\linewidth]{n3_sector_heat.png}
+\caption{$N=3$ reflection sector 分辨的频率热流密度。}
+\label{fig:n3heat}
+\end{figure}
+
+\section{Tier 3:同模型非马尔可夫与 Markov 对照}
+误差定义为
+\begin{align}
+D_\rho&=\frac12\lVert\rho_{\rm IF}-\rho_{\rm ME}\rVert_1,\\
+\epsilon_C&=\frac{\int d\tau\,|C_{\rm IF}(\tau)-C_{\rm ME}(\tau)|}{\int d\tau\,|C_{\rm IF}(\tau)|},\\
+\epsilon_j&=\frac{\int d\omega\,|\bar j_{\rm IF}(\omega)-\bar j_{\rm ME}(\omega)|}{\int d\omega\,|\bar j_{\rm IF}(\omega)|}.
+\end{align}
+even sector 上 $D_\rho=0.9921$--$0.9999$、$\epsilon_C=1.024$--$1.153$、$\epsilon_j=9.02$--$11.72$;odd sector 三点均为 $D_\rho=0.4753$、$\epsilon_C=0.5666$、$\epsilon_j=0.3920$。大误差不是精确端未收敛,而是同参数 Markov benchmark 的真实偏差。
+
+\begin{figure}[htbp]
+\centering
+\includegraphics[width=0.92\linewidth]{n3_error_maps.png}
+\caption{$N=3$ 同模型 UniformTEMPO 与 Floquet-Markov/QRT 的三种误差。}
+\label{fig:n3error}
+\end{figure}
+
+\section{\texorpdfstring{$N=4$}{N=4} 收敛门控结果}
+$N=4$ 采用 reflection-even $10$ 维和 reflection-odd $6$ 维子空间。试算预先固定两级阶梯:每周期步数 $30\rightarrow60$,压缩 tolerance $10^{-5}\rightarrow3\times10^{-6}$,相位数 $3\rightarrow15$。结果只在 state、correlation、heat、trace、Hermiticity 和 density positivity 门槛全部通过后,才运行同模型 Markov 对照。
+
+\begin{table}[htbp]
+\centering
+\caption{$N=4,J/\Omega=0.25$ 的门控试算。}
+\label{tab:n4}
+\begin{tabular}{cccccc}
+\toprule
+sector & dim & 状态 & bond & 尾幅 & $\epsilon_j$ \\
+\midrule
+\NFourRows
+\bottomrule
+\end{tabular}
+\end{table}
+
+\NFourConclusion
+
+\begin{figure}[htbp]
+\centering
+\begin{minipage}{0.49\linewidth}
+\includegraphics[width=\linewidth]{n4_even_j0p25_comparison.png}
+\end{minipage}\hfill
+\begin{minipage}{0.49\linewidth}
+\includegraphics[width=\linewidth]{n4_odd_j0p25_comparison.png}
+\end{minipage}
+\caption{$N=4$ even(左)和 odd(右)sector 的收敛 UniformTEMPO 热谱及同模型 Floquet-Markov/QRT 对照。odd 连续谱主要峰位于 $0.4725,0.9600,1.4400\,\Omega$,显示相对于驱动频率 $0.9256\,\Omega$ 的多峰 collective structure。}
+\label{fig:n4}
+\end{figure}
+
+\section{预注册负结果与创新点}
+我们在计算前定义了暗通道继续条件:中心点热流相对两侧至少降低三倍,且可观测 transfer-pole residue 也至少降低三倍。$N=3$ 三点 pilot 中,准能隙虽塌缩,residue 却上升,热流门槛也未通过,因此九点扩展被按规则停止。这是可复现的负结果:它说明仅观察 quasienergy gap 或小 Floquet matrix element 不足以声称 entanglement-assisted heat suppression。
+
+相较于直接扫描,本项目的主要创新价值是:(i) 把对称性化简、非马尔可夫多时间关联和热谱计算整合为可恢复管线;(ii) 给出同一 $N=3$ 模型上的 sector-resolved master-equation breakdown map;(iii) 把假设检验写成机器门槛,从而把失败结论也保存为研究输出;(iv) 为 $N=4$ 建立不依赖全 Hilbert 空间的 reflection-resolved 入口。
+
+\section{可重复性与数据交付}
+仓库提交源代码、测试、PNG/PDF 图、紧凑 JSON 和本报告源文件。体积较大的 \code{results/} 按上游仓库规则不纳入 Git;\code{validation/ARTIFACT\_PROVENANCE.json} 保存本地审计产物的 SHA-256。推荐验证命令为:
+\begin{verbatim}
+.venv/bin/python -m pytest -q
+.venv/bin/python -m ruff check src tests scripts
+.venv/bin/python -m mypy src scripts/run_fig3_validation.py
+.venv/bin/python -m floquet_if_manybody.cli audit results
+.venv/bin/python -m floquet_if_manybody.cli paper-audit results/paper
+\end{verbatim}
+
+\section{结论}
+本项目已经从单自旋代码验证推进到 $N=3$ 多体生产计算,并用同模型误差图直接回答了原题最具方法学价值的问题:Floquet-Markov/QRT 的失效不仅显著,而且依赖多体对称 sector。$N=4$ 结果按预先声明的收敛门槛分类,不以“程序跑完”替代“数值可信”。所有正结果和负结果都可以从固定版本后端、缓存键、JSON 指标与图件哈希重新审计。
+
+\begin{thebibliography}{9}
+\bibitem{mickiewicz2026}
+K. Mickiewicz, V. Link, and W. T. Strunz,
+``Exact Floquet Dynamics of Strongly Damped Driven Quantum Systems,''
+\emph{Physical Review Letters} \textbf{136}, 200201 (2026).
+\bibitem{link2024}
+V. Link, H.-H. Tu, and W. T. Strunz,
+``Open Quantum System Dynamics from Infinite Tensor Network Contraction,''
+\emph{Physical Review Letters} \textbf{132}, 200403 (2024).
+\bibitem{garbellini2026}
+M. Garbellini, K. Mickiewicz, V. Link, A. Eisfeld, and W. T. Strunz,
+``Uniform process tensor approach for the calculation of multi-time correlation functions of non-Markovian open systems,''
+\emph{Journal of Chemical Physics} (2026), doi:10.1063/5.0331783.
+\end{thebibliography}
+
+\end{document}
diff --git a/tracks/mps/solutions/Ranger-123/scripts/instantiate_julia.sh b/tracks/mps/solutions/Ranger-123/scripts/instantiate_julia.sh
new file mode 100755
index 000000000..3aa2e7fd1
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/scripts/instantiate_julia.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+julia --project="${project_root}/julia" -e \
+ 'using Pkg; Pkg.resolve(); Pkg.instantiate(); Pkg.precompile()'
+julia --project="${project_root}/julia" -e \
+ 'using UniformTEMPO, OrdinaryDiffEq, JSON3; println("UniformTEMPO environment ready")'
diff --git a/tracks/mps/solutions/Ranger-123/scripts/run_baselines.sh b/tracks/mps/solutions/Ranger-123/scripts/run_baselines.sh
new file mode 100755
index 000000000..21ac784ce
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/scripts/run_baselines.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+set -eu
+
+project_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
+cd "$project_dir"
+
+python_bin="${PYTHON_BIN:-$project_dir/.venv/bin/python}"
+"$python_bin" -m floquet_if_manybody.cli baselines --output results --figures figures
+"$python_bin" -m floquet_if_manybody.cli audit results
diff --git a/tracks/mps/solutions/Ranger-123/scripts/run_fig3_validation.py b/tracks/mps/solutions/Ranger-123/scripts/run_fig3_validation.py
new file mode 100644
index 000000000..bbbe5bfdf
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/scripts/run_fig3_validation.py
@@ -0,0 +1,277 @@
+#!/usr/bin/env python3
+"""Reproduce and compare the transversal single-spin data from PRL Fig. 3."""
+
+from __future__ import annotations
+
+import argparse
+import hashlib
+import json
+from dataclasses import asdict
+from io import BytesIO
+from pathlib import Path
+from typing import Any
+from urllib.request import urlopen
+from zipfile import ZipFile
+
+import numpy as np
+from matplotlib import pyplot as plt
+from scipy.integrate import trapezoid
+
+from floquet_if_manybody.backends.uniform_tempo import (
+ UNIFORM_TEMPO_REVISION,
+ UniformTempoBackend,
+ UniformTempoControls,
+)
+from floquet_if_manybody.config import BathConfig, ModelConfig
+from floquet_if_manybody.convergence import atomic_write_result, curve_residual
+from floquet_if_manybody.heat_current import heat_current_spectrum
+from floquet_if_manybody.operators import pauli
+
+ZENODO_RECORD = "https://zenodo.org/records/19593671"
+ZENODO_ARCHIVE = (
+ "https://zenodo.org/api/records/19593671/files/"
+ "exact_floquet_dynamics_of_strongly_damped_driven_quantum_systems.zip/content"
+)
+ZENODO_MD5 = "0f3f9d9d8538aa96aee089973df7d9c2"
+REFERENCE_FREQUENCY = np.arange(0.005, 15.0001, 0.005)
+
+
+def _reference_name(drive_frequency: float) -> str:
+ label = f"{drive_frequency:g}"
+ return (
+ "fig_3/heat_current_transversal_Ω_1_ϵ_d_1_"
+ f"ω_d_{label}_α_0.05_ω_c_2.5_bond_dim_235_dt_0.052.csv"
+ )
+
+
+def download_reference() -> dict[float, np.ndarray]:
+ """Download the immutable author archive and extract the three bottom-panel curves."""
+ with urlopen(ZENODO_ARCHIVE, timeout=30) as response: # noqa: S310
+ archive = response.read()
+ digest = hashlib.md5(archive, usedforsecurity=False).hexdigest()
+ if digest != ZENODO_MD5:
+ raise ValueError(f"Zenodo archive checksum mismatch: {digest}")
+ curves: dict[float, np.ndarray] = {}
+ with ZipFile(BytesIO(archive)) as bundle:
+ for drive_frequency in (1.0, 1.5, 2.0):
+ values = np.loadtxt(BytesIO(bundle.read(_reference_name(drive_frequency))))
+ if values.shape != REFERENCE_FREQUENCY.shape or not np.all(np.isfinite(values)):
+ raise ValueError(f"invalid Fig. 3 reference curve for wd={drive_frequency:g}")
+ curves[drive_frequency] = np.asarray(values, dtype=float)
+ return curves
+
+
+def comparison_metrics(reference: np.ndarray, candidate: np.ndarray) -> dict[str, float]:
+ """Return direct-amplitude and normalized-shape discrepancies."""
+ direct = curve_residual(
+ REFERENCE_FREQUENCY,
+ reference,
+ REFERENCE_FREQUENCY,
+ candidate,
+ )
+ reference_area = float(trapezoid(abs(reference), REFERENCE_FREQUENCY))
+ candidate_area = float(trapezoid(abs(candidate), REFERENCE_FREQUENCY))
+ if reference_area <= 0 or candidate_area <= 0:
+ raise ValueError("Fig. 3 curves must have positive integrated magnitude")
+ shape = curve_residual(
+ REFERENCE_FREQUENCY,
+ reference / reference_area,
+ REFERENCE_FREQUENCY,
+ candidate / candidate_area,
+ )
+ return {
+ "continuous_relative_l1": direct,
+ "normalized_shape_relative_l1": shape,
+ "integrated_magnitude_ratio": candidate_area / reference_area,
+ }
+
+
+def run_point(
+ drive_frequency: float,
+ reference: np.ndarray,
+ cache_directory: Path,
+ *,
+ tolerance: float = 1e-6,
+ phase_samples: int = 4,
+) -> dict[str, Any]:
+ """Run one independent UniformTEMPO point at the published Fig. 3 controls."""
+ steps_per_period = int(round(120 / drive_frequency))
+ model = ModelConfig(
+ n=1,
+ j=0.0,
+ omega=1.0,
+ drive_amplitude=1.0,
+ drive_frequency=drive_frequency,
+ )
+ bath = BathConfig(alpha=0.05, cutoff=2.5, temperature=0.0)
+ controls = UniformTempoControls(
+ steps_per_period=steps_per_period,
+ tolerance=tolerance,
+ phase_samples=phase_samples,
+ delay_periods=12,
+ low_rank_svd=True,
+ truncation="abs",
+ cap_rank=5_000,
+ max_rank=10_000,
+ )
+ run = UniformTempoBackend(
+ tensor_cache_directory=cache_directory / "process_tensors"
+ ).run_periodic(
+ 0.5 * pauli("x"),
+ pauli("z"),
+ model,
+ bath,
+ controls,
+ drive_operator=pauli("z"),
+ )
+ heat = heat_current_spectrum(run.correlation, bath, REFERENCE_FREQUENCY)
+ diagnostics = {
+ **run.diagnostics,
+ **run.metadata,
+ "connected_tail_amplitude": float(abs(run.correlation.connected[-1])),
+ }
+ physical_gates_passed = bool(
+ float(diagnostics["fixed_point_residual"]) <= 1e-3
+ and float(diagnostics["trace_error"]) <= 5e-3
+ and float(diagnostics["hermiticity_error"]) <= 5e-3
+ and float(diagnostics["minimum_density_eigenvalue"]) >= -5e-3
+ and float(diagnostics["connected_tail_amplitude"]) <= 5e-2
+ )
+ return {
+ "method": "uniform_tempo_fig3_transversal_reproduction",
+ "converged": physical_gates_passed,
+ "reference": {
+ "record": ZENODO_RECORD,
+ "archive_md5": ZENODO_MD5,
+ "panel": "Fig. 3 bottom",
+ },
+ "uniform_tempo_revision": UNIFORM_TEMPO_REVISION,
+ "model": asdict(model),
+ "bath": asdict(bath),
+ "controls": asdict(controls),
+ "diagnostics": diagnostics,
+ "metrics": comparison_metrics(reference, heat.continuous),
+ "frequency": heat.frequencies.tolist(),
+ "reference_continuous": reference.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(item) for item in heat.delta_peaks],
+ }
+
+
+def plot_result(result: dict[str, Any], stem: Path) -> None:
+ frequency = np.asarray(result["frequency"], dtype=float)
+ reference = np.asarray(result["reference_continuous"], dtype=float)
+ candidate = np.asarray(result["continuous"], dtype=float)
+ figure, axis = plt.subplots(figsize=(7.2, 4.2))
+ axis.plot(frequency, reference, label="Mickiewicz et al. Fig. 3 data", lw=1.5)
+ axis.plot(frequency, candidate, "--", label="independent UniformTEMPO", lw=1.2)
+ for peak in result["delta_peaks"]:
+ axis.axvline(float(peak["frequency"]), color="black", alpha=0.35, lw=0.8)
+ model = result["model"]
+ axis.set(
+ xlim=(0, 4),
+ xlabel=r"bath frequency $\omega/\Omega$",
+ ylabel=r"continuous $\bar j(\omega)/\Omega$",
+ title=rf"Fig. 3 bottom validation, $\omega_d={float(model['drive_frequency']):g}\Omega$",
+ )
+ axis.grid(alpha=0.2)
+ axis.legend(frameon=False)
+ figure.tight_layout()
+ stem.parent.mkdir(parents=True, exist_ok=True)
+ figure.savefig(stem.with_suffix(".png"), dpi=220)
+ figure.savefig(stem.with_suffix(".pdf"))
+ plt.close(figure)
+
+
+def plot_summary(results: list[dict[str, Any]], stem: Path) -> None:
+ """Plot the complete three-curve bottom-panel validation in one artifact."""
+ ordered = sorted(results, key=lambda item: float(item["model"]["drive_frequency"]))
+ figure, axes = plt.subplots(1, 3, figsize=(12.0, 3.55), sharex=True)
+ for axis, result in zip(axes, ordered, strict=True):
+ frequency = np.asarray(result["frequency"], dtype=float)
+ reference = np.asarray(result["reference_continuous"], dtype=float)
+ candidate = np.asarray(result["continuous"], dtype=float)
+ model = result["model"]
+ metrics = result["metrics"]
+ axis.plot(frequency, reference, label="published data", lw=1.35)
+ axis.plot(frequency, candidate, "--", label="independent run", lw=1.15)
+ for peak in result["delta_peaks"]:
+ if float(peak["frequency"]) <= 4:
+ axis.axvline(float(peak["frequency"]), color="black", alpha=0.3, lw=0.7)
+ axis.set(
+ xlim=(0, 4),
+ xlabel=r"$\omega/\Omega$",
+ title=(
+ rf"$\omega_d={float(model['drive_frequency']):g}\Omega$"
+ "\n"
+ rf"shape $L^1={float(metrics['normalized_shape_relative_l1']):.3f}$"
+ ),
+ )
+ axis.grid(alpha=0.2)
+ axes[0].set_ylabel(r"continuous $\bar j(\omega)/\Omega$")
+ axes[0].legend(frameon=False, fontsize=8)
+ figure.suptitle("Independent reproduction of Mickiewicz et al., Fig. 3 bottom")
+ figure.tight_layout()
+ stem.parent.mkdir(parents=True, exist_ok=True)
+ figure.savefig(stem.with_suffix(".png"), dpi=220)
+ figure.savefig(stem.with_suffix(".pdf"))
+ plt.close(figure)
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--drive-frequency",
+ type=float,
+ choices=(1.0, 1.5, 2.0),
+ default=2.0,
+ )
+ parser.add_argument("--plot-only", type=Path)
+ parser.add_argument("--plot-summary", action="store_true")
+ parser.add_argument("--tolerance", type=float, default=1e-6)
+ parser.add_argument("--phase-samples", type=int, default=4)
+ parser.add_argument(
+ "--figures",
+ type=Path,
+ default=Path("figures/validation"),
+ )
+ parser.add_argument("--output", type=Path, default=Path("results/validation"))
+ parser.add_argument(
+ "--cache",
+ type=Path,
+ default=Path("results/cache/fig3_uniform_tempo"),
+ )
+ arguments = parser.parse_args()
+ if arguments.plot_summary:
+ result_paths = [
+ arguments.output / "fig3_transversal_wd1.json",
+ arguments.output / "fig3_transversal_wd1p5.json",
+ arguments.output / "fig3_transversal_wd2.json",
+ ]
+ results = [json.loads(path.read_text(encoding="utf-8")) for path in result_paths]
+ if not all(bool(result["converged"]) for result in results):
+ raise ValueError("all three Fig. 3 points must pass physical gates")
+ plot_summary(results, arguments.figures / "fig3_transversal_summary")
+ return 0
+ if arguments.plot_only is not None:
+ result = json.loads(arguments.plot_only.read_text(encoding="utf-8"))
+ label = f"{float(result['model']['drive_frequency']):g}".replace(".", "p")
+ plot_result(result, arguments.figures / f"fig3_transversal_wd{label}")
+ return 0
+ references = download_reference()
+ result = run_point(
+ arguments.drive_frequency,
+ references[arguments.drive_frequency],
+ arguments.cache,
+ tolerance=arguments.tolerance,
+ phase_samples=arguments.phase_samples,
+ )
+ arguments.output.mkdir(parents=True, exist_ok=True)
+ label = f"{arguments.drive_frequency:g}".replace(".", "p")
+ atomic_write_result(arguments.output / f"fig3_transversal_wd{label}.json", result)
+ plot_result(result, arguments.figures / f"fig3_transversal_wd{label}")
+ return 0 if result["converged"] else 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/tracks/mps/solutions/Ranger-123/scripts/run_paper_extension.sh b/tracks/mps/solutions/Ranger-123/scripts/run_paper_extension.sh
new file mode 100755
index 000000000..1d61c51ac
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/scripts/run_paper_extension.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+PYTHON_BIN="${PYTHON_BIN:-.venv-py312/bin/python}"
+TARGET="${1:-all}"
+OUTPUT_DIR="${OUTPUT_DIR:-results/paper}"
+CACHE_DIR="${CACHE_DIR:-results/cache/uniform_tempo}"
+FIGURE_DIR="${FIGURE_DIR:-figures/paper}"
+FULL_KAC="${FULL_KAC:-0}"
+
+run_n3() {
+ "$PYTHON_BIN" -m floquet_if_manybody.cli n3-heat-grid \
+ --output "$OUTPUT_DIR" --cache "$CACHE_DIR" --figures "$FIGURE_DIR"
+}
+
+run_errors() {
+ "$PYTHON_BIN" -m floquet_if_manybody.cli error-map \
+ --output "$OUTPUT_DIR" --cache "$CACHE_DIR" --figures "$FIGURE_DIR"
+}
+
+run_models() {
+ local extra=()
+ if [[ "$FULL_KAC" == "1" ]]; then
+ extra+=(--full-kac)
+ fi
+ "$PYTHON_BIN" -m floquet_if_manybody.cli model-comparison \
+ --output "$OUTPUT_DIR" --cache "$CACHE_DIR" --figures "$FIGURE_DIR" \
+ "${extra[@]}"
+}
+
+case "$TARGET" in
+ n3) run_n3 ;;
+ errors) run_errors ;;
+ models) run_models ;;
+ all)
+ run_n3
+ run_errors
+ run_models
+ "$PYTHON_BIN" -m floquet_if_manybody.cli paper-audit "$OUTPUT_DIR"
+ ;;
+ *)
+ echo "usage: $0 {n3|errors|models|all}" >&2
+ exit 2
+ ;;
+esac
diff --git a/tracks/mps/solutions/Ranger-123/scripts/run_pt_baselines.sh b/tracks/mps/solutions/Ranger-123/scripts/run_pt_baselines.sh
new file mode 100755
index 000000000..7a3511864
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/scripts/run_pt_baselines.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+set -eu
+
+project_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
+cd "$project_dir"
+
+python_bin="${PYTHON_BIN:-$project_dir/.venv-py312/bin/python}"
+"$python_bin" -m floquet_if_manybody.cli pt-baselines --output results --figures figures
+"$python_bin" -m floquet_if_manybody.cli audit results
diff --git a/tracks/mps/solutions/Ranger-123/scripts/run_uniform_validation.py b/tracks/mps/solutions/Ranger-123/scripts/run_uniform_validation.py
new file mode 100644
index 000000000..127e1727c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/scripts/run_uniform_validation.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python3
+"""Generate runtime validation records for the pinned UniformTEMPO backend."""
+
+from __future__ import annotations
+
+import argparse
+from dataclasses import asdict
+from pathlib import Path
+from typing import Any, cast
+
+import numpy as np
+from numpy.typing import NDArray
+
+from floquet_if_manybody.backends.uniform_tempo import (
+ UNIFORM_TEMPO_REVISION,
+ UniformTempoBackend,
+ UniformTempoControls,
+)
+from floquet_if_manybody.config import BathConfig, ModelConfig
+from floquet_if_manybody.convergence import (
+ ConvergenceCache,
+ atomic_write_result,
+ curve_residual,
+ state_residual,
+)
+from floquet_if_manybody.heat_current import heat_current_spectrum
+from floquet_if_manybody.n3_heat import N3HeatPoint, prepare_n3_sector, run_n3_heat_point
+from floquet_if_manybody.operators import pauli
+
+
+def _complex_values(values: NDArray[np.complex128]) -> dict[str, Any]:
+ return {
+ "real": np.real(values).astype(float).tolist(),
+ "imag": np.imag(values).astype(float).tolist(),
+ }
+
+
+def _complex_array(value: dict[str, Any]) -> NDArray[np.complex128]:
+ return cast(
+ NDArray[np.complex128],
+ np.asarray(value["real"], dtype=float) + 1j * np.asarray(value["imag"], dtype=float),
+ )
+
+
+def single_spin_record(cache_directory: Path) -> dict[str, Any]:
+ model = ModelConfig(
+ n=1,
+ j=0.0,
+ omega=1.0,
+ drive_amplitude=0.2,
+ drive_frequency=1.0,
+ )
+ bath = BathConfig(alpha=0.05, cutoff=2.5, temperature=0.0)
+ controls = UniformTempoControls(
+ steps_per_period=60,
+ tolerance=1e-6,
+ phase_samples=3,
+ delay_periods=6,
+ low_rank_svd=True,
+ truncation="abs",
+ cap_rank=5_000,
+ max_rank=10_000,
+ )
+ run = UniformTempoBackend(
+ tensor_cache_directory=cache_directory / "process_tensors"
+ ).run_periodic(0.5 * pauli("x"), pauli("z"), model, bath, controls)
+ frequency = np.linspace(0.0, 3.0, 401)
+ heat = heat_current_spectrum(run.correlation, bath, frequency)
+ diagnostics = {
+ **run.diagnostics,
+ **run.metadata,
+ "connected_tail_amplitude": float(abs(run.correlation.connected[-1])),
+ }
+ accepted = bool(
+ diagnostics["fixed_point_residual"] <= 1e-3
+ and diagnostics["trace_error"] <= 5e-3
+ and diagnostics["hermiticity_error"] <= 5e-3
+ and diagnostics["minimum_density_eigenvalue"] >= -5e-3
+ and diagnostics["connected_tail_amplitude"] <= 5e-2
+ )
+ return {
+ "method": "uniform_tempo_single_spin_runtime_validation",
+ "converged": accepted,
+ "uniform_tempo_revision": UNIFORM_TEMPO_REVISION,
+ "model": asdict(model),
+ "bath": asdict(bath),
+ "controls": asdict(controls),
+ "diagnostics": diagnostics,
+ "phase_state": _complex_values(run.floquet_state),
+ "frequency": heat.frequencies.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(item) for item in heat.delta_peaks],
+ }
+
+
+def cross_backend_record(cache_directory: Path) -> dict[str, Any]:
+ common = dict(
+ j=0.25,
+ sector="odd",
+ steps_per_period=60,
+ phase_samples=3,
+ delay_periods=1,
+ frequency_points=401,
+ )
+ uniform_point = N3HeatPoint(
+ **common,
+ backend="uniform_tempo",
+ epsrel=1e-6,
+ uniform_low_rank_svd=True,
+ uniform_truncation="abs",
+ uniform_cap_rank=5_000,
+ uniform_max_rank=10_000,
+ )
+ oqupy_point = N3HeatPoint(
+ **common,
+ backend="oqupy",
+ memory_steps=3,
+ epsrel=1e-5,
+ steady_periods=20,
+ )
+ cache = ConvergenceCache(cache_directory)
+ uniform = run_n3_heat_point(uniform_point, cache)
+ oqupy = run_n3_heat_point(oqupy_point, cache, commit="oqupy-cross-validation-v1")
+ uniform_grid = np.asarray(uniform["frequency"], dtype=float)
+ oqupy_grid = np.asarray(oqupy["frequency"], dtype=float)
+ uniform_delay = np.asarray(uniform["correlation"]["delay"], dtype=float)
+ oqupy_delay = np.asarray(oqupy["correlation"]["delay"], dtype=float)
+ metrics = {
+ "phase_state_frobenius": state_residual(
+ _complex_array(oqupy["phase_state"]),
+ _complex_array(uniform["phase_state"]),
+ ),
+ "connected_correlation_relative_l1": curve_residual(
+ oqupy_delay,
+ _complex_array(oqupy["correlation"]["connected"]),
+ uniform_delay,
+ _complex_array(uniform["correlation"]["connected"]),
+ ),
+ "continuous_heat_relative_l1": curve_residual(
+ oqupy_grid,
+ np.asarray(oqupy["continuous"], dtype=float),
+ uniform_grid,
+ np.asarray(uniform["continuous"], dtype=float),
+ ),
+ }
+ reference = prepare_n3_sector(uniform_point)
+ target = prepare_n3_sector(N3HeatPoint(**{**asdict(uniform_point), "j": 1.0}))
+ return {
+ "method": "coarse_uniform_tempo_vs_oqupy_cross_validation",
+ "complete": True,
+ "converged": bool(
+ uniform.get("complete")
+ and oqupy.get("complete")
+ and all(np.isfinite(value) for value in metrics.values())
+ ),
+ "interpretation": ("independent coarse-backend diagnostic; not a convergence refinement"),
+ "uniform_fingerprint": uniform["fingerprint"],
+ "oqupy_fingerprint": oqupy["fingerprint"],
+ "projected_odd_j_invariance": {
+ "h0_frobenius_residual": float(np.linalg.norm(reference.h0 - target.h0)),
+ "coupling_frobenius_residual": float(
+ np.linalg.norm(reference.coupling - target.coupling)
+ ),
+ },
+ "metrics": metrics,
+ }
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--output", type=Path, default=Path("results/validation"))
+ parser.add_argument(
+ "--cache",
+ type=Path,
+ default=Path("results/cache/uniform_tempo"),
+ )
+ arguments = parser.parse_args()
+ arguments.output.mkdir(parents=True, exist_ok=True)
+ single = single_spin_record(arguments.cache)
+ atomic_write_result(
+ arguments.output / "uniform_tempo_single_spin.json",
+ single,
+ )
+ cross = cross_backend_record(arguments.cache)
+ atomic_write_result(
+ arguments.output / "uniform_tempo_oqupy_crosscheck.json",
+ cross,
+ )
+ return 0 if single["converged"] and cross["converged"] else 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/__init__.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/__init__.py
new file mode 100644
index 000000000..04a1f16ea
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/__init__.py
@@ -0,0 +1,6 @@
+"""Few-body Floquet heat-spectroscopy research tools."""
+
+from .config import BathConfig, ModelConfig, NumericsConfig, RunConfig
+
+__all__ = ["BathConfig", "ModelConfig", "NumericsConfig", "RunConfig"]
+__version__ = "0.1.0"
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/adaptive.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/adaptive.py
new file mode 100644
index 000000000..a9d034784
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/adaptive.py
@@ -0,0 +1,702 @@
+"""Ordered, resumable refinement of PT-TEMPO numerical controls."""
+
+from __future__ import annotations
+
+from collections.abc import Callable
+from dataclasses import dataclass, replace
+from typing import Any, Literal, cast
+
+import numpy as np
+from numpy.typing import NDArray
+from scipy.integrate import trapezoid
+
+from .convergence import ConvergenceCache, state_residual
+from .n3_heat import N3HeatPoint
+
+Parameter = Literal[
+ "memory_steps",
+ "steps_per_period",
+ "epsrel",
+ "phase_samples",
+]
+Runner = Callable[[N3HeatPoint, ConvergenceCache | None], dict[str, Any]]
+
+
+@dataclass(frozen=True)
+class AdaptiveSchedule:
+ memory_steps: tuple[int, ...] = (3, 4, 5)
+ steps_per_period: tuple[int, ...] = (12, 16, 20)
+ epsrel: tuple[float, ...] = (1e-5, 3e-6)
+ state_threshold: float = 5e-2
+ correlation_threshold: float = 5e-2
+ heat_threshold: float = 5e-2
+ phase_threshold: float = 1e-3
+ trace_threshold: float = 5e-3
+
+ def __post_init__(self) -> None:
+ if any(value <= 0 for value in self.memory_steps + self.steps_per_period):
+ raise ValueError("integer refinement controls must be positive")
+ if any(not 0 < value < 1 for value in self.epsrel):
+ raise ValueError("epsrel refinements must lie between zero and one")
+ if tuple(sorted(self.memory_steps)) != self.memory_steps:
+ raise ValueError("memory_steps must increase")
+ if tuple(sorted(self.steps_per_period)) != self.steps_per_period:
+ raise ValueError("steps_per_period must increase")
+ if tuple(sorted(self.epsrel, reverse=True)) != self.epsrel:
+ raise ValueError("epsrel must decrease")
+
+
+@dataclass(frozen=True)
+class UniformAdaptiveSchedule:
+ """Refinement controls for a uniform infinite process tensor."""
+
+ steps_per_period: tuple[int, ...] = (60, 90, 120)
+ tolerances: tuple[float, ...] = (3e-7, 1e-7, 3e-8)
+ phase_samples: tuple[int, ...] = (3, 15)
+ state_threshold: float = 5e-2
+ correlation_threshold: float = 8e-2
+ heat_threshold: float = 8e-2
+ phase_threshold: float = 1e-3
+ trace_threshold: float = 5e-3
+ hermiticity_threshold: float = 5e-3
+
+ def __post_init__(self) -> None:
+ if any(value < 2 for value in self.steps_per_period):
+ raise ValueError("steps_per_period values must be at least two")
+ if any(not 0 < value < 1 for value in self.tolerances):
+ raise ValueError("tolerances must lie between zero and one")
+ if any(value < 2 for value in self.phase_samples):
+ raise ValueError("phase_samples values must be at least two")
+ if tuple(sorted(self.steps_per_period)) != self.steps_per_period:
+ raise ValueError("steps_per_period must increase")
+ if tuple(sorted(self.tolerances, reverse=True)) != self.tolerances:
+ raise ValueError("tolerances must decrease")
+ if tuple(sorted(self.phase_samples)) != self.phase_samples:
+ raise ValueError("phase_samples must increase")
+ if any(
+ steps % samples != 0
+ for steps in self.steps_per_period
+ for samples in self.phase_samples
+ ):
+ raise ValueError(
+ "every phase_samples value must divide every timestep refinement"
+ )
+
+
+@dataclass(frozen=True)
+class RefinementEvidence:
+ parameter: Parameter
+ coarse_fingerprint: str
+ refined_fingerprint: str
+ coarse_value: float
+ refined_value: float
+ state_residual: float
+ correlation_residual: float
+ heat_residual: float
+ passed: bool
+ coarse_bond_dimension: int | None = None
+ refined_bond_dimension: int | None = None
+ coarse_steps_per_period: int | None = None
+ refined_steps_per_period: int | None = None
+ coarse_tolerance: float | None = None
+ refined_tolerance: float | None = None
+ coarse_phase_samples: int | None = None
+ refined_phase_samples: int | None = None
+
+
+@dataclass(frozen=True)
+class AdaptiveResult:
+ converged: bool
+ status: Literal["converged", "resource_ceiling", "backend_failure"]
+ final_point: N3HeatPoint
+ final_result: dict[str, Any]
+ evidence: tuple[RefinementEvidence, ...]
+ failed_parameter: Parameter | None = None
+
+
+def _complex_array(value: dict[str, Any]) -> NDArray[np.complex128]:
+ return cast(
+ NDArray[np.complex128],
+ np.asarray(value["real"], dtype=float)
+ + 1j * np.asarray(value["imag"], dtype=float),
+ )
+
+
+def _aligned_residual(
+ candidate_grid: NDArray[np.float64],
+ candidate: NDArray[np.complex128] | NDArray[np.float64],
+ reference_grid: NDArray[np.float64],
+ reference: NDArray[np.complex128] | NDArray[np.float64],
+) -> float:
+ """Compare curves on the coarser grid over their common domain."""
+ lower = max(float(candidate_grid[0]), float(reference_grid[0]))
+ upper = min(float(candidate_grid[-1]), float(reference_grid[-1]))
+ common = candidate_grid[
+ (candidate_grid >= lower - 1e-14) & (candidate_grid <= upper + 1e-14)
+ ]
+ if len(common) < 2:
+ raise ValueError("curve grids do not share a usable interval")
+ candidate_common = np.interp(common, candidate_grid, np.real(candidate)) + 1j * np.interp(
+ common, candidate_grid, np.imag(candidate)
+ )
+ reference_common = np.interp(common, reference_grid, np.real(reference)) + 1j * np.interp(
+ common, reference_grid, np.imag(reference)
+ )
+ numerator = float(trapezoid(abs(candidate_common - reference_common), common))
+ denominator = float(trapezoid(abs(reference_common), common)) + 1e-15
+ return numerator / denominator
+
+
+def _residuals(
+ coarse: dict[str, Any], refined: dict[str, Any]
+) -> tuple[float, float, float]:
+ state = state_residual(
+ _complex_array(coarse["phase_state"]),
+ _complex_array(refined["phase_state"]),
+ )
+ coarse_correlation = _complex_array(coarse["correlation"]["connected"])
+ refined_correlation = _complex_array(refined["correlation"]["connected"])
+ correlation = _aligned_residual(
+ np.asarray(coarse["correlation"]["delay"], dtype=float),
+ coarse_correlation,
+ np.asarray(refined["correlation"]["delay"], dtype=float),
+ refined_correlation,
+ )
+ heat = _aligned_residual(
+ np.asarray(coarse["frequency"], dtype=float),
+ np.asarray(coarse["continuous"], dtype=float),
+ np.asarray(refined["frequency"], dtype=float),
+ np.asarray(refined["continuous"], dtype=float),
+ )
+ return state, correlation, heat
+
+
+def _refinement_values(
+ point: N3HeatPoint, schedule: AdaptiveSchedule, parameter: Parameter
+) -> tuple[int | float, ...]:
+ if parameter == "memory_steps":
+ values: tuple[int | float, ...] = schedule.memory_steps
+ current: int | float = point.memory_steps
+ elif parameter == "steps_per_period":
+ values = schedule.steps_per_period
+ current = point.steps_per_period
+ else:
+ values = schedule.epsrel
+ current = point.epsrel
+ if current in values:
+ return values[values.index(current) :]
+ if parameter != "epsrel":
+ return current, *tuple(value for value in values if value > current)
+ return current, *tuple(value for value in values if value < current)
+
+
+def _replace_parameter(
+ point: N3HeatPoint, parameter: Parameter, value: int | float
+) -> N3HeatPoint:
+ if parameter == "memory_steps":
+ return replace(point, memory_steps=int(value))
+ if parameter == "steps_per_period":
+ steps = int(value)
+ memory = max(
+ point.memory_steps,
+ int(round(point.memory_steps * steps / point.steps_per_period)),
+ )
+ return replace(point, steps_per_period=steps, memory_steps=memory)
+ return replace(point, epsrel=float(value))
+
+
+def run_adaptive(
+ point: N3HeatPoint,
+ schedule: AdaptiveSchedule,
+ runner: Runner,
+ cache: ConvergenceCache | None,
+) -> AdaptiveResult:
+ """Refine memory, timestep, and SVD tolerance in that order."""
+ current_point = point
+ current_result = runner(current_point, cache)
+ evidence: list[RefinementEvidence] = []
+ if not bool(current_result.get("converged", False)):
+ return AdaptiveResult(
+ False, "backend_failure", current_point, current_result, tuple(evidence)
+ )
+
+ for parameter in ("memory_steps", "steps_per_period", "epsrel"):
+ typed_parameter: Parameter = parameter
+ values = _refinement_values(current_point, schedule, typed_parameter)
+ if len(values) < 2:
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ current_point,
+ current_result,
+ tuple(evidence),
+ typed_parameter,
+ )
+ parameter_passed = False
+ for value in values[1:]:
+ refined_point = _replace_parameter(current_point, typed_parameter, value)
+ refined_result = runner(refined_point, cache)
+ if not bool(refined_result.get("converged", False)):
+ return AdaptiveResult(
+ False,
+ "backend_failure",
+ refined_point,
+ refined_result,
+ tuple(evidence),
+ typed_parameter,
+ )
+ state, correlation, heat = _residuals(current_result, refined_result)
+ passed = (
+ state <= schedule.state_threshold
+ and correlation <= schedule.correlation_threshold
+ and heat <= schedule.heat_threshold
+ )
+ evidence.append(
+ RefinementEvidence(
+ typed_parameter,
+ str(current_result["fingerprint"]),
+ str(refined_result["fingerprint"]),
+ float(getattr(current_point, typed_parameter)),
+ float(value),
+ state,
+ correlation,
+ heat,
+ passed,
+ )
+ )
+ current_point = refined_point
+ current_result = refined_result
+ if passed:
+ parameter_passed = True
+ break
+ if not parameter_passed:
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ current_point,
+ current_result,
+ tuple(evidence),
+ typed_parameter,
+ )
+
+ diagnostics = current_result.get("diagnostics", {})
+ final_checks = (
+ float(diagnostics.get("phase_residual", np.inf))
+ <= schedule.phase_threshold
+ and float(diagnostics.get("trace_error", np.inf))
+ <= schedule.trace_threshold
+ and float(diagnostics.get("minimum_density_eigenvalue", -np.inf)) >= -5e-3
+ and float(diagnostics.get("connected_tail_amplitude", np.inf)) <= 5e-2
+ )
+ return AdaptiveResult(
+ final_checks,
+ "converged" if final_checks else "backend_failure",
+ current_point,
+ current_result,
+ tuple(evidence),
+ )
+
+
+def _schedule_tail(
+ current: int | float,
+ values: tuple[int, ...] | tuple[float, ...],
+ *,
+ increasing: bool,
+) -> tuple[int | float, ...]:
+ if current in values:
+ return values[values.index(current) :]
+ if increasing:
+ return current, *tuple(value for value in values if value > current)
+ return current, *tuple(value for value in values if value < current)
+
+
+def _uniform_refined_point(
+ point: N3HeatPoint,
+ parameter: Parameter,
+ value: int | float,
+) -> N3HeatPoint:
+ if parameter == "steps_per_period":
+ return replace(point, steps_per_period=int(value))
+ if parameter == "phase_samples":
+ return replace(point, phase_samples=int(value))
+ if parameter == "epsrel":
+ return replace(point, epsrel=float(value))
+ raise ValueError(f"unsupported uniform refinement parameter {parameter}")
+
+
+def _bond_dimension(result: dict[str, Any]) -> int | None:
+ value = result.get("diagnostics", {}).get("bond_dimension")
+ if value is None:
+ return None
+ return int(value)
+
+
+def _uniform_physical_checks(
+ result: dict[str, Any],
+ schedule: UniformAdaptiveSchedule,
+) -> bool:
+ diagnostics = result.get("diagnostics", {})
+ return bool(
+ float(diagnostics.get("phase_residual", np.inf))
+ <= schedule.phase_threshold
+ and float(diagnostics.get("trace_error", np.inf))
+ <= schedule.trace_threshold
+ and float(diagnostics.get("hermiticity_error", np.inf))
+ <= schedule.hermiticity_threshold
+ and float(diagnostics.get("minimum_density_eigenvalue", -np.inf)) >= -5e-3
+ and float(diagnostics.get("connected_tail_amplitude", np.inf)) <= 5e-2
+ )
+
+
+def run_uniform_adaptive(
+ point: N3HeatPoint,
+ schedule: UniformAdaptiveSchedule,
+ runner: Runner,
+ cache: ConvergenceCache | None,
+) -> AdaptiveResult:
+ """Converge compression at every timestep, then refine phase quadrature.
+
+ Compression and Trotter errors are coupled: a tolerance that is adequate on
+ one time grid need not be adequate on the next. Each timestep candidate is
+ therefore converged across the tolerance ladder before two adjacent
+ timestep candidates are compared.
+ """
+ if point.backend != "uniform_tempo":
+ raise ValueError("uniform adaptive runner requires backend='uniform_tempo'")
+ current_phase_samples = point.phase_samples
+ if current_phase_samples is None:
+ raise ValueError("uniform adaptive runner requires explicit phase_samples")
+
+ evidence: list[RefinementEvidence] = []
+ timestep_values = _schedule_tail(
+ point.steps_per_period,
+ schedule.steps_per_period,
+ increasing=True,
+ )
+ tolerance_values = _schedule_tail(
+ point.epsrel,
+ schedule.tolerances,
+ increasing=False,
+ )
+ if len(timestep_values) < 2 or len(tolerance_values) < 2:
+ failed: Parameter = (
+ "steps_per_period" if len(timestep_values) < 2 else "epsrel"
+ )
+ initial_result = runner(point, cache)
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ point,
+ initial_result,
+ tuple(evidence),
+ failed,
+ )
+
+ previous_timestep_point: N3HeatPoint | None = None
+ previous_timestep_result: dict[str, Any] | None = None
+ previous_compression_passed = False
+ current_point = point
+ current_result: dict[str, Any] | None = None
+ timestep_passed = False
+
+ for step_index, step_value in enumerate(timestep_values):
+ compression_point = replace(
+ point,
+ steps_per_period=int(step_value),
+ epsrel=float(tolerance_values[0]),
+ )
+ compression_result = runner(compression_point, cache)
+ if not bool(compression_result.get("complete", False)):
+ return AdaptiveResult(
+ False,
+ "backend_failure",
+ compression_point,
+ compression_result,
+ tuple(evidence),
+ "epsrel",
+ )
+
+ compression_passed = False
+ for tolerance in tolerance_values[1:]:
+ refined_point = replace(
+ compression_point,
+ epsrel=float(tolerance),
+ )
+ refined_result = runner(refined_point, cache)
+ if not bool(refined_result.get("complete", False)):
+ return AdaptiveResult(
+ False,
+ "backend_failure",
+ refined_point,
+ refined_result,
+ tuple(evidence),
+ "epsrel",
+ )
+ state, correlation, heat = _residuals(
+ compression_result,
+ refined_result,
+ )
+ passed = (
+ state <= schedule.state_threshold
+ and correlation <= schedule.correlation_threshold
+ and heat <= schedule.heat_threshold
+ )
+ evidence.append(
+ RefinementEvidence(
+ "epsrel",
+ str(compression_result["fingerprint"]),
+ str(refined_result["fingerprint"]),
+ float(compression_point.epsrel),
+ float(tolerance),
+ state,
+ correlation,
+ heat,
+ passed,
+ _bond_dimension(compression_result),
+ _bond_dimension(refined_result),
+ compression_point.steps_per_period,
+ refined_point.steps_per_period,
+ compression_point.epsrel,
+ refined_point.epsrel,
+ compression_point.phase_samples,
+ refined_point.phase_samples,
+ )
+ )
+ compression_point = refined_point
+ compression_result = refined_result
+ if passed:
+ compression_passed = True
+ break
+ current_point = compression_point
+ current_result = compression_result
+ if not compression_passed and step_index == len(timestep_values) - 1:
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ current_point,
+ current_result,
+ tuple(evidence),
+ "epsrel",
+ )
+
+ if previous_timestep_point is not None and previous_timestep_result is not None:
+ state, correlation, heat = _residuals(
+ previous_timestep_result,
+ current_result,
+ )
+ passed = (
+ previous_compression_passed
+ and compression_passed
+ and state <= schedule.state_threshold
+ and correlation <= schedule.correlation_threshold
+ and heat <= schedule.heat_threshold
+ and _uniform_physical_checks(current_result, schedule)
+ )
+ evidence.append(
+ RefinementEvidence(
+ "steps_per_period",
+ str(previous_timestep_result["fingerprint"]),
+ str(current_result["fingerprint"]),
+ float(previous_timestep_point.steps_per_period),
+ float(current_point.steps_per_period),
+ state,
+ correlation,
+ heat,
+ passed,
+ _bond_dimension(previous_timestep_result),
+ _bond_dimension(current_result),
+ previous_timestep_point.steps_per_period,
+ current_point.steps_per_period,
+ previous_timestep_point.epsrel,
+ current_point.epsrel,
+ previous_timestep_point.phase_samples,
+ current_point.phase_samples,
+ )
+ )
+ if passed:
+ timestep_passed = True
+ break
+ previous_timestep_point = current_point
+ previous_timestep_result = current_result
+ previous_compression_passed = compression_passed
+
+ if current_result is None:
+ raise RuntimeError("uniform adaptive refinement produced no result")
+ if not timestep_passed:
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ current_point,
+ current_result,
+ tuple(evidence),
+ "steps_per_period",
+ )
+
+ phase_values = _schedule_tail(
+ current_phase_samples,
+ schedule.phase_samples,
+ increasing=True,
+ )
+ if len(phase_values) < 2:
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ current_point,
+ current_result,
+ tuple(evidence),
+ "phase_samples",
+ )
+ phase_passed = False
+ for phase_value in phase_values[1:]:
+ refined_point = replace(current_point, phase_samples=int(phase_value))
+ refined_result = runner(refined_point, cache)
+ if not bool(refined_result.get("complete", False)):
+ return AdaptiveResult(
+ False,
+ "backend_failure",
+ refined_point,
+ refined_result,
+ tuple(evidence),
+ "phase_samples",
+ )
+ state, correlation, heat = _residuals(current_result, refined_result)
+ passed = (
+ state <= schedule.state_threshold
+ and correlation <= schedule.correlation_threshold
+ and heat <= schedule.heat_threshold
+ and _uniform_physical_checks(refined_result, schedule)
+ )
+ evidence.append(
+ RefinementEvidence(
+ "phase_samples",
+ str(current_result["fingerprint"]),
+ str(refined_result["fingerprint"]),
+ float(current_point.phase_samples or current_phase_samples),
+ float(phase_value),
+ state,
+ correlation,
+ heat,
+ passed,
+ _bond_dimension(current_result),
+ _bond_dimension(refined_result),
+ current_point.steps_per_period,
+ refined_point.steps_per_period,
+ current_point.epsrel,
+ refined_point.epsrel,
+ current_point.phase_samples,
+ refined_point.phase_samples,
+ )
+ )
+ current_point = refined_point
+ current_result = refined_result
+ if passed:
+ phase_passed = True
+ break
+ if not phase_passed:
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ current_point,
+ current_result,
+ tuple(evidence),
+ "phase_samples",
+ )
+
+ final_checks = _uniform_physical_checks(current_result, schedule)
+ return AdaptiveResult(
+ final_checks,
+ "converged" if final_checks else "backend_failure",
+ current_point,
+ current_result,
+ tuple(evidence),
+ )
+
+
+def run_uniform_compression_audit(
+ point: N3HeatPoint,
+ schedule: UniformAdaptiveSchedule,
+ runner: Runner,
+ cache: ConvergenceCache | None,
+) -> AdaptiveResult:
+ """Converge only MPO compression and record a timestep resource ceiling.
+
+ This is used for explicitly exploratory points whose next timestep grid is
+ outside the declared local budget. It never returns ``converged``.
+ """
+ if point.backend != "uniform_tempo":
+ raise ValueError("uniform compression audit requires backend='uniform_tempo'")
+ tolerance_values = _schedule_tail(
+ point.epsrel,
+ schedule.tolerances,
+ increasing=False,
+ )
+ current_point = point
+ current_result = runner(current_point, cache)
+ evidence: list[RefinementEvidence] = []
+ if not bool(current_result.get("complete", False)):
+ return AdaptiveResult(
+ False,
+ "backend_failure",
+ current_point,
+ current_result,
+ tuple(evidence),
+ "epsrel",
+ )
+ for tolerance in tolerance_values[1:]:
+ refined_point = replace(current_point, epsrel=float(tolerance))
+ refined_result = runner(refined_point, cache)
+ if not bool(refined_result.get("complete", False)):
+ return AdaptiveResult(
+ False,
+ "backend_failure",
+ refined_point,
+ refined_result,
+ tuple(evidence),
+ "epsrel",
+ )
+ state, correlation, heat = _residuals(current_result, refined_result)
+ passed = (
+ state <= schedule.state_threshold
+ and correlation <= schedule.correlation_threshold
+ and heat <= schedule.heat_threshold
+ )
+ evidence.append(
+ RefinementEvidence(
+ "epsrel",
+ str(current_result["fingerprint"]),
+ str(refined_result["fingerprint"]),
+ current_point.epsrel,
+ refined_point.epsrel,
+ state,
+ correlation,
+ heat,
+ passed,
+ _bond_dimension(current_result),
+ _bond_dimension(refined_result),
+ current_point.steps_per_period,
+ refined_point.steps_per_period,
+ current_point.epsrel,
+ refined_point.epsrel,
+ current_point.phase_samples,
+ refined_point.phase_samples,
+ )
+ )
+ current_point = refined_point
+ current_result = refined_result
+ if passed:
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ current_point,
+ current_result,
+ tuple(evidence),
+ "steps_per_period",
+ )
+ return AdaptiveResult(
+ False,
+ "resource_ceiling",
+ current_point,
+ current_result,
+ tuple(evidence),
+ "epsrel",
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/__init__.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/__init__.py
new file mode 100644
index 000000000..265614438
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/__init__.py
@@ -0,0 +1,21 @@
+"""Open-system solver backends."""
+
+from .base import OpenSystemResult
+from .finite_memory import FiniteMemoryBackend
+from .floquet_markov import FloquetMarkovBackend
+from .pt_tempo import PtTempoBackend
+from .uniform_tempo import (
+ UniformTempoBackend,
+ UniformTempoControls,
+ UniformTempoResult,
+)
+
+__all__ = [
+ "FiniteMemoryBackend",
+ "FloquetMarkovBackend",
+ "OpenSystemResult",
+ "PtTempoBackend",
+ "UniformTempoBackend",
+ "UniformTempoControls",
+ "UniformTempoResult",
+]
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/base.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/base.py
new file mode 100644
index 000000000..8deb6b83d
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/base.py
@@ -0,0 +1,20 @@
+"""Common, provenance-rich open-system result types."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import Any
+
+import numpy as np
+from numpy.typing import NDArray
+
+
+@dataclass(frozen=True)
+class OpenSystemResult:
+ method: str
+ density_matrices: NDArray[np.complex128]
+ times: NDArray[np.float64]
+ converged: bool
+ diagnostics: dict[str, float]
+ metadata: dict[str, Any]
+ step_maps: NDArray[np.complex128] | None = None
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/finite_memory.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/finite_memory.py
new file mode 100644
index 000000000..d6cea3b1e
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/finite_memory.py
@@ -0,0 +1,136 @@
+"""Brute-force augmented-density-tensor influence-functional backend.
+
+This is a transparent finite-memory QUAPI implementation for few-level
+validation. Its cost is O((d^2)^(K+1)); it intentionally refuses unsafe sizes.
+"""
+
+from __future__ import annotations
+
+from collections.abc import Callable
+from dataclasses import asdict
+
+import numpy as np
+from scipy.linalg import expm
+
+from ..config import BathConfig
+from ..influence import InfluenceCoefficients, discretize_influence
+from ..operators import ComplexMatrix
+from .base import OpenSystemResult
+
+
+def _trace_from_vector(vector: np.ndarray, dimension: int) -> complex:
+ return complex(sum(vector[index * dimension + index] for index in range(dimension)))
+
+
+class FiniteMemoryBackend:
+ """Finite-memory path sum in the coupling-operator eigenbasis."""
+
+ method = "finite_memory_if"
+
+ def __init__(self, max_augmented_elements: int = 2_000_000):
+ self.max_augmented_elements = max_augmented_elements
+
+ @staticmethod
+ def _influence_table(
+ eigenvalues: np.ndarray, coefficients: InfluenceCoefficients, depth: int
+ ) -> np.ndarray:
+ dimension = len(eigenvalues)
+ q = dimension**2
+ pairs = [(plus, minus) for plus in range(dimension) for minus in range(dimension)]
+ shape = (q,) * (depth + 1)
+ table = np.ones(shape, dtype=np.complex128)
+ for new_index, (new_plus, new_minus) in enumerate(pairs):
+ delta = eigenvalues[new_plus] - eigenvalues[new_minus]
+ for indices in np.ndindex(*(q,) * depth):
+ exponent = 0.0j
+ for lag, history_index in enumerate(indices, start=1):
+ old_plus, old_minus = pairs[history_index]
+ eta = coefficients.values[lag]
+ exponent -= delta * (
+ eta * eigenvalues[old_plus] - eta.conjugate() * eigenvalues[old_minus]
+ )
+ eta0 = coefficients.values[0]
+ exponent -= delta * (
+ eta0 * eigenvalues[new_plus]
+ - eta0.conjugate() * eigenvalues[new_minus]
+ )
+ table[(new_index, *indices)] = np.exp(exponent)
+ return table
+
+ def run(
+ self,
+ hamiltonian: Callable[[float], ComplexMatrix],
+ coupling: ComplexMatrix,
+ initial_density: ComplexMatrix,
+ bath: BathConfig,
+ dt: float,
+ steps: int,
+ memory_steps: int,
+ ) -> OpenSystemResult:
+ if steps < 1:
+ raise ValueError("steps must be positive")
+ eigenvalues, basis = np.linalg.eigh(coupling)
+ dimension = coupling.shape[0]
+ q = dimension**2
+ augmented_size = q ** (memory_steps + 1)
+ if augmented_size > self.max_augmented_elements:
+ raise ValueError(
+ f"augmented tensor requires {augmented_size} elements; "
+ f"limit is {self.max_augmented_elements}"
+ )
+ coefficients = discretize_influence(bath, dt, memory_steps)
+ rho = basis.conj().T @ initial_density @ basis
+ augmented = rho.reshape(q).copy()
+ histories = 1
+ output = [initial_density.copy()]
+ maximum_trace_error = 0.0
+ minimum_eigenvalue = float(np.min(np.linalg.eigvalsh(initial_density)))
+
+ for step in range(steps):
+ midpoint = (step + 0.5) * dt
+ transformed_h = basis.conj().T @ hamiltonian(midpoint) @ basis
+ unitary = expm(-1j * transformed_h * dt)
+ propagator = np.einsum("ac,bd->abcd", unitary, unitary.conj()).reshape(q, q)
+ active_depth = min(histories, memory_steps)
+ table = self._influence_table(eigenvalues, coefficients, active_depth)
+ transition_shape = (q, q) + (1,) * (active_depth - 1)
+ expanded = propagator.reshape(transition_shape) * augmented[np.newaxis, ...] * table
+ if histories >= memory_steps:
+ augmented = expanded.sum(axis=-1)
+ else:
+ augmented = expanded
+ histories += 1
+ reduced = augmented
+ while reduced.ndim > 1:
+ reduced = reduced.sum(axis=-1)
+ trace = _trace_from_vector(reduced, dimension)
+ maximum_trace_error = max(maximum_trace_error, abs(trace - 1))
+ if abs(trace) > 1e-14:
+ augmented /= trace
+ reduced /= trace
+ rho_s = reduced.reshape(dimension, dimension)
+ rho_lab = basis @ rho_s @ basis.conj().T
+ rho_lab = (rho_lab + rho_lab.conj().T) / 2
+ minimum_eigenvalue = min(minimum_eigenvalue, float(np.min(np.linalg.eigvalsh(rho_lab))))
+ output.append(rho_lab)
+
+ diagnostics = {
+ "trace_error": maximum_trace_error,
+ "minimum_density_eigenvalue": minimum_eigenvalue,
+ "quadrature_error": coefficients.quadrature_error,
+ "correlation_tail_bound": coefficients.tail_bound,
+ }
+ converged = maximum_trace_error < 1e-8 and minimum_eigenvalue > -1e-6
+ return OpenSystemResult(
+ self.method,
+ np.asarray(output),
+ np.asarray(np.arange(steps + 1) * dt, dtype=np.float64),
+ converged,
+ diagnostics,
+ {
+ "bath": asdict(bath),
+ "dt": dt,
+ "memory_steps": memory_steps,
+ "approximation": "finite timestep and hard memory cutoff",
+ },
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/floquet_markov.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/floquet_markov.py
new file mode 100644
index 000000000..1f3e75d39
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/floquet_markov.py
@@ -0,0 +1,192 @@
+"""Secular Floquet-Markov population solver."""
+
+from __future__ import annotations
+
+from collections.abc import Callable
+from dataclasses import dataclass
+
+import numpy as np
+from scipy.linalg import expm
+
+from ..bath import bose_occupation, ohmic_spectral_density
+from ..config import BathConfig
+from ..floquet import FloquetSolution, micromotion, solve_floquet
+from ..operators import ComplexMatrix
+from .base import OpenSystemResult
+
+
+@dataclass(frozen=True)
+class FloquetRates:
+ matrix: np.ndarray
+ fourier_elements: np.ndarray
+
+
+def _bath_rate(frequency: float, bath: BathConfig) -> float:
+ if abs(frequency) < 1e-14:
+ return 0.0
+ positive = abs(frequency)
+ density = float(ohmic_spectral_density(positive, bath))
+ occupation = bose_occupation(positive, bath.temperature)
+ return 2 * np.pi * density * (occupation + (1 if frequency > 0 else 0))
+
+
+class FloquetMarkovBackend:
+ method = "floquet_markov"
+
+ def rates(
+ self,
+ solution: FloquetSolution,
+ coupling: ComplexMatrix,
+ bath: BathConfig,
+ harmonic_cutoff: int,
+ ) -> FloquetRates:
+ cumulative = micromotion(solution)[:-1]
+ steps = len(cumulative)
+ omega_d = 2 * np.pi / solution.period
+ times = np.arange(steps) * solution.period / steps
+ dimension = coupling.shape[0]
+ harmonics = np.arange(-harmonic_cutoff, harmonic_cutoff + 1)
+ elements = np.zeros(
+ (len(harmonics), dimension, dimension), dtype=np.complex128
+ )
+ for time, propagator in zip(times, cumulative, strict=True):
+ periodic_modes = (
+ propagator
+ @ solution.modes
+ @ np.diag(np.exp(1j * solution.quasienergies * time))
+ )
+ instantaneous = periodic_modes.conj().T @ coupling @ periodic_modes
+ elements += (
+ np.exp(-1j * harmonics[:, None, None] * omega_d * time)
+ * instantaneous[None, :, :]
+ / steps
+ )
+
+ rates = np.zeros((dimension, dimension), dtype=float)
+ for target in range(dimension):
+ for source in range(dimension):
+ if target == source:
+ continue
+ for h_index, harmonic in enumerate(harmonics):
+ emitted = (
+ solution.quasienergies[source]
+ - solution.quasienergies[target]
+ + harmonic * omega_d
+ )
+ rates[target, source] += _bath_rate(emitted, bath) * abs(
+ elements[h_index, target, source]
+ ) ** 2
+ for source in range(dimension):
+ rates[source, source] = -np.sum(rates[:, source])
+ return FloquetRates(rates, elements)
+
+ def run(
+ self,
+ hamiltonian: Callable[[float], ComplexMatrix],
+ coupling: ComplexMatrix,
+ bath: BathConfig,
+ period: float,
+ steps: int,
+ harmonic_cutoff: int,
+ ) -> OpenSystemResult:
+ solution = solve_floquet(hamiltonian, period, steps)
+ rate_data = self.rates(solution, coupling, bath, harmonic_cutoff)
+ matrix = rate_data.matrix.copy()
+ rhs = np.zeros(matrix.shape[0])
+ matrix[-1, :] = 1
+ rhs[-1] = 1
+ populations, *_ = np.linalg.lstsq(matrix, rhs, rcond=None)
+ populations = np.real_if_close(populations).real
+ populations = np.clip(populations, 0, None)
+ populations /= populations.sum()
+ dimension = coupling.shape[0]
+ identity = np.eye(dimension, dtype=np.complex128)
+ omega_d = 2 * np.pi / period
+ harmonics = np.arange(-harmonic_cutoff, harmonic_cutoff + 1)
+ cumulative = micromotion(solution)[:-1]
+ dt = period / steps
+ step_maps: list[ComplexMatrix] = []
+ for index, propagator in enumerate(cumulative):
+ time = index * dt
+ modes = (
+ propagator
+ @ solution.modes
+ @ np.diag(np.exp(1j * solution.quasienergies * time))
+ )
+ h = hamiltonian((index + 0.5) * dt)
+ liouvillian = -1j * (
+ np.kron(identity, h) - np.kron(h.T, identity)
+ )
+ for target in range(dimension):
+ for source in range(dimension):
+ if target == source:
+ continue
+ basis_jump = np.outer(modes[:, target], modes[:, source].conj())
+ for harmonic_index, harmonic in enumerate(harmonics):
+ emitted = (
+ solution.quasienergies[source]
+ - solution.quasienergies[target]
+ + harmonic * omega_d
+ )
+ gamma = _bath_rate(emitted, bath)
+ amplitude = rate_data.fourier_elements[
+ harmonic_index, target, source
+ ]
+ if gamma == 0 or abs(amplitude) < 1e-14:
+ continue
+ jump = np.sqrt(gamma) * amplitude * basis_jump
+ product = jump.conj().T @ jump
+ liouvillian += (
+ np.kron(jump.conj(), jump)
+ - 0.5 * np.kron(identity, product)
+ - 0.5 * np.kron(product.T, identity)
+ )
+ step_maps.append(expm(liouvillian * dt))
+
+ period_map = np.eye(dimension**2, dtype=np.complex128)
+ for step_map in step_maps:
+ period_map = step_map @ period_map
+ values, vectors = np.linalg.eig(period_map)
+ steady_index = int(np.argmin(abs(values - 1)))
+ steady_vector = vectors[:, steady_index]
+ steady_density = steady_vector.reshape((dimension, dimension), order="F")
+ steady_density = (steady_density + steady_density.conj().T) / 2
+ steady_density /= np.trace(steady_density)
+ densities = [steady_density]
+ vector = steady_density.reshape(dimension**2, order="F")
+ for step_map in step_maps:
+ vector = step_map @ vector
+ density = vector.reshape((dimension, dimension), order="F")
+ density = (density + density.conj().T) / 2
+ density /= np.trace(density)
+ densities.append(density)
+ vector = density.reshape(dimension**2, order="F")
+ rate_residual = float(np.linalg.norm(rate_data.matrix @ populations))
+ map_residual = float(
+ np.linalg.norm(
+ period_map @ steady_density.reshape(dimension**2, order="F")
+ - steady_density.reshape(dimension**2, order="F")
+ )
+ )
+ return OpenSystemResult(
+ self.method,
+ np.asarray(densities),
+ np.linspace(0, period, steps + 1),
+ map_residual < 1e-8,
+ {
+ "rate_residual": rate_residual,
+ "period_map_residual": map_residual,
+ "trace_error": float(
+ max(abs(np.trace(density) - 1) for density in densities)
+ ),
+ "minimum_population": float(
+ min(np.min(np.linalg.eigvalsh(density)) for density in densities)
+ ),
+ },
+ {
+ "approximation": "Born-Markov, Floquet and full secular approximations",
+ "harmonic_cutoff": harmonic_cutoff,
+ "populations": populations.tolist(),
+ },
+ np.asarray(step_maps),
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/pt_tempo.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/pt_tempo.py
new file mode 100644
index 000000000..b9371693c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/pt_tempo.py
@@ -0,0 +1,180 @@
+"""OQuPy PT-TEMPO backend for controlled non-Markovian calculations."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import Any
+
+import numpy as np
+
+from ..config import BathConfig
+from ..operators import ComplexMatrix
+from .base import OpenSystemResult
+
+
+@dataclass(frozen=True)
+class PtTempoResult:
+ result: OpenSystemResult
+ process_tensor: Any
+ system: Any
+ bath: Any
+ initial_density: ComplexMatrix
+
+
+class PtTempoBackend:
+ """Numerically controlled PT-TEMPO process-tensor wrapper.
+
+ OQuPy uses ``J(w)=2*alpha*w*exp(-w/wc)``. This wrapper passes half of the
+ project's alpha so both packages implement the same spectral density.
+ """
+
+ method = "pt_tempo"
+
+ @staticmethod
+ def _oqupy() -> Any:
+ try:
+ import oqupy
+ except ImportError as exc:
+ raise RuntimeError(
+ "PT-TEMPO requires the 'nonmarkov' optional dependencies"
+ ) from exc
+ return oqupy
+
+ def run(
+ self,
+ hamiltonian: Any,
+ coupling: ComplexMatrix,
+ initial_density: ComplexMatrix,
+ bath_config: BathConfig,
+ dt: float,
+ steps: int,
+ memory_steps: int,
+ epsrel: float,
+ ) -> PtTempoResult:
+ if dt <= 0 or steps < 1 or memory_steps < 1 or not 0 < epsrel < 1:
+ raise ValueError("invalid PT-TEMPO numerical parameters")
+ oqupy = self._oqupy()
+ correlations = oqupy.PowerLawSD(
+ alpha=bath_config.alpha / 2,
+ zeta=1,
+ cutoff=bath_config.cutoff,
+ cutoff_type="exponential",
+ temperature=bath_config.temperature,
+ )
+ bath = oqupy.Bath(coupling, correlations)
+ parameters = oqupy.TempoParameters(
+ dt=dt,
+ epsrel=epsrel,
+ dkmax=memory_steps,
+ )
+ process_tensor = oqupy.pt_tempo_compute(
+ bath=bath,
+ start_time=0.0,
+ end_time=steps * dt,
+ parameters=parameters,
+ unique=True,
+ progress_type="silent",
+ )
+ system = oqupy.TimeDependentSystem(hamiltonian)
+ dynamics = oqupy.compute_dynamics(
+ system=system,
+ initial_state=initial_density,
+ process_tensor=process_tensor,
+ progress_type="silent",
+ )
+ states = np.asarray(dynamics.states, dtype=np.complex128)
+ traces = np.trace(states, axis1=1, axis2=2)
+ trace_error = float(np.max(abs(traces - 1)))
+ minimum_eigenvalue = float(
+ min(np.min(np.linalg.eigvalsh((state + state.conj().T) / 2)) for state in states)
+ )
+ bond_dimensions = process_tensor.get_bond_dimensions()
+ result = OpenSystemResult(
+ self.method,
+ states,
+ np.asarray(dynamics.times, dtype=np.float64),
+ trace_error < 5e-3 and minimum_eigenvalue > -5e-3,
+ {
+ "trace_error": trace_error,
+ "minimum_density_eigenvalue": minimum_eigenvalue,
+ "maximum_bond_dimension": float(np.max(bond_dimensions)),
+ },
+ {
+ "approximation": "PT-TEMPO: finite dt, dkmax and SVD epsrel",
+ "dt": dt,
+ "memory_steps": memory_steps,
+ "epsrel": epsrel,
+ "spectral_density_convention": (
+ "OQuPy alpha divided by two to match J=alpha*w*exp(-w/wc)"
+ ),
+ },
+ )
+ return PtTempoResult(result, process_tensor, system, bath, initial_density)
+
+ def period_averaged_correlation(
+ self,
+ run: PtTempoResult,
+ operator: ComplexMatrix,
+ phase_start: int,
+ period_steps: int,
+ delay_steps: int,
+ drive_frequency: float,
+ phase_offsets: list[int] | None = None,
+ ) -> Any:
+ """Calculate exact process-tensor insertions and average drive phases."""
+ from ..correlations import CorrelationResult, coherent_decomposition
+
+ oqupy = self._oqupy()
+ offsets = list(range(period_steps)) if phase_offsets is None else phase_offsets
+ if (
+ len(offsets) < 2
+ or len(set(offsets)) != len(offsets)
+ or min(offsets) < 0
+ or max(offsets) >= period_steps
+ ):
+ raise ValueError("phase offsets must be distinct indices in one period")
+ initial_indices = [phase_start + offset for offset in offsets]
+ final_indices = list(
+ range(phase_start, phase_start + period_steps + delay_steps)
+ )
+ _, matrix = oqupy.compute_correlations(
+ system=run.system,
+ process_tensor=run.process_tensor,
+ operator_a=operator,
+ operator_b=operator,
+ times_a=initial_indices,
+ times_b=final_indices,
+ time_order="ordered",
+ initial_state=run.initial_density,
+ progress_type="silent",
+ )
+ total = np.empty(delay_steps + 1, dtype=np.complex128)
+ for delay in range(delay_steps + 1):
+ values = [
+ matrix[row, offset + delay]
+ for row, offset in enumerate(offsets)
+ ]
+ total[delay] = np.mean(values)
+ dt = float(run.result.times[1] - run.result.times[0])
+ delays = np.arange(delay_steps + 1, dtype=np.float64) * dt
+ phase_states = run.result.density_matrices[
+ [phase_start + offset for offset in offsets]
+ ]
+ one_point = np.real(
+ np.einsum("ij,tji->t", operator, phase_states, optimize=True)
+ )
+ coherent, peaks = coherent_decomposition(one_point, drive_frequency, delays)
+ return CorrelationResult(
+ delays,
+ total,
+ total - coherent,
+ coherent,
+ peaks,
+ "pt_tempo_multitime",
+ {
+ "period_steps": float(period_steps),
+ "phase_samples": float(len(offsets)),
+ "dt": dt,
+ "phase_start": float(phase_start),
+ },
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/uniform_tempo.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/uniform_tempo.py
new file mode 100644
index 000000000..8bb09222d
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/backends/uniform_tempo.py
@@ -0,0 +1,472 @@
+"""Pinned UniformTEMPO.jl backend for periodic non-Markovian correlations."""
+
+from __future__ import annotations
+
+import hashlib
+import json
+import shutil
+import subprocess
+import tempfile
+from dataclasses import asdict, dataclass, field
+from pathlib import Path
+from typing import Any, Literal, cast
+
+import numpy as np
+from numpy.typing import NDArray
+
+from ..config import BathConfig, ModelConfig
+from ..correlations import CorrelationResult, coherent_decomposition
+from ..operators import ComplexMatrix
+
+METHOD = "uniform_tempo_floquet_multitime"
+UNIFORM_TEMPO_REVISION = "b76a018c32e5415989761d902b1b0e95f1a337da"
+
+
+@dataclass(frozen=True)
+class UniformTempoControls:
+ """Complete numerical controls passed to the Julia runner."""
+
+ steps_per_period: int
+ tolerance: float
+ phase_samples: int
+ delay_periods: int
+ auto_nc: bool = True
+ memory_cutoff: int = 100_000
+ low_rank_svd: bool = False
+ truncation: Literal["rel", "abs"] = "rel"
+ cap_rank: int = 100_000
+ max_rank: int = 100_000
+ pole_count: int = 0
+ pole_tolerance: float = 1e-10
+ pole_maxiter: int = 2_000
+
+ def __post_init__(self) -> None:
+ if self.steps_per_period < 2:
+ raise ValueError("steps_per_period must be at least two")
+ if not 0 < self.tolerance < 1:
+ raise ValueError("tolerance must lie between zero and one")
+ if (
+ self.phase_samples < 2
+ or self.phase_samples > self.steps_per_period
+ or self.steps_per_period % self.phase_samples != 0
+ ):
+ raise ValueError("phase_samples must divide steps_per_period")
+ if self.delay_periods < 1:
+ raise ValueError("delay_periods must be positive")
+ if self.memory_cutoff < 1:
+ raise ValueError("memory_cutoff must be positive")
+ if self.truncation not in ("rel", "abs"):
+ raise ValueError("truncation must be 'rel' or 'abs'")
+ if self.cap_rank < 1 or self.max_rank < self.cap_rank:
+ raise ValueError("invalid rank limits")
+ if isinstance(self.pole_count, bool) or self.pole_count < 0:
+ raise ValueError("pole_count must be nonnegative")
+ if self.pole_tolerance <= 0:
+ raise ValueError("pole_tolerance must be positive")
+ if isinstance(self.pole_maxiter, bool) or self.pole_maxiter < 1:
+ raise ValueError("pole_maxiter must be positive")
+
+ @property
+ def phase_offsets(self) -> tuple[int, ...]:
+ stride = self.steps_per_period // self.phase_samples
+ return tuple(range(0, self.steps_per_period, stride))
+
+ @property
+ def delay_steps(self) -> int:
+ return self.delay_periods * self.steps_per_period
+
+
+@dataclass(frozen=True)
+class UniformTempoResult:
+ method: str
+ floquet_state: ComplexMatrix
+ phase_states: NDArray[np.complex128]
+ correlation: CorrelationResult
+ diagnostics: dict[str, float]
+ metadata: dict[str, float | int | str]
+ transfer_eigenvalues: NDArray[np.complex128] = field(
+ default_factory=lambda: np.empty(0, dtype=np.complex128)
+ )
+ transfer_eigenpair_residuals: NDArray[np.float64] = field(
+ default_factory=lambda: np.empty(0, dtype=np.float64)
+ )
+
+
+def _encode_complex(values: NDArray[np.complex128] | ComplexMatrix) -> dict[str, Any]:
+ array = np.asarray(values, dtype=np.complex128)
+ return {
+ "real": np.real(array).astype(float).tolist(),
+ "imag": np.imag(array).astype(float).tolist(),
+ }
+
+
+def _tensor_cache_key(
+ coupling: ComplexMatrix,
+ model: ModelConfig,
+ bath: BathConfig,
+ controls: UniformTempoControls,
+) -> str:
+ """Fingerprint every input that changes the uniform process tensor."""
+ payload = {
+ "schema": "uniform-process-tensor-v1",
+ "uniform_tempo_revision": UNIFORM_TEMPO_REVISION,
+ "coupling": _encode_complex(np.asarray(coupling, dtype=np.complex128)),
+ "bath": asdict(bath),
+ "dt": model.period / controls.steps_per_period,
+ "tolerance": controls.tolerance,
+ "auto_nc": controls.auto_nc,
+ "memory_cutoff": controls.memory_cutoff,
+ "low_rank_svd": controls.low_rank_svd,
+ "truncation": controls.truncation,
+ "cap_rank": controls.cap_rank,
+ "max_rank": controls.max_rank,
+ }
+ encoded = json.dumps(
+ payload,
+ sort_keys=True,
+ separators=(",", ":"),
+ allow_nan=False,
+ ).encode("utf-8")
+ return hashlib.sha256(encoded).hexdigest()
+
+
+def _required(payload: dict[str, Any], key: str, context: str = "payload") -> Any:
+ if key not in payload:
+ raise ValueError(f"{context} is missing required field {key!r}")
+ return payload[key]
+
+
+def _decode_complex(
+ payload: dict[str, Any],
+ *,
+ label: str,
+ allow_empty: bool = False,
+) -> NDArray[np.complex128]:
+ try:
+ shape = tuple(int(value) for value in payload["shape"])
+ real = np.asarray(payload["real"], dtype=float)
+ imag = np.asarray(payload["imag"], dtype=float)
+ except (KeyError, TypeError, ValueError) as exc:
+ raise ValueError(f"{label} has an invalid complex-array schema") from exc
+ expected = int(np.prod(shape, dtype=np.int64))
+ if (
+ expected < 0
+ or (expected == 0 and not allow_empty)
+ or real.size != expected
+ or imag.size != expected
+ ):
+ raise ValueError(f"{label} data do not match the declared shape")
+ values = real.reshape(-1) + 1j * imag.reshape(-1)
+ array = values.reshape(shape, order="F")
+ if not np.all(np.isfinite(array)):
+ raise ValueError(f"{label} contains non-finite values")
+ return cast(NDArray[np.complex128], array)
+
+
+class UniformTempoBackend:
+ """Subprocess boundary around the pinned Julia implementation."""
+
+ def __init__(
+ self,
+ *,
+ command_prefix: tuple[str, ...] | None = None,
+ timeout_seconds: float = 86_400.0,
+ tensor_cache_directory: Path | None = None,
+ ) -> None:
+ if timeout_seconds <= 0:
+ raise ValueError("timeout_seconds must be positive")
+ root = Path(__file__).resolve().parents[3]
+ if command_prefix is None:
+ julia = shutil.which("julia")
+ if julia is None:
+ raise RuntimeError("UniformTEMPO backend requires Julia on PATH")
+ command_prefix = (
+ julia,
+ f"--project={root / 'julia'}",
+ str(root / "julia" / "run_uniform_tempo.jl"),
+ )
+ if not command_prefix:
+ raise ValueError("command_prefix must not be empty")
+ self._command_prefix = tuple(command_prefix)
+ self._timeout_seconds = timeout_seconds
+ self._tensor_cache_directory = (
+ None
+ if tensor_cache_directory is None
+ else Path(tensor_cache_directory).resolve()
+ )
+
+ def run_periodic(
+ self,
+ h0: ComplexMatrix,
+ coupling: ComplexMatrix,
+ model: ModelConfig,
+ bath: BathConfig,
+ controls: UniformTempoControls,
+ *,
+ drive_operator: ComplexMatrix | None = None,
+ ) -> UniformTempoResult:
+ """Compute the Floquet state and phase-averaged two-time correlation."""
+ h0_array = np.asarray(h0, dtype=np.complex128)
+ coupling_array = np.asarray(coupling, dtype=np.complex128)
+ drive_array = (
+ coupling_array
+ if drive_operator is None
+ else np.asarray(drive_operator, dtype=np.complex128)
+ )
+ if h0_array.ndim != 2 or h0_array.shape[0] != h0_array.shape[1]:
+ raise ValueError("h0 must be a square matrix")
+ if coupling_array.shape != h0_array.shape:
+ raise ValueError("coupling must match h0")
+ if drive_array.shape != h0_array.shape:
+ raise ValueError("drive_operator must match h0")
+ if not all(
+ np.all(np.isfinite(array))
+ for array in (h0_array, coupling_array, drive_array)
+ ):
+ raise ValueError("system operators must contain finite values")
+ if not np.allclose(h0_array, h0_array.conj().T, atol=1e-10):
+ raise ValueError("h0 must be Hermitian")
+ if not np.allclose(coupling_array, coupling_array.conj().T, atol=1e-10):
+ raise ValueError("coupling must be Hermitian")
+ if not np.allclose(drive_array, drive_array.conj().T, atol=1e-10):
+ raise ValueError("drive_operator must be Hermitian")
+
+ request: dict[str, Any] = {
+ "h0": _encode_complex(h0_array),
+ "coupling": _encode_complex(coupling_array),
+ "drive": _encode_complex(drive_array),
+ "model": asdict(model),
+ "bath": asdict(bath),
+ "controls": {
+ "steps_per_period": controls.steps_per_period,
+ "tolerance": controls.tolerance,
+ "phase_offsets": list(controls.phase_offsets),
+ "delay_steps": controls.delay_steps,
+ "auto_nc": controls.auto_nc,
+ "memory_cutoff": controls.memory_cutoff,
+ "low_rank_svd": controls.low_rank_svd,
+ "truncation": controls.truncation,
+ "cap_rank": controls.cap_rank,
+ "max_rank": controls.max_rank,
+ "pole_count": controls.pole_count,
+ "pole_tolerance": controls.pole_tolerance,
+ "pole_maxiter": controls.pole_maxiter,
+ },
+ }
+ if self._tensor_cache_directory is not None:
+ tensor_key = _tensor_cache_key(
+ coupling_array,
+ model,
+ bath,
+ controls,
+ )
+ self._tensor_cache_directory.mkdir(parents=True, exist_ok=True)
+ request["controls"]["process_tensor_cache_key"] = tensor_key
+ request["controls"]["process_tensor_cache_path"] = str(
+ self._tensor_cache_directory / f"{tensor_key}.jls"
+ )
+ with tempfile.TemporaryDirectory(prefix="uniform-tempo-") as temporary:
+ temporary_path = Path(temporary)
+ input_path = temporary_path / "input.json"
+ output_path = temporary_path / "output.json"
+ input_path.write_text(
+ json.dumps(request, sort_keys=True),
+ encoding="utf-8",
+ )
+ try:
+ completed = subprocess.run(
+ [*self._command_prefix, str(input_path), str(output_path)],
+ capture_output=True,
+ text=True,
+ timeout=self._timeout_seconds,
+ check=False,
+ )
+ except subprocess.TimeoutExpired as exc:
+ raise RuntimeError(
+ f"UniformTEMPO runner exceeded {self._timeout_seconds:g} seconds"
+ ) from exc
+ if completed.returncode != 0:
+ detail = completed.stderr.strip() or completed.stdout.strip()
+ raise RuntimeError(
+ f"UniformTEMPO runner failed with exit code "
+ f"{completed.returncode}: {detail}"
+ )
+ if not output_path.is_file():
+ raise RuntimeError("UniformTEMPO runner did not create output JSON")
+ try:
+ payload = cast(
+ dict[str, Any],
+ json.loads(output_path.read_text(encoding="utf-8")),
+ )
+ except (json.JSONDecodeError, OSError) as exc:
+ raise ValueError("UniformTEMPO runner returned malformed JSON") from exc
+ return self._validate_payload(payload, h0_array.shape[0], model, controls)
+
+ @staticmethod
+ def _validate_payload(
+ payload: dict[str, Any],
+ dimension: int,
+ model: ModelConfig,
+ controls: UniformTempoControls,
+ ) -> UniformTempoResult:
+ method = str(_required(payload, "method"))
+ if method != METHOD:
+ raise ValueError(f"unexpected UniformTEMPO method label {method!r}")
+ for provenance_key in (
+ "julia_version",
+ "uniform_tempo_revision",
+ "manifest_sha256",
+ ):
+ if provenance_key not in payload or not str(payload[provenance_key]):
+ raise ValueError("UniformTEMPO payload is missing provenance")
+ manifest_hash = str(payload["manifest_sha256"])
+ if len(manifest_hash) != 64:
+ raise ValueError("UniformTEMPO manifest provenance is invalid")
+
+ period_steps = int(_required(payload, "period_steps"))
+ if period_steps != controls.steps_per_period:
+ raise ValueError("UniformTEMPO period grid does not match the request")
+ phase_offsets = tuple(int(value) for value in _required(payload, "phase_offsets"))
+ if phase_offsets != controls.phase_offsets:
+ raise ValueError("UniformTEMPO phase grid does not match the request")
+ dt = float(_required(payload, "dt"))
+ if not np.isclose(
+ dt,
+ model.period / controls.steps_per_period,
+ rtol=1e-11,
+ atol=1e-13,
+ ):
+ raise ValueError("UniformTEMPO timestep does not match the model period")
+
+ floquet_state_raw = _decode_complex(
+ cast(dict[str, Any], _required(payload, "floquet_state")),
+ label="floquet_state",
+ )
+ if floquet_state_raw.shape != (dimension, dimension):
+ raise ValueError("floquet_state has the wrong shape")
+ phase_states_raw = _decode_complex(
+ cast(dict[str, Any], _required(payload, "phase_states")),
+ label="phase_states",
+ )
+ expected_phase_shape = (
+ dimension,
+ dimension,
+ controls.phase_samples,
+ )
+ if phase_states_raw.shape != expected_phase_shape:
+ raise ValueError("phase_states have the wrong shape")
+ phase_states = np.moveaxis(phase_states_raw, 2, 0)
+
+ delay = np.asarray(_required(payload, "delay"), dtype=float)
+ if delay.shape != (controls.delay_steps + 1,) or not np.all(np.isfinite(delay)):
+ raise ValueError("delay grid has the wrong shape")
+ if not np.allclose(delay, np.arange(len(delay)) * dt, atol=1e-12):
+ raise ValueError("delay grid is not uniform")
+ total = _decode_complex(
+ cast(dict[str, Any], _required(payload, "correlation")),
+ label="correlation",
+ )
+ if total.shape != delay.shape:
+ raise ValueError("correlation data do not match the delay shape")
+ one_point = np.asarray(_required(payload, "one_point"), dtype=float)
+ if one_point.shape != (controls.phase_samples,) or not np.all(
+ np.isfinite(one_point)
+ ):
+ raise ValueError("one_point data have the wrong shape")
+ coherent, peaks = coherent_decomposition(
+ one_point,
+ model.drive_frequency,
+ delay,
+ )
+ correlation = CorrelationResult(
+ delay,
+ total,
+ total - coherent,
+ coherent,
+ peaks,
+ METHOD,
+ {
+ "period_steps": float(period_steps),
+ "phase_samples": float(controls.phase_samples),
+ "dt": dt,
+ },
+ )
+
+ diagnostics_payload = cast(
+ dict[str, Any],
+ _required(payload, "diagnostics"),
+ )
+ diagnostic_keys = (
+ "trace_error",
+ "hermiticity_error",
+ "minimum_density_eigenvalue",
+ "fixed_point_residual",
+ "floquet_transfer_residual",
+ )
+ try:
+ diagnostics = {
+ key: float(diagnostics_payload[key]) for key in diagnostic_keys
+ }
+ except (KeyError, TypeError, ValueError) as exc:
+ raise ValueError("UniformTEMPO diagnostics are incomplete") from exc
+ if not all(np.isfinite(value) for value in diagnostics.values()):
+ raise ValueError("UniformTEMPO diagnostics contain non-finite values")
+
+ transfer_dimension = int(_required(payload, "transfer_dimension"))
+ if transfer_dimension < 2:
+ raise ValueError("UniformTEMPO transfer dimension is invalid")
+ transfer_eigenvalues = _decode_complex(
+ cast(dict[str, Any], _required(payload, "transfer_eigenvalues")),
+ label="transfer_eigenvalues",
+ allow_empty=True,
+ )
+ if transfer_eigenvalues.ndim != 1:
+ raise ValueError("transfer_eigenvalues must be one-dimensional")
+ transfer_eigenpair_residuals = np.asarray(
+ _required(payload, "transfer_eigenpair_residuals"),
+ dtype=float,
+ )
+ if transfer_eigenpair_residuals.ndim != 1:
+ raise ValueError(
+ "transfer_eigenpair_residuals must be one-dimensional"
+ )
+ if transfer_eigenvalues.shape != transfer_eigenpair_residuals.shape:
+ raise ValueError(
+ "transfer eigenvalues and residuals must have the same length"
+ )
+ expected_poles = min(controls.pole_count, transfer_dimension - 1)
+ if len(transfer_eigenvalues) != expected_poles:
+ raise ValueError(
+ "UniformTEMPO returned "
+ f"{len(transfer_eigenvalues)} poles; expected {expected_poles}"
+ )
+ if not np.all(np.isfinite(transfer_eigenpair_residuals)):
+ raise ValueError("transfer eigenpair residuals contain non-finite values")
+ if np.any(transfer_eigenpair_residuals < 0):
+ raise ValueError("transfer eigenpair residuals must be nonnegative")
+
+ metadata: dict[str, float | int | str] = {
+ "dt": dt,
+ "period_steps": period_steps,
+ "phase_samples": controls.phase_samples,
+ "bond_dimension": int(_required(payload, "bond_dimension")),
+ "tolerance": controls.tolerance,
+ "julia_version": str(payload["julia_version"]),
+ "uniform_tempo_revision": str(payload["uniform_tempo_revision"]),
+ "manifest_sha256": manifest_hash,
+ "process_tensor_cache_hit": int(
+ bool(_required(payload, "process_tensor_cache_hit"))
+ ),
+ "transfer_dimension": transfer_dimension,
+ "pole_count": len(transfer_eigenvalues),
+ }
+ return UniformTempoResult(
+ method,
+ floquet_state_raw,
+ phase_states,
+ correlation,
+ diagnostics,
+ metadata,
+ transfer_eigenvalues,
+ transfer_eigenpair_residuals,
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/bath.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/bath.py
new file mode 100644
index 000000000..b6ec2d00c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/bath.py
@@ -0,0 +1,45 @@
+"""Ohmic bosonic-bath conventions used throughout the project."""
+
+from __future__ import annotations
+
+import numpy as np
+from scipy.integrate import quad
+
+from .config import BathConfig
+
+
+def ohmic_spectral_density(frequency: float | np.ndarray, bath: BathConfig) -> float | np.ndarray:
+ frequency_array = np.asarray(frequency)
+ result = bath.alpha * frequency_array * np.exp(-frequency_array / bath.cutoff)
+ result = np.where(frequency_array >= 0, result, 0.0)
+ return float(result) if result.ndim == 0 else result
+
+
+def bose_occupation(frequency: float, temperature: float) -> float:
+ if frequency <= 0:
+ raise ValueError("frequency must be positive")
+ if temperature == 0:
+ return 0.0
+ argument = frequency / temperature
+ if argument > 700:
+ return 0.0
+ return float(1.0 / float(np.expm1(argument)))
+
+
+def bath_correlation(time: float, bath: BathConfig) -> complex:
+ """Return for J(w)=alpha*w*exp(-w/wc), hbar=kB=1."""
+ zero_temperature = bath.alpha * bath.cutoff**2 / (1 + 1j * bath.cutoff * time) ** 2
+ if bath.temperature == 0 or bath.alpha == 0:
+ return complex(zero_temperature)
+
+ def thermal_real(frequency: float) -> float:
+ density = float(ohmic_spectral_density(frequency, bath))
+ return float(
+ 2
+ * density
+ * bose_occupation(frequency, bath.temperature)
+ * np.cos(frequency * time)
+ )
+
+ thermal, _ = quad(thermal_real, 0, np.inf, epsabs=1e-10, epsrel=1e-9, limit=300)
+ return complex(zero_temperature + thermal)
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/cli.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/cli.py
new file mode 100644
index 000000000..290f6ec6a
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/cli.py
@@ -0,0 +1,430 @@
+"""Command line interface for baseline generation and audit."""
+
+from __future__ import annotations
+
+import argparse
+import json
+import sys
+from dataclasses import asdict
+from pathlib import Path
+from typing import Literal
+
+import numpy as np
+
+from .experiments import (
+ backend_comparison,
+ n2_bright_sweep,
+ n2_markov_heat_spectrum,
+ n3_sector_sweep,
+)
+from .io import read_result, write_result
+from .plotting import (
+ plot_backend_comparison,
+ plot_dark_diagnostics,
+ plot_error_maps,
+ plot_heat_spectrum,
+ plot_heat_valve_hero,
+ plot_model_variants,
+ plot_n2,
+ plot_n3,
+ plot_n3_error_maps,
+ plot_n3_pt_dynamics,
+ plot_n3_sector_heat,
+ plot_n4_pilot_comparison,
+ plot_odd_sector_difference,
+)
+
+ExactBackend = Literal["uniform_tempo", "oqupy"]
+
+
+def generate_baselines(output: Path, figures: Path, quick: bool = False) -> int:
+ n2 = n2_bright_sweep(np.linspace(0, 2, 17 if quick else 81))
+ n3_values = np.geomspace(0.125, 16, 15 if quick else 49)
+ n3 = n3_sector_sweep(n3_values)
+ comparison = backend_comparison(
+ [0.005, 0.01] if quick else [0.005, 0.01, 0.025, 0.05],
+ steps_per_period=24 if quick else 48,
+ periods=4 if quick else 100,
+ )
+ heat = n2_markov_heat_spectrum(
+ steps_per_period=32 if quick else 96,
+ correlation_periods=3 if quick else 16,
+ )
+ paths = {
+ "n2_exact.json": n2,
+ "n3_exact.json": n3,
+ "backend_comparison.json": comparison,
+ "n2_markov_heat.json": heat,
+ }
+ for name, payload in paths.items():
+ write_result(output / name, payload)
+ plot_n2(read_result(output / "n2_exact.json"), figures / "n2_exact")
+ plot_n3(read_result(output / "n3_exact.json"), figures / "n3_exact")
+ plot_backend_comparison(
+ read_result(output / "backend_comparison.json"), figures / "backend_comparison"
+ )
+ plot_heat_spectrum(
+ read_result(output / "n2_markov_heat.json"), figures / "n2_markov_heat"
+ )
+ return 0
+
+
+def audit_results(directory: Path, allow_unconverged: bool = False) -> int:
+ failures: list[str] = []
+ files = sorted(
+ path
+ for path in directory.glob("*.json")
+ if path.name != "ARTIFACT_PROVENANCE.json"
+ )
+ if not files:
+ failures.append("no result files")
+ for path in files:
+ try:
+ result = read_result(path)
+ except (ValueError, OSError) as exc:
+ failures.append(str(exc))
+ continue
+ if not result["converged"] and not allow_unconverged:
+ failures.append(f"{path.name}: unconverged")
+ if "method" not in result:
+ failures.append(f"{path.name}: missing method label")
+ if failures:
+ for failure in failures:
+ print(f"FAIL: {failure}")
+ return 1
+ print(f"PASS: audited {len(files)} result files")
+ return 0
+
+
+def generate_pt_baselines(output: Path, figures: Path) -> int:
+ from .pt_experiments import n2_pt_tempo_heat, n3_pt_tempo_dynamics
+
+ n2 = n2_pt_tempo_heat()
+ write_result(output / "n2_pt_tempo_heat.json", n2)
+ plot_heat_spectrum(
+ read_result(output / "n2_pt_tempo_heat.json"), figures / "n2_pt_tempo_heat"
+ )
+ n3 = n3_pt_tempo_dynamics()
+ write_result(output / "n3_pt_tempo_dynamics.json", n3)
+ plot_n3_pt_dynamics(
+ read_result(output / "n3_pt_tempo_dynamics.json"),
+ figures / "n3_pt_tempo_dynamics",
+ )
+ return 0
+
+
+def generate_n3_paper_grid(
+ output: Path,
+ cache: Path,
+ figures: Path,
+ exact_backend: ExactBackend = "uniform_tempo",
+) -> int:
+ from .paper_extension import run_n3_heat_grid
+
+ manifest = run_n3_heat_grid(output, cache, exact_backend=exact_backend)
+ plot_n3_sector_heat(manifest, figures / "n3_sector_heat")
+ plot_odd_sector_difference(manifest, figures / "n3_odd_difference")
+ plot_dark_diagnostics(manifest, figures / "dark_diagnostics")
+ return 0 if manifest["converged"] else 1
+
+
+def generate_error_map(
+ output: Path,
+ cache: Path,
+ figures: Path,
+ exact_backend: ExactBackend = "uniform_tempo",
+) -> int:
+ from .paper_extension import run_error_grid
+
+ manifest = run_error_grid(output, cache, exact_backend=exact_backend)
+ plot_error_maps(manifest, figures / "error_maps")
+ return 0
+
+
+def generate_n3_error_map(
+ exact_manifest: Path,
+ output: Path,
+ figures: Path,
+) -> int:
+ from .paper_extension import run_n3_error_map
+
+ manifest = run_n3_error_map(exact_manifest, output)
+ plot_n3_error_maps(manifest, figures / "n3_error_maps")
+ return 0 if manifest["converged"] else 1
+
+
+def generate_n4_pilot(
+ output: Path,
+ cache: Path,
+ figures: Path,
+ sector: Literal["even", "odd"],
+ j: float,
+) -> int:
+ from .paper_extension import run_n4_pilot
+
+ result = run_n4_pilot(output, cache, sector=sector, j=j)
+ if result["converged"]:
+ j_label = f"{j:.2f}".replace(".", "p")
+ plot_n4_pilot_comparison(
+ result,
+ figures / f"n4_{sector}_j{j_label}_comparison",
+ )
+ return 0 if result["converged"] else 1
+
+
+def generate_model_comparison(
+ output: Path,
+ cache: Path,
+ figures: Path,
+ exact_backend: ExactBackend = "uniform_tempo",
+ full_kac: bool = False,
+) -> int:
+ from .paper_extension import run_model_comparison
+
+ manifest = run_model_comparison(
+ output,
+ cache,
+ exact_backend=exact_backend,
+ full_kac=full_kac,
+ )
+ plot_model_variants(manifest, figures / "model_variants")
+ return 0 if manifest.get("locally_complete", manifest["converged"]) else 1
+
+
+def paper_audit(directory: Path) -> int:
+ from .paper_extension import audit_paper_results
+
+ passed, failures = audit_paper_results(directory)
+ if not passed:
+ for failure in failures:
+ print(f"FAIL: {failure}")
+ return 1
+ print("PASS: paper extension manifests and convergence evidence are complete")
+ return 0
+
+
+def generate_heat_valve(
+ output: Path,
+ cache: Path,
+ figures: Path,
+ *,
+ full: bool,
+) -> int:
+ from .convergence import ConvergenceCache, atomic_write_result
+ from .heat_valve import (
+ HeatValvePoint,
+ ValveNumerics,
+ build_heat_valve_manifest,
+ isolated_valve_scan,
+ run_uniform_valve_point,
+ )
+ from .heat_valve_audit import audit_heat_valve_manifest
+
+ floquet_steps = 360 if full else 240
+ xi_values = np.linspace(1.8, 4.0, 45)
+ isolated = isolated_valve_scan(
+ HeatValvePoint(
+ n=n,
+ xi=float(xi),
+ drive_frequency=3.0,
+ floquet_steps=floquet_steps,
+ )
+ for n in (1, 2, 3)
+ for xi in xi_values
+ )
+ atomic_write_result(output / "isolated_scan.json", isolated)
+ selection = build_heat_valve_manifest(isolated)
+ selected = [
+ HeatValvePoint(
+ n=int(item["n"]), # type: ignore[arg-type]
+ xi=float(item["xi"]),
+ j=float(item["j"]),
+ omega=float(item["omega"]),
+ drive_frequency=float(item["drive_frequency"]),
+ alpha=float(item["alpha"]),
+ cutoff=float(item["cutoff"]),
+ temperature=float(item["temperature"]),
+ floquet_steps=int(item["floquet_steps"]),
+ )
+ for item in selection["selected_points"]
+ if full or int(item["n"]) == 3
+ ]
+ numerical_controls = ValveNumerics()
+ result_cache = ConvergenceCache(cache)
+ results = []
+ for point in selected:
+ result = run_uniform_valve_point(
+ point,
+ numerical_controls,
+ result_cache,
+ )
+ results.append(result)
+ atomic_write_result(
+ output / f"n{point.n}_xi{point.xi:.2f}.json",
+ result,
+ )
+ manifest = build_heat_valve_manifest(isolated, results)
+ audit = audit_heat_valve_manifest(manifest)
+ manifest["audit"] = asdict(audit)
+ atomic_write_result(output / "heat_valve_manifest.json", manifest)
+ plot_heat_valve_hero(manifest, figures / "heat_valve_hero")
+ requested = 9 if full else 3
+ return 0 if len(results) == requested and all(
+ bool(item.get("converged", False)) for item in results
+ ) else 1
+
+
+def heat_valve_audit(directory: Path) -> int:
+ from .heat_valve_audit import audit_heat_valve_manifest
+
+ path = directory / "heat_valve_manifest.json"
+ if not path.is_file():
+ print(f"FAIL: missing {path}")
+ return 1
+ try:
+ manifest = json.loads(path.read_text(encoding="utf-8"))
+ audit = audit_heat_valve_manifest(manifest)
+ except (OSError, json.JSONDecodeError, ValueError, KeyError, TypeError) as exc:
+ print(f"FAIL: malformed heat-valve manifest: {exc}")
+ return 1
+ if not audit.dark_channel_passed:
+ for failure in audit.failures:
+ print(f"FAIL: {failure}")
+ return 1
+ print("PASS: pole-resolved Floquet dark-channel gates are complete")
+ return 0
+
+
+def build_parser() -> argparse.ArgumentParser:
+ parser = argparse.ArgumentParser(prog="floquet-if")
+ subparsers = parser.add_subparsers(dest="command", required=True)
+ baseline = subparsers.add_parser("baselines")
+ baseline.add_argument("--output", type=Path, default=Path("results"))
+ baseline.add_argument("--figures", type=Path, default=Path("figures"))
+ baseline.add_argument("--quick", action="store_true")
+ pt_baseline = subparsers.add_parser("pt-baselines")
+ pt_baseline.add_argument("--output", type=Path, default=Path("results"))
+ pt_baseline.add_argument("--figures", type=Path, default=Path("figures"))
+ audit = subparsers.add_parser("audit")
+ audit.add_argument("directory", type=Path)
+ audit.add_argument("--allow-unconverged", action="store_true")
+ for command in ("n3-heat-grid", "error-map", "model-comparison"):
+ paper = subparsers.add_parser(command)
+ paper.add_argument("--output", type=Path, default=Path("results/paper"))
+ paper.add_argument("--cache", type=Path, default=Path("results/cache"))
+ paper.add_argument("--figures", type=Path, default=Path("figures/paper"))
+ paper.add_argument(
+ "--exact-backend",
+ choices=("uniform_tempo", "oqupy"),
+ default="uniform_tempo",
+ )
+ if command == "model-comparison":
+ paper.add_argument(
+ "--full-kac",
+ action="store_true",
+ help="run cluster-scale timestep and phase refinement for Kac variants",
+ )
+ n3_error = subparsers.add_parser("n3-error-map")
+ n3_error.add_argument(
+ "--exact-manifest",
+ type=Path,
+ default=Path("results/paper/n3_heat_manifest.json"),
+ )
+ n3_error.add_argument("--output", type=Path, default=Path("results/paper"))
+ n3_error.add_argument("--figures", type=Path, default=Path("figures/paper"))
+ n4_pilot = subparsers.add_parser("n4-pilot")
+ n4_pilot.add_argument("--output", type=Path, default=Path("results/paper"))
+ n4_pilot.add_argument(
+ "--cache",
+ type=Path,
+ default=Path("results/cache/n4_uniform_tempo"),
+ )
+ n4_pilot.add_argument("--figures", type=Path, default=Path("figures/paper"))
+ n4_pilot.add_argument("--sector", choices=("even", "odd"), default="odd")
+ n4_pilot.add_argument("--j", type=float, default=0.25)
+ paper_check = subparsers.add_parser("paper-audit")
+ paper_check.add_argument("directory", type=Path, default=Path("results/paper"))
+ heat_valve = subparsers.add_parser("heat-valve")
+ heat_valve.add_argument(
+ "--output",
+ type=Path,
+ default=Path("results/heat-valve"),
+ )
+ heat_valve.add_argument(
+ "--cache",
+ type=Path,
+ default=Path("results/cache/uniform_tempo"),
+ )
+ heat_valve.add_argument(
+ "--figures",
+ type=Path,
+ default=Path("figures/heat-valve"),
+ )
+ mode = heat_valve.add_mutually_exclusive_group()
+ mode.add_argument("--pilot", action="store_true")
+ mode.add_argument("--full", action="store_true")
+ heat_check = subparsers.add_parser("heat-valve-audit")
+ heat_check.add_argument("directory", type=Path)
+ return parser
+
+
+def main(argv: list[str] | None = None) -> int:
+ arguments = build_parser().parse_args(argv)
+ if arguments.command == "baselines":
+ return generate_baselines(arguments.output, arguments.figures, arguments.quick)
+ if arguments.command == "audit":
+ return audit_results(arguments.directory, arguments.allow_unconverged)
+ if arguments.command == "pt-baselines":
+ return generate_pt_baselines(arguments.output, arguments.figures)
+ if arguments.command == "n3-heat-grid":
+ return generate_n3_paper_grid(
+ arguments.output,
+ arguments.cache,
+ arguments.figures,
+ arguments.exact_backend,
+ )
+ if arguments.command == "error-map":
+ return generate_error_map(
+ arguments.output,
+ arguments.cache,
+ arguments.figures,
+ arguments.exact_backend,
+ )
+ if arguments.command == "n3-error-map":
+ return generate_n3_error_map(
+ arguments.exact_manifest,
+ arguments.output,
+ arguments.figures,
+ )
+ if arguments.command == "n4-pilot":
+ return generate_n4_pilot(
+ arguments.output,
+ arguments.cache,
+ arguments.figures,
+ arguments.sector,
+ arguments.j,
+ )
+ if arguments.command == "model-comparison":
+ return generate_model_comparison(
+ arguments.output,
+ arguments.cache,
+ arguments.figures,
+ arguments.exact_backend,
+ arguments.full_kac,
+ )
+ if arguments.command == "paper-audit":
+ return paper_audit(arguments.directory)
+ if arguments.command == "heat-valve":
+ return generate_heat_valve(
+ arguments.output,
+ arguments.cache,
+ arguments.figures,
+ full=arguments.full,
+ )
+ if arguments.command == "heat-valve-audit":
+ return heat_valve_audit(arguments.directory)
+ return 2
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/config.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/config.py
new file mode 100644
index 000000000..7f0fd0690
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/config.py
@@ -0,0 +1,131 @@
+"""Validated scientific and numerical configuration."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass, field
+from pathlib import Path
+from typing import Any, Literal
+
+import yaml
+
+Normalization = Literal["bounded", "kac", "collective"]
+DriveNormalization = Literal["coupling", "per_spin"]
+
+
+@dataclass(frozen=True)
+class ModelConfig:
+ n: int = 2
+ j: float = 0.5
+ omega: float = 1.0
+ drive_amplitude: float = 0.3
+ drive_frequency: float = 1.0
+ normalization: Normalization = "bounded"
+ drive_normalization: DriveNormalization = "coupling"
+ counterterm: bool = False
+ counterterm_strength: float = 0.0
+
+ def __post_init__(self) -> None:
+ if self.n not in (1, 2, 3, 4):
+ raise ValueError("n must be one of 1, 2, 3, 4")
+ if self.j < 0:
+ raise ValueError("j must be nonnegative")
+ if self.omega <= 0:
+ raise ValueError("omega must be positive")
+ if self.drive_amplitude < 0:
+ raise ValueError("drive_amplitude must be nonnegative")
+ if self.drive_frequency <= 0:
+ raise ValueError("drive_frequency must be positive")
+ if isinstance(self.counterterm_strength, bool) or self.counterterm_strength < 0:
+ raise ValueError("counterterm_strength must be a nonnegative coefficient")
+ if self.counterterm and self.counterterm_strength <= 0:
+ raise ValueError(
+ "counterterm=True requires a positive counterterm_strength"
+ )
+ if self.normalization not in ("bounded", "kac", "collective"):
+ raise ValueError("unknown normalization")
+ if self.drive_normalization not in ("coupling", "per_spin"):
+ raise ValueError("unknown drive normalization")
+
+ @property
+ def eta(self) -> float:
+ if self.normalization == "bounded":
+ return 1.0 / self.n
+ if self.normalization == "kac":
+ return float(1.0 / self.n**0.5)
+ return 1.0
+
+ @property
+ def drive_eta(self) -> float:
+ if self.drive_normalization == "coupling":
+ return self.eta
+ return 1.0
+
+ @property
+ def period(self) -> float:
+ import math
+
+ return 2 * math.pi / self.drive_frequency
+
+
+@dataclass(frozen=True)
+class BathConfig:
+ alpha: float = 0.05
+ cutoff: float = 2.5
+ temperature: float = 0.0
+
+ def __post_init__(self) -> None:
+ if self.alpha < 0:
+ raise ValueError("alpha must be nonnegative")
+ if self.cutoff <= 0:
+ raise ValueError("cutoff must be positive")
+ if self.temperature < 0:
+ raise ValueError("temperature must be nonnegative")
+
+
+@dataclass(frozen=True)
+class NumericsConfig:
+ drive_steps: int = 240
+ memory_steps: int = 4
+ periods: int = 80
+ correlation_periods: int = 20
+ harmonic_cutoff: int = 6
+ convergence_tolerance: float = 1e-3
+
+ def __post_init__(self) -> None:
+ if self.drive_steps < 8:
+ raise ValueError("drive_steps must be at least 8")
+ if self.memory_steps < 1:
+ raise ValueError("memory_steps must be positive")
+ if self.periods < 1 or self.correlation_periods < 1:
+ raise ValueError("period counts must be positive")
+ if self.harmonic_cutoff < 0:
+ raise ValueError("harmonic_cutoff must be nonnegative")
+ if self.convergence_tolerance <= 0:
+ raise ValueError("convergence_tolerance must be positive")
+
+
+@dataclass(frozen=True)
+class RunConfig:
+ model: ModelConfig = field(default_factory=ModelConfig)
+ bath: BathConfig = field(default_factory=BathConfig)
+ numerics: NumericsConfig = field(default_factory=NumericsConfig)
+ sector: Literal["full", "triplet", "singlet", "even", "odd"] = "full"
+ method: Literal["closed", "floquet_markov", "finite_memory_if"] = "closed"
+
+
+def _section(cls: type[Any], data: dict[str, Any], key: str) -> Any:
+ return cls(**data.get(key, {}))
+
+
+def load_config(path: Path) -> RunConfig:
+ """Load a validated run configuration from YAML."""
+ data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
+ if not isinstance(data, dict):
+ raise ValueError("configuration root must be a mapping")
+ return RunConfig(
+ model=_section(ModelConfig, data, "model"),
+ bath=_section(BathConfig, data, "bath"),
+ numerics=_section(NumericsConfig, data, "numerics"),
+ sector=data.get("sector", "full"),
+ method=data.get("method", "closed"),
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/convergence.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/convergence.py
new file mode 100644
index 000000000..31afeef96
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/convergence.py
@@ -0,0 +1,125 @@
+"""Content-addressed caching and numerical convergence metrics."""
+
+from __future__ import annotations
+
+import hashlib
+import json
+import os
+import tempfile
+from collections.abc import Mapping
+from dataclasses import asdict, dataclass
+from pathlib import Path
+from typing import Any, cast
+
+import numpy as np
+from numpy.typing import NDArray
+from scipy.integrate import trapezoid
+
+
+@dataclass(frozen=True)
+class ConvergencePoint:
+ """Complete numerical controls for one backend evaluation."""
+
+ model: Mapping[str, Any]
+ bath: Mapping[str, Any]
+ sector: str
+ steps_per_period: int
+ periods: int
+ delay_periods: int
+ memory_steps: int
+ epsrel: float
+
+
+@dataclass(frozen=True)
+class ConvergenceThresholds:
+ state: float = 5e-2
+ correlation: float = 5e-2
+ heat: float = 5e-2
+ phase: float = 1e-3
+ trace: float = 5e-3
+
+
+def fingerprint(point: Mapping[str, Any] | ConvergencePoint, commit: str) -> str:
+ """Return a stable SHA-256 key for a point and source revision."""
+ payload: Any = asdict(point) if isinstance(point, ConvergencePoint) else point
+ encoded = json.dumps(
+ {"commit": commit, "point": payload},
+ sort_keys=True,
+ separators=(",", ":"),
+ default=str,
+ ).encode()
+ return hashlib.sha256(encoded).hexdigest()
+
+
+def atomic_write_result(path: Path, payload: Mapping[str, Any]) -> None:
+ """Atomically replace a JSON cache entry in its destination directory."""
+ path.parent.mkdir(parents=True, exist_ok=True)
+ descriptor, temporary_name = tempfile.mkstemp(
+ dir=path.parent, prefix=f".{path.name}.", suffix=".tmp"
+ )
+ temporary = Path(temporary_name)
+ try:
+ with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
+ json.dump(payload, handle, indent=2, sort_keys=True, default=str)
+ handle.flush()
+ os.fsync(handle.fileno())
+ os.replace(temporary, path)
+ finally:
+ temporary.unlink(missing_ok=True)
+
+
+def state_residual(
+ candidate: NDArray[np.complex128], reference: NDArray[np.complex128]
+) -> float:
+ if candidate.shape != reference.shape:
+ raise ValueError("state shapes do not match")
+ return float(np.linalg.norm(candidate - reference))
+
+
+def curve_residual(
+ candidate_grid: NDArray[np.float64],
+ candidate: NDArray[np.complex128] | NDArray[np.float64],
+ reference_grid: NDArray[np.float64],
+ reference: NDArray[np.complex128] | NDArray[np.float64],
+) -> float:
+ """Normalized L1 residual on an identical one-dimensional grid."""
+ if (
+ candidate_grid.shape != reference_grid.shape
+ or candidate.shape != reference.shape
+ or candidate.shape != candidate_grid.shape
+ or not np.allclose(candidate_grid, reference_grid, atol=1e-12, rtol=1e-12)
+ ):
+ raise ValueError("curve grids or values do not match")
+ numerator = float(trapezoid(abs(candidate - reference), reference_grid))
+ denominator = float(trapezoid(abs(reference), reference_grid)) + 1e-15
+ return numerator / denominator
+
+
+class ConvergenceCache:
+ """Small JSON cache whose entries are complete only after atomic rename."""
+
+ def __init__(self, directory: Path):
+ self.directory = directory
+
+ def path_for(self, key: str) -> Path:
+ if len(key) != 64 or any(character not in "0123456789abcdef" for character in key):
+ raise ValueError("cache key must be a lowercase SHA-256 digest")
+ return self.directory / f"{key}.json"
+
+ def contains(self, key: str) -> bool:
+ return self.path_for(key).is_file()
+
+ def load(self, key: str) -> dict[str, Any]:
+ path = self.path_for(key)
+ value = json.loads(path.read_text(encoding="utf-8"))
+ if value.get("fingerprint") != key or value.get("complete") is not True:
+ raise ValueError(f"invalid or incomplete cache entry {path}")
+ return cast(dict[str, Any], value)
+
+ def store(self, key: str, payload: Mapping[str, Any]) -> Path:
+ path = self.path_for(key)
+ atomic_write_result(
+ path,
+ {"fingerprint": key, "complete": True, **dict(payload)},
+ )
+ return path
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/correlations.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/correlations.py
new file mode 100644
index 000000000..9730186c5
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/correlations.py
@@ -0,0 +1,143 @@
+"""Period-averaged correlations and coherent-harmonic decomposition."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+import numpy as np
+from numpy.typing import NDArray
+
+from .operators import ComplexMatrix
+
+
+@dataclass(frozen=True)
+class DeltaCorrelationPeak:
+ harmonic: int
+ frequency: float
+ correlation_weight: float
+
+
+@dataclass(frozen=True)
+class CorrelationResult:
+ delays: NDArray[np.float64]
+ total: NDArray[np.complex128]
+ connected: NDArray[np.complex128]
+ coherent: NDArray[np.float64]
+ delta_peaks: tuple[DeltaCorrelationPeak, ...]
+ method: str
+ metadata: dict[str, float | str]
+
+
+def coherent_decomposition(
+ one_point: NDArray[np.float64],
+ drive_frequency: float,
+ delays: NDArray[np.float64],
+ threshold: float = 1e-12,
+) -> tuple[NDArray[np.float64], tuple[DeltaCorrelationPeak, ...]]:
+ """Compute period-averaged factorized correlation from one micromotion period."""
+ if one_point.ndim != 1 or len(one_point) < 2:
+ raise ValueError("one_point must contain one sampled drive period")
+ coefficients = np.fft.fft(one_point) / len(one_point)
+ coherent = np.full_like(delays, abs(coefficients[0]) ** 2, dtype=np.float64)
+ peaks: list[DeltaCorrelationPeak] = []
+ if abs(coefficients[0]) ** 2 >= threshold:
+ peaks.append(DeltaCorrelationPeak(0, 0.0, float(abs(coefficients[0]) ** 2)))
+ maximum = len(one_point) // 2
+ for harmonic in range(1, maximum + 1):
+ weight = float(2 * abs(coefficients[harmonic]) ** 2)
+ if weight >= threshold:
+ frequency = harmonic * drive_frequency
+ coherent += weight * np.cos(frequency * delays)
+ peaks.append(DeltaCorrelationPeak(harmonic, frequency, weight))
+ return coherent, tuple(peaks)
+
+
+def unitary_period_correlation(
+ step_propagators: tuple[ComplexMatrix, ...],
+ phase_densities: NDArray[np.complex128],
+ operator: ComplexMatrix,
+ dt: float,
+ delay_steps: int,
+ drive_frequency: float,
+ method: str = "closed_unitary",
+) -> CorrelationResult:
+ """Compute Cbar(tau) by exact finite-system operator insertions.
+
+ This routine is valid for closed dynamics. Using open-system reduced
+ propagators would constitute a quantum-regression approximation and must
+ carry a different method label.
+ """
+ period_steps = len(step_propagators)
+ if phase_densities.shape[0] != period_steps:
+ raise ValueError("one phase density is required per step in a period")
+ total = np.zeros(delay_steps + 1, dtype=np.complex128)
+ one_point = np.real(
+ np.einsum("ij,tji->t", operator, phase_densities, optimize=True)
+ )
+ for phase in range(period_steps):
+ inserted = operator @ phase_densities[phase]
+ propagation = np.eye(operator.shape[0], dtype=np.complex128)
+ total[0] += np.trace(operator @ inserted)
+ for delay in range(1, delay_steps + 1):
+ piece = step_propagators[(phase + delay - 1) % period_steps]
+ propagation = piece @ propagation
+ evolved = propagation @ inserted @ propagation.conj().T
+ total[delay] += np.trace(operator @ evolved)
+ total /= period_steps
+ delays = np.arange(delay_steps + 1, dtype=np.float64) * dt
+ coherent, peaks = coherent_decomposition(one_point, drive_frequency, delays)
+ return CorrelationResult(
+ delays,
+ total,
+ total - coherent,
+ coherent,
+ peaks,
+ method,
+ {"period_steps": float(period_steps), "dt": dt},
+ )
+
+
+def superoperator_period_correlation(
+ step_maps: NDArray[np.complex128],
+ phase_densities: NDArray[np.complex128],
+ operator: ComplexMatrix,
+ dt: float,
+ delay_steps: int,
+ drive_frequency: float,
+ method: str = "floquet_markov_qr",
+) -> CorrelationResult:
+ """Two-time correlation using a periodic Markovian dynamical map.
+
+ This is the quantum regression theorem and is only used for the explicitly
+ labeled Markovian backend.
+ """
+ period_steps = len(step_maps)
+ if phase_densities.shape[0] != period_steps:
+ raise ValueError("one phase density is required per step in a period")
+ dimension = operator.shape[0]
+ total = np.zeros(delay_steps + 1, dtype=np.complex128)
+ one_point = np.real(
+ np.einsum("ij,tji->t", operator, phase_densities, optimize=True)
+ )
+ measurement = operator.T.reshape(dimension**2, order="F")
+ for phase in range(period_steps):
+ inserted = (operator @ phase_densities[phase]).reshape(
+ dimension**2, order="F"
+ )
+ vector = inserted
+ total[0] += measurement @ vector
+ for delay in range(1, delay_steps + 1):
+ vector = step_maps[(phase + delay - 1) % period_steps] @ vector
+ total[delay] += measurement @ vector
+ total /= period_steps
+ delays = np.arange(delay_steps + 1, dtype=np.float64) * dt
+ coherent, peaks = coherent_decomposition(one_point, drive_frequency, delays)
+ return CorrelationResult(
+ delays,
+ total,
+ total - coherent,
+ coherent,
+ peaks,
+ method,
+ {"period_steps": float(period_steps), "dt": dt},
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/dark_channels.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/dark_channels.py
new file mode 100644
index 000000000..af99a667c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/dark_channels.py
@@ -0,0 +1,128 @@
+"""Harmonic-resolved Floquet transition and dark-channel diagnostics."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+import numpy as np
+from numpy.typing import NDArray
+
+from .floquet import FloquetSolution, micromotion
+from .operators import ComplexMatrix
+
+
+@dataclass(frozen=True)
+class FloquetTransition:
+ source: int
+ target: int
+ harmonic: int
+ emitted_frequency: float
+ amplitude: complex
+ weight: float
+
+
+@dataclass(frozen=True)
+class DarkCandidate:
+ transition: FloquetTransition
+ relative_weight: float
+
+
+def periodic_modes(solution: FloquetSolution) -> NDArray[np.complex128]:
+ cumulative = micromotion(solution)[:-1]
+ dt = solution.period / len(cumulative)
+ values = []
+ for index, propagator in enumerate(cumulative):
+ time = index * dt
+ values.append(
+ propagator
+ @ solution.modes
+ @ np.diag(np.exp(1j * solution.quasienergies * time))
+ )
+ return np.asarray(values)
+
+
+def floquet_matrix_elements(
+ solution: FloquetSolution,
+ operator: ComplexMatrix,
+ harmonic_cutoff: int,
+ threshold: float = 0.0,
+) -> tuple[FloquetTransition, ...]:
+ """Return S_ab^(m) under the project's Fourier convention."""
+ if harmonic_cutoff < 0:
+ raise ValueError("harmonic_cutoff must be nonnegative")
+ modes = periodic_modes(solution)
+ samples = len(modes)
+ omega_d = 2 * np.pi / solution.period
+ instantaneous = np.einsum(
+ "tai,ab,tbj->tij", modes.conj(), operator, modes, optimize=True
+ )
+ records: list[FloquetTransition] = []
+ for harmonic in range(-harmonic_cutoff, harmonic_cutoff + 1):
+ phase = np.exp(-1j * harmonic * omega_d * np.arange(samples) * solution.period / samples)
+ fourier = np.einsum("t,tij->ij", phase, instantaneous) / samples
+ for target in range(fourier.shape[0]):
+ for source in range(fourier.shape[1]):
+ amplitude = complex(fourier[target, source])
+ weight = float(abs(amplitude) ** 2)
+ if weight >= threshold:
+ records.append(
+ FloquetTransition(
+ source=source,
+ target=target,
+ harmonic=harmonic,
+ emitted_frequency=float(
+ solution.quasienergies[source]
+ - solution.quasienergies[target]
+ + harmonic * omega_d
+ ),
+ amplitude=amplitude,
+ weight=weight,
+ )
+ )
+ return tuple(records)
+
+
+def harmonic_sum_rule(
+ solution: FloquetSolution,
+ operator: ComplexMatrix,
+ harmonic_cutoff: int,
+) -> float:
+ """Return maximum relative Parseval residual over mode pairs."""
+ modes = periodic_modes(solution)
+ instantaneous = np.einsum(
+ "tai,ab,tbj->tij", modes.conj(), operator, modes, optimize=True
+ )
+ direct = np.mean(abs(instantaneous) ** 2, axis=0)
+ records = floquet_matrix_elements(solution, operator, harmonic_cutoff)
+ summed = np.zeros_like(direct, dtype=float)
+ for record in records:
+ summed[record.target, record.source] += record.weight
+ return float(np.max(abs(summed - direct) / (direct + 1e-15)))
+
+
+def period_variance(
+ phase_densities: NDArray[np.complex128], operator: ComplexMatrix
+) -> float:
+ first = np.einsum("ij,tji->t", operator, phase_densities, optimize=True)
+ second = np.einsum(
+ "ij,tji->t", operator @ operator, phase_densities, optimize=True
+ )
+ return float(np.real(np.mean(second - first * first)))
+
+
+def dark_candidates(
+ transitions: tuple[FloquetTransition, ...],
+ relative_threshold: float = 1e-4,
+) -> tuple[DarkCandidate, ...]:
+ if not 0 <= relative_threshold <= 1:
+ raise ValueError("relative_threshold must lie in [0, 1]")
+ if not transitions:
+ return ()
+ maximum = max(record.weight for record in transitions)
+ if maximum == 0:
+ return tuple(DarkCandidate(record, 0.0) for record in transitions)
+ return tuple(
+ DarkCandidate(record, record.weight / maximum)
+ for record in transitions
+ if record.weight / maximum <= relative_threshold
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/error_map.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/error_map.py
new file mode 100644
index 000000000..65edebe7d
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/error_map.py
@@ -0,0 +1,152 @@
+"""Exact PT-TEMPO versus Floquet-Markov comparison metrics and audits."""
+
+from __future__ import annotations
+
+from dataclasses import asdict, dataclass
+from typing import Any, cast
+
+import numpy as np
+from numpy.typing import NDArray
+
+from .convergence import curve_residual
+
+
+@dataclass(frozen=True)
+class ErrorMetrics:
+ trace_distance: float
+ correlation: float
+ heat: float
+
+
+def trace_distance(
+ first: NDArray[np.complex128], second: NDArray[np.complex128]
+) -> float:
+ if first.shape != second.shape or first.ndim != 2 or first.shape[0] != first.shape[1]:
+ raise ValueError("density matrices must have the same square shape")
+ difference = (first - second + (first - second).conj().T) / 2
+ return float(0.5 * np.sum(abs(np.linalg.eigvalsh(difference))))
+
+
+def correlation_error(
+ exact_grid: NDArray[np.float64],
+ exact: NDArray[np.complex128],
+ markov_grid: NDArray[np.float64],
+ markov: NDArray[np.complex128],
+) -> float:
+ return curve_residual(markov_grid, markov, exact_grid, exact)
+
+
+def heat_error(
+ exact_grid: NDArray[np.float64],
+ exact: NDArray[np.float64],
+ markov_grid: NDArray[np.float64],
+ markov: NDArray[np.float64],
+) -> float:
+ return curve_residual(markov_grid, markov, exact_grid, exact)
+
+
+def _complex_array(value: dict[str, Any]) -> NDArray[np.complex128]:
+ return cast(
+ NDArray[np.complex128],
+ np.asarray(value["real"], dtype=float)
+ + 1j * np.asarray(value["imag"], dtype=float),
+ )
+
+
+def build_error_record(
+ exact: dict[str, Any], markov: dict[str, Any]
+) -> dict[str, Any]:
+ """Build a comparison only after checking scientific compatibility."""
+ if not bool(exact.get("converged")):
+ raise ValueError("exact PT-TEMPO input must be converged")
+ exact_method = str(exact.get("method", ""))
+ if exact_method not in {
+ "pt_tempo_multitime",
+ "uniform_tempo_floquet_multitime",
+ }:
+ raise ValueError("exact input must use an approved process-tensor method")
+ if exact.get("model_hash") != markov.get("model_hash"):
+ raise ValueError("model_hash mismatch")
+ exact_normalization = exact.get("model", {}).get("normalization")
+ markov_normalization = markov.get("model", {}).get("normalization")
+ if exact_normalization != markov_normalization:
+ raise ValueError("normalization mismatch")
+ exact_frequency = np.asarray(exact["frequency"], dtype=float)
+ markov_frequency = np.asarray(markov["frequency"], dtype=float)
+ if (
+ exact_frequency.shape != markov_frequency.shape
+ or not np.allclose(exact_frequency, markov_frequency)
+ ):
+ raise ValueError("frequency grid mismatch")
+ exact_delay = np.asarray(exact["correlation"]["delay"], dtype=float)
+ markov_delay = np.asarray(markov["correlation"]["delay"], dtype=float)
+ if exact_delay.shape != markov_delay.shape or not np.allclose(
+ exact_delay, markov_delay
+ ):
+ raise ValueError("correlation grid mismatch")
+ metrics = ErrorMetrics(
+ trace_distance(
+ _complex_array(exact["phase_state"]),
+ _complex_array(markov["phase_state"]),
+ ),
+ correlation_error(
+ exact_delay,
+ _complex_array(exact["correlation"]["connected"]),
+ markov_delay,
+ _complex_array(markov["correlation"]["connected"]),
+ ),
+ heat_error(
+ exact_frequency,
+ np.asarray(exact["continuous"], dtype=float),
+ markov_frequency,
+ np.asarray(markov["continuous"], dtype=float),
+ ),
+ )
+ return {
+ "status": "converged",
+ "model_hash": exact["model_hash"],
+ "exact_method": exact["method"],
+ "markov_method": markov["method"],
+ "metrics": asdict(metrics),
+ "convergence_evidence": exact.get("evidence", []),
+ }
+
+
+def audit_grid_manifest(
+ manifest: dict[str, Any],
+ alphas: tuple[float, ...] = (0.025, 0.05, 0.1),
+ drive_ratios: tuple[float, ...] = (0.75, 1.0, 1.25),
+) -> dict[str, Any]:
+ """Require each requested cell to be converged or explicitly masked."""
+ expected = {(float(alpha), float(ratio)) for alpha in alphas for ratio in drive_ratios}
+ points = manifest.get("points")
+ if not isinstance(points, list):
+ raise ValueError("manifest points must be a list")
+ observed: dict[tuple[float, float], dict[str, Any]] = {}
+ for point in points:
+ key = (float(point["alpha"]), float(point["drive_ratio"]))
+ if key in observed:
+ raise ValueError(f"duplicate grid point {key}")
+ observed[key] = point
+ if set(observed) != expected:
+ missing = sorted(expected - set(observed))
+ extra = sorted(set(observed) - expected)
+ raise ValueError(f"grid mismatch; missing={missing}, extra={extra}")
+ masked = 0
+ for key, point in observed.items():
+ status = point.get("status")
+ if status == "converged":
+ if not isinstance(point.get("metrics"), dict):
+ raise ValueError(f"converged point {key} lacks metrics")
+ elif status == "resource_ceiling":
+ if point.get("metrics") is not None:
+ raise ValueError(f"masked point {key} must not fabricate metrics")
+ masked += 1
+ else:
+ raise ValueError(f"invalid status for point {key}: {status}")
+ return {
+ "complete": True,
+ "requested_points": len(expected),
+ "converged_points": len(expected) - masked,
+ "masked_points": masked,
+ }
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/experiments.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/experiments.py
new file mode 100644
index 000000000..cec12d945
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/experiments.py
@@ -0,0 +1,273 @@
+"""Reproducible baseline experiments used by the report."""
+
+from __future__ import annotations
+
+from dataclasses import asdict
+
+import numpy as np
+
+from .backends.finite_memory import FiniteMemoryBackend
+from .backends.floquet_markov import FloquetMarkovBackend
+from .config import BathConfig, ModelConfig, Normalization
+from .correlations import superoperator_period_correlation
+from .heat_current import heat_current_spectrum
+from .models import coupling_operator, ising_hamiltonian
+from .spectra import diagonalize, transitions
+from .symmetry import n2_sectors, n3_reflection_sectors, project
+
+
+def n2_bright_sweep(
+ j_values: np.ndarray,
+ omega: float = 1.0,
+ normalization: Normalization = "bounded",
+) -> dict[str, object]:
+ _, triplet = n2_sectors()
+ records = []
+ maximum_residual = 0.0
+ for j in j_values:
+ cfg = ModelConfig(n=2, j=float(j), omega=omega, normalization=normalization)
+ h = project(ising_hamiltonian(cfg), triplet)
+ s = project(coupling_operator(cfg), triplet)
+ spectrum = diagonalize(h)
+ items = transitions(spectrum, spectrum, s, threshold=1e-10)
+ low = next(item for item in items if item.source == 0 and item.frequency > 0)
+ high = next(item for item in items if item.source == 1 and item.target == 2)
+ energy = float(np.sqrt(j**2 + omega**2))
+ analytic = {
+ "gap_low": energy - float(j),
+ "gap_high": energy + float(j),
+ "weight_low": 2 * cfg.eta**2 * (1 + float(j) / energy),
+ "weight_high": 2 * cfg.eta**2 * (1 - float(j) / energy),
+ }
+ numerical = {
+ "gap_low": low.frequency,
+ "gap_high": high.frequency,
+ "weight_low": low.weight,
+ "weight_high": high.weight,
+ }
+ maximum_residual = max(
+ maximum_residual,
+ max(abs(numerical[key] - analytic[key]) for key in analytic),
+ )
+ records.append(
+ {
+ "j": float(j),
+ **numerical,
+ **{f"analytic_{key}": value for key, value in analytic.items()},
+ }
+ )
+ return {
+ "method": "exact_diagonalization",
+ "converged": maximum_residual < 1e-10,
+ "diagnostics": {"maximum_analytic_residual": maximum_residual},
+ "data": records,
+ }
+
+
+def n3_sector_sweep(
+ j_values: np.ndarray,
+ omega: float = 1.0,
+ normalization: Normalization = "bounded",
+) -> dict[str, object]:
+ odd, even = n3_reflection_sectors()
+ records = []
+ odd_gap_spread = 0.0
+ odd_gaps = []
+ for j in j_values:
+ cfg = ModelConfig(n=3, j=float(j), omega=omega, normalization=normalization)
+ full_h = ising_hamiltonian(cfg)
+ full_s = coupling_operator(cfg)
+ even_spectrum = diagonalize(project(full_h, even))
+ odd_spectrum = diagonalize(project(full_h, odd))
+ odd_gap = float(odd_spectrum.energies[1] - odd_spectrum.energies[0])
+ odd_gaps.append(odd_gap)
+ even_operator = project(full_s, even)
+ bright = sorted(
+ [
+ item
+ for item in transitions(even_spectrum, even_spectrum, even_operator, 1e-10)
+ if item.source == 0 and item.frequency > 0
+ ],
+ key=lambda item: item.frequency,
+ )
+ primary = bright[0]
+ records.append(
+ {
+ "j": float(j),
+ "odd_gap": odd_gap,
+ "primary_even_gap": primary.frequency,
+ "primary_even_weight": primary.weight,
+ "cat_ratio": (
+ primary.frequency * 4 * float(j) ** 2 / omega**3 if j > 0 else None
+ ),
+ }
+ )
+ odd_gap_spread = float(np.ptp(odd_gaps))
+ return {
+ "method": "exact_diagonalization",
+ "converged": odd_gap_spread < 1e-10,
+ "diagnostics": {"odd_gap_spread": odd_gap_spread},
+ "data": records,
+ }
+
+
+def backend_comparison(
+ alphas: list[float],
+ j: float = 0.5,
+ omega: float = 1.0,
+ drive_amplitude: float = 0.2,
+ steps_per_period: int = 48,
+ periods: int = 100,
+) -> dict[str, object]:
+ """Compare two explicitly approximate backends for the N=2 triplet."""
+ _, triplet = n2_sectors()
+ gap = float(np.sqrt(j**2 + omega**2) - j)
+ cfg = ModelConfig(
+ n=2,
+ j=j,
+ omega=omega,
+ drive_amplitude=drive_amplitude,
+ drive_frequency=gap,
+ )
+ h0 = project(ising_hamiltonian(cfg), triplet)
+ s = project(coupling_operator(cfg), triplet)
+
+ def hamiltonian(time: float) -> np.ndarray:
+ return np.asarray(
+ h0 + cfg.drive_amplitude * np.cos(cfg.drive_frequency * time) * s,
+ dtype=np.complex128,
+ )
+
+ ground = diagonalize(h0).states[:, 0]
+ rho0 = np.outer(ground, ground.conj())
+ dt = cfg.period / steps_per_period
+ records = []
+ for alpha in alphas:
+ bath = BathConfig(alpha=alpha)
+ markov = FloquetMarkovBackend().run(
+ hamiltonian, s, bath, cfg.period, steps_per_period, 4
+ )
+ memory = FiniteMemoryBackend().run(
+ hamiltonian,
+ s,
+ rho0,
+ bath,
+ dt,
+ steps_per_period * periods,
+ 1,
+ )
+ memory_phase_residual = float(
+ np.linalg.norm(
+ memory.density_matrices[-1]
+ - memory.density_matrices[-1 - steps_per_period]
+ )
+ )
+ trace_distance = float(
+ 0.5
+ * np.sum(
+ np.abs(
+ np.linalg.eigvalsh(
+ memory.density_matrices[-1] - markov.density_matrices[0]
+ )
+ )
+ )
+ )
+ records.append(
+ {
+ "alpha": alpha,
+ "trace_distance": trace_distance,
+ "finite_memory_phase_residual": memory_phase_residual,
+ "finite_memory_trace_error": memory.diagnostics["trace_error"],
+ "finite_memory_min_eigenvalue": memory.diagnostics[
+ "minimum_density_eigenvalue"
+ ],
+ "markov_rate_residual": markov.diagnostics["rate_residual"],
+ }
+ )
+ converged = all(
+ record["finite_memory_phase_residual"] < 5e-3
+ and record["finite_memory_min_eigenvalue"] > -1e-5
+ for record in records
+ )
+ return {
+ "method": "finite_memory_if_vs_floquet_markov",
+ "converged": converged,
+ "diagnostics": {
+ "memory_steps": 1,
+ "steps_per_period": steps_per_period,
+ "periods": periods,
+ "warning": (
+ "This is an approximation-to-approximation comparison, "
+ "not an exact Floquet-IF error map."
+ ),
+ },
+ "model": asdict(cfg),
+ "data": records,
+ }
+
+
+def n2_markov_heat_spectrum(
+ j: float = 0.5,
+ omega: float = 1.0,
+ alpha: float = 0.05,
+ drive_amplitude: float = 0.2,
+ steps_per_period: int = 96,
+ correlation_periods: int = 16,
+) -> dict[str, object]:
+ """Generate the explicitly approximate N=2 Floquet-Markov heat spectrum."""
+ _, triplet = n2_sectors()
+ gap = float(np.sqrt(j**2 + omega**2) - j)
+ cfg = ModelConfig(
+ n=2,
+ j=j,
+ omega=omega,
+ drive_amplitude=drive_amplitude,
+ drive_frequency=gap,
+ )
+ h0 = project(ising_hamiltonian(cfg), triplet)
+ coupling = project(coupling_operator(cfg), triplet)
+
+ def hamiltonian(time: float) -> np.ndarray:
+ return np.asarray(
+ h0 + drive_amplitude * np.cos(cfg.drive_frequency * time) * coupling,
+ dtype=np.complex128,
+ )
+
+ bath = BathConfig(alpha=alpha)
+ markov = FloquetMarkovBackend().run(
+ hamiltonian,
+ coupling,
+ bath,
+ cfg.period,
+ steps_per_period,
+ 5,
+ )
+ if markov.step_maps is None:
+ raise RuntimeError("Floquet-Markov backend did not return step maps")
+ correlation = superoperator_period_correlation(
+ markov.step_maps,
+ markov.density_matrices[:-1],
+ coupling,
+ cfg.period / steps_per_period,
+ steps_per_period * correlation_periods,
+ cfg.drive_frequency,
+ )
+ frequencies = np.linspace(0, 3.0, 601)
+ heat = heat_current_spectrum(correlation, bath, frequencies)
+ records = [
+ {"frequency": float(frequency), "continuous": float(value)}
+ for frequency, value in zip(heat.frequencies, heat.continuous, strict=True)
+ ]
+ return {
+ "method": heat.method,
+ "converged": markov.converged,
+ "diagnostics": {
+ **markov.diagnostics,
+ **heat.metadata,
+ "continuous_tail_amplitude": float(abs(correlation.connected[-1])),
+ },
+ "model": asdict(cfg),
+ "bath": asdict(bath),
+ "delta_peaks": [asdict(peak) for peak in heat.delta_peaks],
+ "data": records,
+ }
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/floquet.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/floquet.py
new file mode 100644
index 000000000..092cb152c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/floquet.py
@@ -0,0 +1,79 @@
+"""Direct finite-dimensional Floquet propagation."""
+
+from __future__ import annotations
+
+from collections.abc import Callable
+from dataclasses import dataclass
+
+import numpy as np
+from numpy.typing import NDArray
+from scipy.linalg import expm
+
+from .operators import ComplexMatrix
+
+
+@dataclass(frozen=True)
+class FloquetSolution:
+ propagator: ComplexMatrix
+ quasienergies: NDArray[np.float64]
+ modes: ComplexMatrix
+ period: float
+ step_propagators: tuple[ComplexMatrix, ...]
+ unitarity_residual: float
+ eigen_residual: float
+
+
+def one_period_propagator(
+ hamiltonian: Callable[[float], ComplexMatrix],
+ period: float,
+ steps: int,
+) -> tuple[ComplexMatrix, tuple[ComplexMatrix, ...]]:
+ if period <= 0 or steps < 1:
+ raise ValueError("period and steps must be positive")
+ dt = period / steps
+ dimension = hamiltonian(0.0).shape[0]
+ total = np.eye(dimension, dtype=np.complex128)
+ pieces: list[ComplexMatrix] = []
+ for index in range(steps):
+ midpoint = (index + 0.5) * dt
+ piece = expm(-1j * hamiltonian(midpoint) * dt)
+ pieces.append(piece)
+ total = piece @ total
+ return total, tuple(pieces)
+
+
+def solve_floquet(
+ hamiltonian: Callable[[float], ComplexMatrix],
+ period: float,
+ steps: int,
+) -> FloquetSolution:
+ total, pieces = one_period_propagator(hamiltonian, period, steps)
+ values, modes = np.linalg.eig(total)
+ phases = np.angle(values)
+ quasienergies = -phases / period
+ order = np.argsort(quasienergies)
+ quasienergies = quasienergies[order].astype(np.float64)
+ modes = modes[:, order]
+ modes /= np.linalg.norm(modes, axis=0)
+ identity = np.eye(total.shape[0])
+ unitarity = float(np.linalg.norm(total.conj().T @ total - identity))
+ residual = float(
+ np.linalg.norm(total @ modes - modes * np.exp(-1j * quasienergies * period))
+ )
+ return FloquetSolution(
+ total,
+ quasienergies,
+ modes,
+ period,
+ pieces,
+ unitarity,
+ residual,
+ )
+
+
+def micromotion(solution: FloquetSolution) -> tuple[ComplexMatrix, ...]:
+ """Return cumulative propagators at all step boundaries, including t=0."""
+ values = [np.eye(solution.propagator.shape[0], dtype=np.complex128)]
+ for piece in solution.step_propagators:
+ values.append(piece @ values[-1])
+ return tuple(values)
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_current.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_current.py
new file mode 100644
index 000000000..5df62f44c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_current.py
@@ -0,0 +1,93 @@
+"""Frequency-resolved bath heat current from collective correlations."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+import numpy as np
+from numpy.typing import NDArray
+from scipy.integrate import trapezoid
+
+from .bath import bose_occupation, ohmic_spectral_density
+from .config import BathConfig
+from .correlations import CorrelationResult
+
+
+@dataclass(frozen=True)
+class HeatDeltaPeak:
+ harmonic: int
+ frequency: float
+ weight: float
+
+
+@dataclass(frozen=True)
+class HeatCurrentResult:
+ frequencies: NDArray[np.float64]
+ continuous: NDArray[np.float64]
+ delta_peaks: tuple[HeatDeltaPeak, ...]
+ method: str
+ metadata: dict[str, float | str]
+
+
+def heat_current_spectrum(
+ correlation: CorrelationResult,
+ bath: BathConfig,
+ frequencies: NDArray[np.float64],
+ window: str = "hann",
+) -> HeatCurrentResult:
+ """Evaluate the half-sided heat-current transform.
+
+ The continuous part uses only the connected correlation. Coherent
+ contributions are returned as analytic delta weights.
+ """
+ if np.any(frequencies < 0):
+ raise ValueError("bath frequencies must be nonnegative")
+ delays = correlation.delays
+ if len(delays) < 2 or not np.allclose(np.diff(delays), np.diff(delays)[0]):
+ raise ValueError("correlation delays must form a uniform grid")
+ if window == "hann":
+ taper = np.hanning(2 * len(delays) - 1)[len(delays) - 1 :]
+ elif window == "none":
+ taper = np.ones(len(delays))
+ else:
+ raise ValueError("window must be 'hann' or 'none'")
+ connected = correlation.connected * taper
+ output = np.zeros_like(frequencies, dtype=np.float64)
+ for index, frequency in enumerate(frequencies):
+ if frequency == 0:
+ continue
+ occupation = bose_occupation(float(frequency), bath.temperature)
+ kernel = (
+ np.cos(frequency * delays) * np.real(connected)
+ + (1 + 2 * occupation)
+ * np.sin(frequency * delays)
+ * np.imag(connected)
+ )
+ prefactor = 2 * float(ohmic_spectral_density(float(frequency), bath)) * frequency
+ output[index] = prefactor * trapezoid(kernel, delays)
+
+ delta_peaks = tuple(
+ HeatDeltaPeak(
+ peak.harmonic,
+ peak.frequency,
+ float(
+ np.pi
+ * ohmic_spectral_density(peak.frequency, bath)
+ * peak.frequency
+ * peak.correlation_weight
+ ),
+ )
+ for peak in correlation.delta_peaks
+ if peak.frequency > 0
+ )
+ return HeatCurrentResult(
+ frequencies,
+ output,
+ delta_peaks,
+ correlation.method,
+ {
+ "window": window,
+ "tau_max": float(delays[-1]),
+ "frequency_resolution": float(2 * np.pi / delays[-1]),
+ },
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_valve.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_valve.py
new file mode 100644
index 000000000..d178aac2c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_valve.py
@@ -0,0 +1,502 @@
+"""Fixed-frequency coherent-destruction scans for the Floquet heat valve."""
+
+from __future__ import annotations
+
+import subprocess
+from collections.abc import Iterable
+from dataclasses import asdict, dataclass
+from typing import Any, Literal
+
+import numpy as np
+from scipy.integrate import trapezoid
+from scipy.optimize import linear_sum_assignment
+from scipy.special import jn_zeros, jv
+
+from .backends.uniform_tempo import (
+ UNIFORM_TEMPO_REVISION,
+ UniformTempoBackend,
+ UniformTempoControls,
+)
+from .config import BathConfig, ModelConfig
+from .convergence import ConvergenceCache, fingerprint
+from .dark_channels import floquet_matrix_elements
+from .floquet import FloquetSolution, solve_floquet
+from .heat_current import heat_current_spectrum
+from .models import coupling_operator, drive_operator, ising_hamiltonian
+from .operators import ComplexMatrix
+from .poles import fit_pole_residues, transfer_poles
+from .symmetry import Sector, n2_sectors, n3_reflection_sectors, project
+
+BESSEL_ROOT = float(jn_zeros(0, 1)[0])
+
+
+@dataclass(frozen=True)
+class HeatValvePoint:
+ n: Literal[1, 2, 3]
+ xi: float
+ j: float = 1.0
+ omega: float = 1.0
+ drive_frequency: float = 3.0
+ alpha: float = 0.05
+ cutoff: float = 2.5
+ temperature: float = 0.0
+ floquet_steps: int = 360
+
+ def __post_init__(self) -> None:
+ if self.n not in (1, 2, 3):
+ raise ValueError("n must be one of 1, 2, 3")
+ if self.xi < 0:
+ raise ValueError("xi must be nonnegative")
+ if self.floquet_steps < 8:
+ raise ValueError("floquet_steps must be at least eight")
+
+ @property
+ def drive_amplitude(self) -> float:
+ return self.xi * self.drive_frequency / 2
+
+
+@dataclass(frozen=True)
+class PreparedHeatValve:
+ point: HeatValvePoint
+ model: ModelConfig
+ bath: BathConfig
+ sector: Sector
+ h0: ComplexMatrix
+ coupling: ComplexMatrix
+ drive: ComplexMatrix
+ cat_plus: np.ndarray[Any, np.dtype[np.complex128]]
+ cat_minus: np.ndarray[Any, np.dtype[np.complex128]]
+
+
+@dataclass(frozen=True)
+class ValveNumerics:
+ steps_per_period: int = 60
+ tolerance: float = 1e-6
+ phase_samples: int = 3
+ delay_periods: int = 12
+ pole_count: int = 8
+ pole_tolerance: float = 1e-10
+ pole_maxiter: int = 2_000
+ frequency_max: float = 6.0
+ frequency_points: int = 601
+ auto_nc: bool = True
+ memory_cutoff: int = 100_000
+ low_rank_svd: bool = False
+ truncation: Literal["rel", "abs"] = "rel"
+ cap_rank: int = 100_000
+ max_rank: int = 100_000
+
+ def __post_init__(self) -> None:
+ if self.steps_per_period < 2:
+ raise ValueError("steps_per_period must be at least two")
+ if (
+ self.phase_samples < 2
+ or self.phase_samples > self.steps_per_period
+ or self.steps_per_period % self.phase_samples != 0
+ ):
+ raise ValueError("phase_samples must divide steps_per_period")
+ if not 0 < self.tolerance < 1:
+ raise ValueError("tolerance must lie between zero and one")
+ if self.delay_periods < 1:
+ raise ValueError("delay_periods must be positive")
+ if self.pole_count < 2:
+ raise ValueError("pole_count must include steady and decaying poles")
+ if self.delay_periods + 1 <= self.pole_count - 1:
+ raise ValueError("delay window must overdetermine the pole fit")
+ if self.pole_tolerance <= 0 or self.pole_maxiter < 1:
+ raise ValueError("invalid pole solver controls")
+ if self.frequency_max <= 0 or self.frequency_points < 2:
+ raise ValueError("invalid heat-current frequency grid")
+ if self.memory_cutoff < 1:
+ raise ValueError("memory_cutoff must be positive")
+ if self.truncation not in ("rel", "abs"):
+ raise ValueError("truncation must be 'rel' or 'abs'")
+ if self.cap_rank < 1 or self.max_rank < self.cap_rank:
+ raise ValueError("invalid rank limits")
+
+
+def _active_sector(n: int) -> Sector:
+ if n == 1:
+ return Sector("full", np.eye(2, dtype=np.complex128))
+ if n == 2:
+ _, triplet = n2_sectors()
+ return triplet
+ _, even = n3_reflection_sectors()
+ return even
+
+
+def _projected_cat(
+ n: int,
+ sector: Sector,
+ sign: Literal[-1, 1],
+) -> np.ndarray[Any, np.dtype[np.complex128]]:
+ up = np.zeros(2**n, dtype=np.complex128)
+ down = np.zeros(2**n, dtype=np.complex128)
+ up[0] = 1
+ down[-1] = 1
+ value = sector.isometry.conj().T @ ((up + sign * down) / np.sqrt(2))
+ norm = float(np.linalg.norm(value))
+ if norm <= 1e-13:
+ raise ValueError("selected sector does not contain the cat state")
+ return np.asarray(value / norm, dtype=np.complex128)
+
+
+def prepare_heat_valve_point(point: HeatValvePoint) -> PreparedHeatValve:
+ """Project a size point while keeping bath and drive normalizations separate."""
+ model = ModelConfig(
+ n=point.n,
+ j=point.j,
+ omega=point.omega,
+ drive_amplitude=point.drive_amplitude,
+ drive_frequency=point.drive_frequency,
+ normalization="bounded",
+ drive_normalization="per_spin",
+ )
+ bath = BathConfig(point.alpha, point.cutoff, point.temperature)
+ sector = _active_sector(point.n)
+ return PreparedHeatValve(
+ point=point,
+ model=model,
+ bath=bath,
+ sector=sector,
+ h0=project(ising_hamiltonian(model), sector),
+ coupling=project(coupling_operator(model), sector),
+ drive=project(drive_operator(model), sector),
+ cat_plus=_projected_cat(point.n, sector, +1),
+ cat_minus=_projected_cat(point.n, sector, -1),
+ )
+
+
+def _cat_modes(
+ prepared: PreparedHeatValve,
+ solution: FloquetSolution,
+) -> tuple[tuple[int, int], tuple[float, float], float]:
+ cat_basis = np.column_stack((prepared.cat_plus, prepared.cat_minus))
+ subspace_weights = np.sum(
+ abs(cat_basis.conj().T @ solution.modes) ** 2,
+ axis=0,
+ )
+ selected = np.argsort(subspace_weights)[-2:]
+ overlaps = abs(cat_basis.conj().T @ solution.modes[:, selected]) ** 2
+ rows, columns = linear_sum_assignment(-overlaps)
+ assigned = {
+ int(row): (int(selected[column]), float(overlaps[row, column]))
+ for row, column in zip(rows, columns, strict=True)
+ }
+ modes = (assigned[0][0], assigned[1][0])
+ direct_overlaps = (assigned[0][1], assigned[1][1])
+ cat_overlap = float(np.min(subspace_weights[selected]))
+ return modes, direct_overlaps, cat_overlap
+
+
+def _isolated_point(point: HeatValvePoint) -> dict[str, Any]:
+ prepared = prepare_heat_valve_point(point)
+ model = prepared.model
+
+ def hamiltonian(time: float) -> ComplexMatrix:
+ return np.asarray(
+ prepared.h0
+ + model.drive_amplitude
+ * np.cos(model.drive_frequency * time)
+ * prepared.drive,
+ dtype=np.complex128,
+ )
+
+ solution = solve_floquet(
+ hamiltonian,
+ model.period,
+ point.floquet_steps,
+ )
+ modes, direct_overlaps, cat_overlap = _cat_modes(prepared, solution)
+ raw_gap = float(abs(solution.quasienergies[modes[0]] - solution.quasienergies[modes[1]]))
+ cat_gap = min(raw_gap, model.drive_frequency - raw_gap)
+ transitions = floquet_matrix_elements(
+ solution,
+ prepared.coupling,
+ harmonic_cutoff=3,
+ )
+ selected_modes = set(modes)
+ cat_brightness = float(
+ sum(
+ record.weight
+ for record in transitions
+ if record.source in selected_modes
+ and record.target in selected_modes
+ and record.source != record.target
+ )
+ )
+ return {
+ **asdict(point),
+ "drive_amplitude": model.drive_amplitude,
+ "bessel_j0": float(jv(0, point.xi)),
+ "bessel_root": BESSEL_ROOT,
+ "sector": prepared.sector.name,
+ "dimension": prepared.sector.dimension,
+ "cat_mode_indices": list(modes),
+ "cat_plus_overlap": direct_overlaps[0],
+ "cat_minus_overlap": direct_overlaps[1],
+ "cat_overlap": cat_overlap,
+ "cat_gap": float(cat_gap),
+ "cat_brightness": cat_brightness,
+ "unitarity_residual": solution.unitarity_residual,
+ "floquet_eigen_residual": solution.eigen_residual,
+ }
+
+
+def isolated_valve_scan(
+ points: Iterable[HeatValvePoint],
+) -> dict[str, Any]:
+ """Run a deterministic exact scan before selecting open-system points."""
+ selected = tuple(points)
+ if not selected:
+ raise ValueError("the isolated valve scan requires at least one point")
+ records = [_isolated_point(point) for point in selected]
+ return {
+ "complete": True,
+ "method": "isolated_floquet_coherent_destruction",
+ "schema_version": 1,
+ "bessel_root": BESSEL_ROOT,
+ "points": records,
+ }
+
+
+def _complex_values(values: np.ndarray[Any, np.dtype[np.complex128]]) -> dict[str, Any]:
+ array = np.asarray(values, dtype=np.complex128)
+ return {
+ "real": np.real(array).astype(float).tolist(),
+ "imag": np.imag(array).astype(float).tolist(),
+ }
+
+
+def _git_commit() -> str:
+ try:
+ return subprocess.check_output(
+ ["git", "rev-parse", "HEAD"],
+ text=True,
+ stderr=subprocess.DEVNULL,
+ ).strip()
+ except (OSError, subprocess.CalledProcessError):
+ return "unknown"
+
+
+def run_uniform_valve_point(
+ point: HeatValvePoint,
+ numerics: ValveNumerics,
+ cache: ConvergenceCache,
+ *,
+ source_revision: str | None = None,
+) -> dict[str, Any]:
+ """Run or restore one pole-resolved UniformTEMPO heat-valve point."""
+ prepared = prepare_heat_valve_point(point)
+ revision = _git_commit() if source_revision is None else source_revision
+ cache_payload = {
+ "experiment": "uniform-floquet-pole-heat-valve-v1",
+ "point": asdict(point),
+ "numerics": asdict(numerics),
+ "h0": _complex_values(prepared.h0),
+ "coupling": _complex_values(prepared.coupling),
+ "drive": _complex_values(prepared.drive),
+ "bath": asdict(prepared.bath),
+ "uniform_tempo_revision": UNIFORM_TEMPO_REVISION,
+ }
+ key = fingerprint(cache_payload, revision)
+ if cache.contains(key):
+ return cache.load(key)
+
+ controls = UniformTempoControls(
+ steps_per_period=numerics.steps_per_period,
+ tolerance=numerics.tolerance,
+ phase_samples=numerics.phase_samples,
+ delay_periods=numerics.delay_periods,
+ auto_nc=numerics.auto_nc,
+ memory_cutoff=numerics.memory_cutoff,
+ low_rank_svd=numerics.low_rank_svd,
+ truncation=numerics.truncation,
+ cap_rank=numerics.cap_rank,
+ max_rank=numerics.max_rank,
+ pole_count=numerics.pole_count,
+ pole_tolerance=numerics.pole_tolerance,
+ pole_maxiter=numerics.pole_maxiter,
+ )
+ run = UniformTempoBackend(
+ tensor_cache_directory=cache.directory / "process_tensors"
+ ).run_periodic(
+ prepared.h0,
+ prepared.coupling,
+ prepared.model,
+ prepared.bath,
+ controls,
+ drive_operator=prepared.drive,
+ )
+ poles = transfer_poles(
+ run.transfer_eigenvalues,
+ run.transfer_eigenpair_residuals,
+ prepared.model.period,
+ )
+ fit = fit_pole_residues(
+ poles,
+ run.correlation.delays,
+ run.correlation.connected,
+ prepared.model.period,
+ max_modes=len(poles),
+ )
+ frequencies = np.linspace(
+ 0,
+ numerics.frequency_max,
+ numerics.frequency_points,
+ )
+ heat = heat_current_spectrum(
+ run.correlation,
+ prepared.bath,
+ frequencies,
+ )
+ connected_tail = float(abs(run.correlation.connected[-1]))
+ maximum_eigenpair_residual = float(
+ np.max(run.transfer_eigenpair_residuals)
+ )
+ maximum_pole_modulus = float(
+ max(abs(item.eigenvalue) for item in poles)
+ )
+ converged = bool(
+ run.diagnostics["trace_error"] <= 5e-3
+ and run.diagnostics["hermiticity_error"] <= 5e-3
+ and run.diagnostics["minimum_density_eigenvalue"] >= -5e-3
+ and run.diagnostics["fixed_point_residual"] <= 1e-3
+ and connected_tail <= 5e-2
+ and maximum_eigenpair_residual <= 1e-8
+ and maximum_pole_modulus <= 1 + 1e-6
+ and fit.reconstruction_residual <= 5e-2
+ )
+ residue_records = [
+ {
+ "eigenvalue": {
+ "real": float(item.pole.eigenvalue.real),
+ "imag": float(item.pole.eigenvalue.imag),
+ "abs": float(abs(item.pole.eigenvalue)),
+ },
+ "decay_rate": item.pole.decay_rate,
+ "quasifrequency": item.pole.quasifrequency,
+ "eigenpair_residual": item.pole.eigenpair_residual,
+ "residue": {
+ "real": float(item.residue.real),
+ "imag": float(item.residue.imag),
+ "abs": float(abs(item.residue)),
+ },
+ }
+ for item in fit.residues
+ ]
+ dominant = max(fit.residues, key=lambda item: abs(item.residue))
+ payload: dict[str, Any] = {
+ "method": run.method,
+ "source_commit": revision,
+ "point": asdict(point),
+ "model": asdict(prepared.model),
+ "bath": asdict(prepared.bath),
+ "numerics": asdict(numerics),
+ "sector": prepared.sector.name,
+ "dimension": prepared.sector.dimension,
+ "converged": converged,
+ "diagnostics": {
+ **run.diagnostics,
+ **run.metadata,
+ "connected_tail": connected_tail,
+ "maximum_eigenpair_residual": maximum_eigenpair_residual,
+ "maximum_pole_modulus": maximum_pole_modulus,
+ },
+ "phase_state": _complex_values(run.floquet_state),
+ "phase_states": _complex_values(run.phase_states),
+ "correlation": {
+ "delay": run.correlation.delays.tolist(),
+ "total": _complex_values(run.correlation.total),
+ "connected": _complex_values(run.correlation.connected),
+ "coherent": run.correlation.coherent.tolist(),
+ },
+ "frequency": heat.frequencies.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(item) for item in heat.delta_peaks],
+ "integrated_absolute_heat": float(
+ trapezoid(abs(heat.continuous), heat.frequencies)
+ ),
+ "poles": residue_records,
+ "dominant_residue": {
+ "real": float(dominant.residue.real),
+ "imag": float(dominant.residue.imag),
+ "abs": float(abs(dominant.residue)),
+ },
+ "visible_residue_weight": float(
+ sum(abs(item.residue) for item in fit.residues)
+ ),
+ "pole_fit": {
+ "reconstruction": _complex_values(fit.reconstruction),
+ "stroboscopic_delays": fit.stroboscopic_delays.tolist(),
+ "reconstruction_residual": fit.reconstruction_residual,
+ "condition_number": fit.condition_number,
+ },
+ }
+ cache.store(key, payload)
+ return cache.load(key)
+
+
+def _point_from_scan(record: dict[str, Any]) -> HeatValvePoint:
+ return HeatValvePoint(
+ n=int(record["n"]), # type: ignore[arg-type]
+ xi=float(record["xi"]),
+ j=float(record["j"]),
+ omega=float(record["omega"]),
+ drive_frequency=float(record["drive_frequency"]),
+ alpha=float(record["alpha"]),
+ cutoff=float(record["cutoff"]),
+ temperature=float(record["temperature"]),
+ floquet_steps=int(record["floquet_steps"]),
+ )
+
+
+def build_heat_valve_manifest(
+ isolated_scan: dict[str, Any],
+ uniform_results: Iterable[dict[str, Any]] = (),
+) -> dict[str, Any]:
+ """Select two-sided valve points and combine any completed exact results."""
+ scan_records = tuple(isolated_scan.get("points", ()))
+ selected: list[HeatValvePoint] = []
+ for n in (1, 2, 3):
+ candidates = [
+ record
+ for record in scan_records
+ if int(record["n"]) == n and float(record["cat_overlap"]) >= 0.5
+ ]
+ if not candidates:
+ raise ValueError(f"isolated scan has no resolved N={n} cat points")
+ minimum = min(candidates, key=lambda item: float(item["cat_gap"]))
+ minimum_xi = float(minimum["xi"])
+ lower = [
+ record
+ for record in candidates
+ if float(record["xi"]) <= minimum_xi - 0.15
+ ]
+ upper = [
+ record
+ for record in candidates
+ if float(record["xi"]) >= minimum_xi + 0.15
+ ]
+ if not lower or not upper:
+ raise ValueError(f"isolated N={n} minimum lacks two resolved flanks")
+ selected.extend(
+ (
+ _point_from_scan(max(lower, key=lambda item: float(item["xi"]))),
+ _point_from_scan(minimum),
+ _point_from_scan(min(upper, key=lambda item: float(item["xi"]))),
+ )
+ )
+
+ results = tuple(uniform_results)
+ result_keys = {
+ (int(item["point"]["n"]), float(item["point"]["xi"])) for item in results
+ }
+ selected_keys = {(item.n, item.xi) for item in selected}
+ return {
+ "complete": result_keys == selected_keys,
+ "method": "uniform-floquet-pole-heat-valve-v1",
+ "isolated_scan_complete": bool(isolated_scan.get("complete", False)),
+ "selected_points": [asdict(item) for item in selected],
+ "points": list(results),
+ }
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_valve_audit.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_valve_audit.py
new file mode 100644
index 000000000..21448dc27
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/heat_valve_audit.py
@@ -0,0 +1,198 @@
+"""Independent scientific claim gates for the pole-resolved heat valve."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import Any
+
+import numpy as np
+
+
+@dataclass(frozen=True)
+class HeatValveAudit:
+ complete: bool
+ dark_channel_passed: bool
+ many_body_amplification_passed: bool
+ markov_payoff_passed: bool
+ failures: tuple[str, ...]
+ metrics: dict[str, float]
+
+
+def _same_numeric(values: list[float], tolerance: float = 1e-12) -> bool:
+ return bool(values) and bool(
+ np.allclose(values, values[0], rtol=tolerance, atol=tolerance)
+ )
+
+
+def _ratio(numerator: float, denominator: float) -> float:
+ if denominator <= 0:
+ return float("inf")
+ return numerator / denominator
+
+
+def audit_heat_valve_manifest(manifest: dict[str, Any]) -> HeatValveAudit:
+ """Apply the design gates without relying on any plotting decisions."""
+ dark_failures: list[str] = []
+ auxiliary_failures: list[str] = []
+ metrics: dict[str, float] = {}
+ selected = list(manifest.get("selected_points", ()))
+ points = list(manifest.get("points", ()))
+
+ selected_keys = [
+ (int(item["n"]), float(item["xi"]))
+ for item in selected
+ if isinstance(item, dict) and "n" in item and "xi" in item
+ ]
+ point_map = {
+ (int(item["point"]["n"]), float(item["point"]["xi"])): item
+ for item in points
+ if isinstance(item, dict)
+ and isinstance(item.get("point"), dict)
+ and "n" in item["point"]
+ and "xi" in item["point"]
+ }
+ complete = bool(
+ manifest.get("complete", False)
+ and len(selected_keys) == 9
+ and len(set(selected_keys)) == 9
+ and len(point_map) == 9
+ and set(selected_keys) == set(point_map)
+ and all(sum(key[0] == n for key in selected_keys) == 3 for n in (1, 2, 3))
+ )
+ if not complete:
+ dark_failures.append("heat-valve manifest is incomplete")
+
+ drive_frequencies = [
+ float(item["model"]["drive_frequency"])
+ for item in point_map.values()
+ ]
+ if point_map and not _same_numeric(drive_frequencies):
+ dark_failures.append("fixed drive frequency was not held constant")
+
+ fixed_controls = (
+ ("j", [float(item["model"]["j"]) for item in point_map.values()]),
+ (
+ "omega",
+ [float(item["model"]["omega"]) for item in point_map.values()],
+ ),
+ (
+ "alpha",
+ [float(item["bath"]["alpha"]) for item in point_map.values()],
+ ),
+ (
+ "cutoff",
+ [float(item["bath"]["cutoff"]) for item in point_map.values()],
+ ),
+ (
+ "temperature",
+ [float(item["bath"]["temperature"]) for item in point_map.values()],
+ ),
+ )
+ for label, values in fixed_controls:
+ if point_map and not _same_numeric(values):
+ dark_failures.append(f"fixed physical control {label} changed")
+ for label in ("normalization", "drive_normalization"):
+ labels = {str(item["model"][label]) for item in point_map.values()}
+ if point_map and len(labels) != 1:
+ dark_failures.append(f"fixed physical control {label} changed")
+
+ for key, item in point_map.items():
+ label = f"N={key[0]}, xi={key[1]:g}"
+ if not bool(item.get("converged", False)):
+ dark_failures.append(f"{label}: convergence gate failed")
+ diagnostics = item.get("diagnostics", {})
+ if (
+ float(diagnostics.get("trace_error", float("inf"))) > 5e-3
+ or float(diagnostics.get("hermiticity_error", float("inf"))) > 5e-3
+ or float(
+ diagnostics.get("minimum_density_eigenvalue", -float("inf"))
+ )
+ < -5e-3
+ or float(diagnostics.get("fixed_point_residual", float("inf")))
+ > 1e-3
+ or float(diagnostics.get("connected_tail", float("inf"))) > 5e-2
+ ):
+ dark_failures.append(f"{label}: physical diagnostics gate failed")
+ reconstruction = float(
+ item.get("pole_fit", {}).get(
+ "reconstruction_residual",
+ float("inf"),
+ )
+ )
+ if reconstruction > 5e-2:
+ dark_failures.append(f"{label}: pole reconstruction residual exceeds 5%")
+ for pole in item.get("poles", ()):
+ if float(pole.get("eigenpair_residual", float("inf"))) > 1e-8:
+ dark_failures.append(f"{label}: eigenpair residual exceeds 1e-8")
+ break
+ for pole in item.get("poles", ()):
+ modulus = float(
+ pole.get("eigenvalue", {}).get("abs", float("inf"))
+ )
+ if modulus > 1 + 1e-6:
+ dark_failures.append(f"{label}: transfer pole leaves the unit disk")
+ break
+
+ heat_contrasts: dict[int, float] = {}
+ for n in (1, 2, 3):
+ ordered_keys = [key for key in selected_keys if key[0] == n]
+ if len(ordered_keys) != 3 or any(key not in point_map for key in ordered_keys):
+ continue
+ lower, minimum, upper = (point_map[key] for key in ordered_keys)
+ lower_heat = float(lower.get("integrated_absolute_heat", float("nan")))
+ minimum_heat = float(minimum.get("integrated_absolute_heat", float("nan")))
+ upper_heat = float(upper.get("integrated_absolute_heat", float("nan")))
+ heat_ratio = max(
+ _ratio(minimum_heat, lower_heat),
+ _ratio(minimum_heat, upper_heat),
+ )
+ heat_contrast = _ratio(min(lower_heat, upper_heat), minimum_heat)
+ heat_contrasts[n] = heat_contrast
+ metrics[f"heat_ratio_n{n}"] = heat_ratio
+ metrics[f"heat_contrast_n{n}"] = heat_contrast
+ if not np.isfinite(heat_ratio) or heat_ratio > 0.1:
+ dark_failures.append(
+ f"N={n}: tenfold heat suppression against both flanks failed"
+ )
+
+ lower_residue = float(
+ lower.get("visible_residue_weight", float("nan"))
+ )
+ minimum_residue = float(
+ minimum.get("visible_residue_weight", float("nan"))
+ )
+ upper_residue = float(
+ upper.get("visible_residue_weight", float("nan"))
+ )
+ residue_ratio = max(
+ _ratio(minimum_residue, lower_residue),
+ _ratio(minimum_residue, upper_residue),
+ )
+ metrics[f"residue_ratio_n{n}"] = residue_ratio
+ if not np.isfinite(residue_ratio) or residue_ratio > 0.1:
+ dark_failures.append(
+ f"N={n}: tenfold residue suppression against both flanks failed"
+ )
+
+ dark_channel_passed = complete and not dark_failures
+ amplification = bool(
+ dark_channel_passed
+ and 1 in heat_contrasts
+ and 3 in heat_contrasts
+ and heat_contrasts[3] >= 5 * heat_contrasts[1]
+ )
+ if dark_channel_passed and not amplification:
+ auxiliary_failures.append(
+ "many-body amplification did not exceed the fivefold contrast gate"
+ )
+ markov_payoff = bool(
+ manifest.get("markov_comparison", {}).get("passed", False)
+ )
+ return HeatValveAudit(
+ complete=complete,
+ dark_channel_passed=dark_channel_passed,
+ many_body_amplification_passed=amplification,
+ markov_payoff_passed=markov_payoff,
+ failures=tuple(dark_failures + auxiliary_failures),
+ metrics=metrics,
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/influence.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/influence.py
new file mode 100644
index 000000000..ca3a4fbd3
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/influence.py
@@ -0,0 +1,71 @@
+"""Discrete Feynman-Vernon coefficients for piecewise-constant paths."""
+
+from __future__ import annotations
+
+from collections.abc import Callable
+from dataclasses import dataclass
+
+import numpy as np
+from numpy.typing import NDArray
+from scipy.integrate import quad
+
+from .bath import bath_correlation
+from .config import BathConfig
+
+
+@dataclass(frozen=True)
+class InfluenceCoefficients:
+ values: NDArray[np.complex128]
+ dt: float
+ quadrature_error: float
+ tail_bound: float
+
+
+def _integrate_complex(
+ function: Callable[[float], complex], low: float, high: float
+) -> tuple[complex, float]:
+ real, real_error = quad(lambda x: np.real(function(x)), low, high, epsabs=2e-11)
+ imag, imag_error = quad(lambda x: np.imag(function(x)), low, high, epsabs=2e-11)
+ return complex(real, imag), float(real_error + imag_error)
+
+
+def discretize_influence(
+ bath: BathConfig,
+ dt: float,
+ memory_steps: int,
+) -> InfluenceCoefficients:
+ """Cell-integrate the bath correlation.
+
+ ``eta[0]`` uses the causal triangle in a single time cell. ``eta[k>0]``
+ uses two full cells separated by ``k`` timesteps.
+ """
+ if dt <= 0 or memory_steps < 1:
+ raise ValueError("dt and memory_steps must be positive")
+ values = np.empty(memory_steps + 1, dtype=np.complex128)
+ error = 0.0
+
+ # eta_0 = integral_0^dt du integral_0^u dv C(u-v)
+ value0, error0 = _integrate_complex(
+ lambda tau: (dt - tau) * bath_correlation(tau, bath), 0, dt
+ )
+ values[0] = value0
+ error += error0
+
+ for lag in range(1, memory_steps + 1):
+ # Difference of two points from equal-width cells has triangular weight.
+ center = lag * dt
+
+ def integrand(offset: float, center: float = center) -> complex:
+ return (dt - abs(offset)) * bath_correlation(center + offset, bath)
+
+ value, item_error = _integrate_complex(
+ integrand,
+ -dt,
+ dt,
+ )
+ values[lag] = value
+ error += item_error
+
+ memory_time = memory_steps * dt
+ tail_bound = bath.alpha / max(1 / bath.cutoff, memory_time)
+ return InfluenceCoefficients(values, dt, error, float(tail_bound))
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/io.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/io.py
new file mode 100644
index 000000000..481a7bd90
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/io.py
@@ -0,0 +1,60 @@
+"""Result serialization and provenance."""
+
+from __future__ import annotations
+
+import hashlib
+import json
+import platform
+import subprocess
+from datetime import UTC, datetime
+from pathlib import Path
+from typing import Any, cast
+
+import numpy as np
+
+from . import __version__
+
+
+def _git_commit() -> str:
+ try:
+ return subprocess.check_output(
+ ["git", "rev-parse", "HEAD"], text=True, stderr=subprocess.DEVNULL
+ ).strip()
+ except (OSError, subprocess.CalledProcessError):
+ return "unknown"
+
+
+def write_result(path: Path, payload: dict[str, Any]) -> None:
+ canonical = json.dumps(payload, sort_keys=True, default=str)
+ envelope = {
+ "schema_version": 1,
+ "config_hash": hashlib.sha256(canonical.encode()).hexdigest()[:16],
+ "created_utc": datetime.now(UTC).isoformat(),
+ "environment": {
+ "python": platform.python_version(),
+ "numpy": np.__version__,
+ "package": __version__,
+ "git_commit": _git_commit(),
+ },
+ **payload,
+ }
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(json.dumps(envelope, indent=2, sort_keys=True), encoding="utf-8")
+
+
+def read_result(path: Path) -> dict[str, Any]:
+ result = json.loads(path.read_text(encoding="utf-8"))
+ required = {
+ "schema_version",
+ "config_hash",
+ "created_utc",
+ "environment",
+ "method",
+ "converged",
+ "diagnostics",
+ "data",
+ }
+ missing = required - set(result)
+ if missing:
+ raise ValueError(f"{path} is missing keys: {sorted(missing)}")
+ return cast(dict[str, Any], result)
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/model_comparison.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/model_comparison.py
new file mode 100644
index 000000000..3a5453819
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/model_comparison.py
@@ -0,0 +1,97 @@
+"""Explicit common-bath normalization and counterterm model variants."""
+
+from __future__ import annotations
+
+from dataclasses import asdict, dataclass
+from typing import Any
+
+import numpy as np
+from numpy.typing import NDArray
+
+from .config import BathConfig, ModelConfig, Normalization
+from .models import coupling_operator, ising_hamiltonian
+from .operators import ComplexMatrix
+
+
+@dataclass(frozen=True)
+class ModelVariant:
+ name: str
+ config: ModelConfig
+ metadata: dict[str, Any]
+
+
+def _variant(
+ *,
+ name: str,
+ n: int,
+ j: float,
+ omega: float,
+ drive_amplitude: float,
+ drive_frequency: float,
+ normalization: Normalization,
+ counterterm: bool,
+ bath: BathConfig,
+) -> ModelVariant:
+ strength = bath.alpha * bath.cutoff if counterterm else 0.0
+ config = ModelConfig(
+ n=n,
+ j=j,
+ omega=omega,
+ drive_amplitude=drive_amplitude,
+ drive_frequency=drive_frequency,
+ normalization=normalization,
+ counterterm=counterterm,
+ counterterm_strength=strength,
+ )
+ return ModelVariant(
+ name,
+ config,
+ {
+ "normalization": normalization,
+ "eta": config.eta,
+ "counterterm": counterterm,
+ "counterterm_strength": strength,
+ "bath": asdict(bath),
+ },
+ )
+
+
+def model_variants(
+ *,
+ n: int,
+ j: float,
+ bath: BathConfig,
+ omega: float = 1.0,
+ drive_amplitude: float = 0.2,
+ drive_frequency: float = 1.0,
+) -> tuple[ModelVariant, ...]:
+ """Return the four predeclared bounded/Kac and counterterm choices."""
+ return tuple(
+ _variant(
+ name=f"{normalization}_{'ct' if counterterm else 'no_ct'}",
+ n=n,
+ j=j,
+ omega=omega,
+ drive_amplitude=drive_amplitude,
+ drive_frequency=drive_frequency,
+ normalization=normalization,
+ counterterm=counterterm,
+ bath=bath,
+ )
+ for normalization in ("bounded", "kac")
+ for counterterm in (False, True)
+ )
+
+
+def variant_operators(variant: ModelVariant) -> tuple[ComplexMatrix, ComplexMatrix]:
+ return ising_hamiltonian(variant.config), coupling_operator(variant.config)
+
+
+def diagnostic_heat_rescaling(
+ heat: NDArray[np.float64], eta: float
+) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
+ """Return raw heat and a separately labeled eta-squared diagnostic."""
+ if eta <= 0:
+ raise ValueError("eta must be positive")
+ raw = np.array(heat, dtype=np.float64, copy=True)
+ return raw, raw / eta**2
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/models.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/models.py
new file mode 100644
index 000000000..40a06c4a2
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/models.py
@@ -0,0 +1,38 @@
+"""Hamiltonians for the open-boundary driven transverse-field Ising model."""
+
+from __future__ import annotations
+
+import numpy as np
+
+from .config import ModelConfig
+from .operators import ComplexMatrix, collective_operator, product_operator
+
+
+def coupling_operator(config: ModelConfig) -> ComplexMatrix:
+ return collective_operator("z", config.n, config.eta)
+
+
+def drive_operator(config: ModelConfig) -> ComplexMatrix:
+ return collective_operator("z", config.n, config.drive_eta)
+
+
+def ising_hamiltonian(config: ModelConfig) -> ComplexMatrix:
+ dimension = 2**config.n
+ hamiltonian = np.zeros((dimension, dimension), dtype=np.complex128)
+ for site in range(config.n - 1):
+ hamiltonian -= config.j * product_operator({site: "z", site + 1: "z"}, config.n)
+ hamiltonian += (config.omega / 2) * collective_operator("x", config.n)
+ if config.counterterm:
+ s = coupling_operator(config)
+ hamiltonian += config.counterterm_strength * (s @ s)
+ return hamiltonian
+
+
+def driven_hamiltonian(config: ModelConfig, time: float) -> ComplexMatrix:
+ return np.asarray(
+ ising_hamiltonian(config)
+ + config.drive_amplitude
+ * np.cos(config.drive_frequency * time)
+ * drive_operator(config),
+ dtype=np.complex128,
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/n2_heat.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/n2_heat.py
new file mode 100644
index 000000000..c8bef4b64
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/n2_heat.py
@@ -0,0 +1,366 @@
+"""Reusable interacting-triplet N=2 PT-TEMPO heat-current points."""
+
+from __future__ import annotations
+
+import subprocess
+from dataclasses import asdict, dataclass
+from typing import Any, Literal
+
+import numpy as np
+
+from .backends.pt_tempo import PtTempoBackend
+from .backends.uniform_tempo import UniformTempoBackend, UniformTempoControls
+from .config import BathConfig, ModelConfig, Normalization
+from .convergence import ConvergenceCache, fingerprint
+from .heat_current import heat_current_spectrum
+from .models import coupling_operator, ising_hamiltonian
+from .operators import ComplexMatrix
+from .spectra import diagonalize, transitions
+from .symmetry import n2_sectors, project
+
+
+@dataclass(frozen=True)
+class N2HeatPoint:
+ j: float = 0.5
+ backend: Literal["oqupy", "uniform_tempo"] = "oqupy"
+ omega: float = 1.0
+ drive_amplitude: float = 0.2
+ drive_ratio: float = 1.0
+ drive_frequency: float | None = None
+ normalization: Normalization = "bounded"
+ counterterm: bool = False
+ alpha: float = 0.1
+ cutoff: float = 2.5
+ temperature: float = 0.0
+ steps_per_period: int = 16
+ steady_periods: int = 20
+ delay_periods: int = 4
+ memory_steps: int = 4
+ epsrel: float = 1e-5
+ frequency_max: float = 3.0
+ frequency_points: int = 401
+ phase_samples: int = 4
+ uniform_auto_nc: bool = True
+ uniform_memory_cutoff: int = 100_000
+ uniform_low_rank_svd: bool = False
+ uniform_truncation: Literal["rel", "abs"] = "rel"
+ uniform_cap_rank: int = 100_000
+ uniform_max_rank: int = 100_000
+
+ def __post_init__(self) -> None:
+ if self.backend not in ("oqupy", "uniform_tempo"):
+ raise ValueError("backend must be 'oqupy' or 'uniform_tempo'")
+ if self.drive_ratio <= 0 or self.steps_per_period < 2:
+ raise ValueError("invalid drive or timestep controls")
+ if self.steady_periods < 1 or self.delay_periods < 1:
+ raise ValueError("period counts must be positive")
+ if self.memory_steps < 1 or not 0 < self.epsrel < 1:
+ raise ValueError("invalid process-tensor controls")
+ if (
+ self.phase_samples < 2
+ or self.phase_samples > self.steps_per_period
+ or self.steps_per_period % self.phase_samples != 0
+ ):
+ raise ValueError("phase_samples must divide steps_per_period")
+ if self.uniform_memory_cutoff < 1:
+ raise ValueError("uniform_memory_cutoff must be positive")
+ if self.uniform_truncation not in ("rel", "abs"):
+ raise ValueError("uniform_truncation must be 'rel' or 'abs'")
+ if (
+ self.uniform_cap_rank < 1
+ or self.uniform_max_rank < self.uniform_cap_rank
+ ):
+ raise ValueError("invalid uniform rank limits")
+
+
+@dataclass(frozen=True)
+class PreparedN2:
+ point: N2HeatPoint
+ model: ModelConfig
+ bath: BathConfig
+ h0: ComplexMatrix
+ coupling: ComplexMatrix
+ bright_gap: float
+
+ @property
+ def dimension(self) -> int:
+ return int(self.h0.shape[0])
+
+
+def _bright_gap(hamiltonian: ComplexMatrix, coupling: ComplexMatrix) -> float:
+ spectrum = diagonalize(hamiltonian)
+ candidates = [
+ item.frequency
+ for item in transitions(spectrum, spectrum, coupling)
+ if item.source == 0 and item.frequency > 1e-12
+ ]
+ return float(f"{min(candidates):.14g}")
+
+
+def prepare_n2_triplet(point: N2HeatPoint) -> PreparedN2:
+ provisional = ModelConfig(
+ n=2,
+ j=point.j,
+ omega=point.omega,
+ drive_amplitude=point.drive_amplitude,
+ drive_frequency=point.omega,
+ normalization=point.normalization,
+ counterterm=point.counterterm,
+ counterterm_strength=(
+ point.alpha * point.cutoff if point.counterterm else 0.0
+ ),
+ )
+ _, triplet = n2_sectors()
+ h0 = project(ising_hamiltonian(provisional), triplet)
+ coupling = project(coupling_operator(provisional), triplet)
+ gap = _bright_gap(h0, coupling)
+ frequency = (
+ point.drive_frequency
+ if point.drive_frequency is not None
+ else point.drive_ratio * gap
+ )
+ model = ModelConfig(
+ n=2,
+ j=point.j,
+ omega=point.omega,
+ drive_amplitude=point.drive_amplitude,
+ drive_frequency=frequency,
+ normalization=point.normalization,
+ counterterm=point.counterterm,
+ counterterm_strength=provisional.counterterm_strength,
+ )
+ return PreparedN2(
+ point,
+ model,
+ BathConfig(point.alpha, point.cutoff, point.temperature),
+ h0,
+ coupling,
+ gap,
+ )
+
+
+def _complex_values(values: np.ndarray[Any, np.dtype[np.complex128]]) -> dict[str, Any]:
+ return {
+ "real": np.real(values).astype(float).tolist(),
+ "imag": np.imag(values).astype(float).tolist(),
+ }
+
+
+def _git_commit() -> str:
+ try:
+ return subprocess.check_output(
+ ["git", "rev-parse", "HEAD"],
+ text=True,
+ stderr=subprocess.DEVNULL,
+ ).strip()
+ except (OSError, subprocess.CalledProcessError):
+ return "unknown"
+
+
+def run_n2_heat_point(
+ point: N2HeatPoint,
+ cache: ConvergenceCache | None = None,
+ *,
+ commit: str | None = None,
+) -> dict[str, Any]:
+ prepared = prepare_n2_triplet(point)
+ revision = _git_commit() if commit is None else commit
+ key = fingerprint(
+ {
+ "experiment": f"n2_triplet_{point.backend}_heat",
+ "point": asdict(point),
+ "model": asdict(prepared.model),
+ "bath": asdict(prepared.bath),
+ },
+ revision,
+ )
+ if cache is not None and cache.contains(key):
+ return cache.load(key)
+ model_hash = fingerprint(
+ {
+ "model": asdict(prepared.model),
+ "bath": asdict(prepared.bath),
+ "sector": "triplet",
+ },
+ "scientific-model-v1",
+ )
+ projected_model_hash = fingerprint(
+ {
+ "h0": _complex_values(prepared.h0),
+ "coupling": _complex_values(prepared.coupling),
+ "drive_amplitude": prepared.model.drive_amplitude,
+ "drive_frequency": prepared.model.drive_frequency,
+ "bath": asdict(prepared.bath),
+ },
+ "projected-open-system-v1",
+ )
+ if point.backend == "uniform_tempo":
+ controls = UniformTempoControls(
+ steps_per_period=point.steps_per_period,
+ tolerance=point.epsrel,
+ phase_samples=point.phase_samples,
+ delay_periods=point.delay_periods,
+ auto_nc=point.uniform_auto_nc,
+ memory_cutoff=point.uniform_memory_cutoff,
+ low_rank_svd=point.uniform_low_rank_svd,
+ truncation=point.uniform_truncation,
+ cap_rank=point.uniform_cap_rank,
+ max_rank=point.uniform_max_rank,
+ )
+ uniform_run = UniformTempoBackend(
+ tensor_cache_directory=(
+ None if cache is None else cache.directory / "process_tensors"
+ )
+ ).run_periodic(
+ prepared.h0,
+ prepared.coupling,
+ prepared.model,
+ prepared.bath,
+ controls,
+ )
+ correlation = uniform_run.correlation
+ frequencies = np.linspace(
+ 0,
+ point.frequency_max,
+ point.frequency_points,
+ )
+ heat = heat_current_spectrum(correlation, prepared.bath, frequencies)
+ connected_tail = float(abs(correlation.connected[-1]))
+ diagnostics = {
+ **uniform_run.diagnostics,
+ **uniform_run.metadata,
+ "phase_residual": uniform_run.diagnostics["fixed_point_residual"],
+ "connected_tail_amplitude": connected_tail,
+ "tau_max": float(correlation.delays[-1]),
+ "epsrel": point.epsrel,
+ "phase_samples": point.phase_samples,
+ }
+ physical = bool(
+ uniform_run.diagnostics["trace_error"] <= 5e-3
+ and uniform_run.diagnostics["hermiticity_error"] <= 5e-3
+ and uniform_run.diagnostics["minimum_density_eigenvalue"] >= -5e-3
+ and uniform_run.diagnostics["fixed_point_residual"] <= 1e-3
+ and connected_tail <= 5e-2
+ )
+ uniform_payload: dict[str, Any] = {
+ "method": uniform_run.method,
+ "sector": "triplet",
+ "model": asdict(prepared.model),
+ "model_hash": model_hash,
+ "projected_model_hash": projected_model_hash,
+ "bath": asdict(prepared.bath),
+ "point": asdict(point),
+ "bright_gap": prepared.bright_gap,
+ "dimension": prepared.dimension,
+ "source_commit": revision,
+ "converged": physical,
+ "diagnostics": diagnostics,
+ "phase_state": _complex_values(uniform_run.floquet_state),
+ "phase_states": _complex_values(uniform_run.phase_states),
+ "correlation": {
+ "delay": correlation.delays.tolist(),
+ "total": _complex_values(correlation.total),
+ "connected": _complex_values(correlation.connected),
+ "coherent": correlation.coherent.tolist(),
+ },
+ "frequency": heat.frequencies.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(peak) for peak in heat.delta_peaks],
+ "fingerprint": key,
+ }
+ if cache is not None:
+ cache.store(key, uniform_payload)
+ return cache.load(key)
+ return {"complete": True, **uniform_payload}
+
+ def hamiltonian(time: float) -> ComplexMatrix:
+ return np.asarray(
+ prepared.h0
+ + prepared.model.drive_amplitude
+ * np.cos(prepared.model.drive_frequency * time)
+ * prepared.coupling,
+ dtype=np.complex128,
+ )
+
+ ground = diagonalize(prepared.h0).states[:, 0]
+ initial = np.outer(ground, ground.conj())
+ dt = prepared.model.period / point.steps_per_period
+ phase_start = point.steady_periods * point.steps_per_period
+ delay_steps = point.delay_periods * point.steps_per_period
+ total_steps = phase_start + point.steps_per_period + delay_steps
+ backend = PtTempoBackend()
+ run = backend.run(
+ hamiltonian,
+ prepared.coupling,
+ initial,
+ prepared.bath,
+ dt,
+ total_steps,
+ point.memory_steps,
+ point.epsrel,
+ )
+ states = run.result.density_matrices
+ phase_state = states[phase_start]
+ phase_residual = float(
+ np.linalg.norm(phase_state - states[phase_start - point.steps_per_period])
+ )
+ offsets = list(
+ range(0, point.steps_per_period, point.steps_per_period // point.phase_samples)
+ )
+ correlation = backend.period_averaged_correlation(
+ run,
+ prepared.coupling,
+ phase_start,
+ point.steps_per_period,
+ delay_steps,
+ prepared.model.drive_frequency,
+ offsets,
+ )
+ frequencies = np.linspace(0, point.frequency_max, point.frequency_points)
+ heat = heat_current_spectrum(correlation, prepared.bath, frequencies)
+ diagnostics = {
+ **run.result.diagnostics,
+ "phase_residual": phase_residual,
+ "connected_tail_amplitude": float(abs(correlation.connected[-1])),
+ "dt": dt,
+ "tau_max": float(correlation.delays[-1]),
+ "memory_steps": point.memory_steps,
+ "epsrel": point.epsrel,
+ "phase_samples": point.phase_samples,
+ }
+ payload: dict[str, Any] = {
+ "method": "pt_tempo_multitime",
+ "sector": "triplet",
+ "model": asdict(prepared.model),
+ "model_hash": model_hash,
+ "projected_model_hash": projected_model_hash,
+ "bath": asdict(prepared.bath),
+ "point": asdict(point),
+ "bright_gap": prepared.bright_gap,
+ "dimension": prepared.dimension,
+ "source_commit": revision,
+ "converged": bool(
+ run.result.converged
+ and phase_residual < 2e-3
+ and float(diagnostics["connected_tail_amplitude"]) < 5e-2
+ ),
+ "diagnostics": diagnostics,
+ "phase_state": _complex_values(phase_state),
+ "phase_states": _complex_values(
+ states[phase_start : phase_start + point.steps_per_period]
+ ),
+ "correlation": {
+ "delay": correlation.delays.tolist(),
+ "total": _complex_values(correlation.total),
+ "connected": _complex_values(correlation.connected),
+ "coherent": correlation.coherent.tolist(),
+ },
+ "frequency": heat.frequencies.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(peak) for peak in heat.delta_peaks],
+ "fingerprint": key,
+ }
+ if cache is not None:
+ cache.store(key, payload)
+ return cache.load(key)
+ return {"complete": True, **payload}
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/n3_heat.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/n3_heat.py
new file mode 100644
index 000000000..acf7d5a74
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/n3_heat.py
@@ -0,0 +1,430 @@
+"""Reusable reflection-resolved N=3 PT-TEMPO heat-current points."""
+
+from __future__ import annotations
+
+import subprocess
+from dataclasses import asdict, dataclass
+from typing import Any, Literal
+
+import numpy as np
+from numpy.typing import NDArray
+from scipy.integrate import trapezoid
+
+from .backends.pt_tempo import PtTempoBackend
+from .backends.uniform_tempo import UniformTempoBackend, UniformTempoControls
+from .config import BathConfig, DriveNormalization, ModelConfig, Normalization
+from .convergence import ConvergenceCache, fingerprint
+from .heat_current import heat_current_spectrum
+from .models import coupling_operator, drive_operator, ising_hamiltonian
+from .operators import ComplexMatrix
+from .spectra import diagonalize, transitions
+from .symmetry import Sector, project, reflection_sectors
+
+
+@dataclass(frozen=True)
+class N3HeatPoint:
+ """Complete controls for one reflection-resolved N=3 or N=4 calculation."""
+
+ n: Literal[3, 4] = 3
+ j: float = 0.5
+ sector: Literal["even", "odd"] = "even"
+ backend: Literal["oqupy", "uniform_tempo"] = "oqupy"
+ omega: float = 1.0
+ drive_amplitude: float = 0.2
+ drive_ratio: float = 1.0
+ drive_frequency: float | None = None
+ normalization: Normalization = "bounded"
+ drive_normalization: DriveNormalization = "coupling"
+ counterterm: bool = False
+ alpha: float = 0.1
+ cutoff: float = 2.5
+ temperature: float = 0.0
+ steps_per_period: int = 12
+ steady_periods: int = 30
+ delay_periods: int = 3
+ memory_steps: int = 3
+ epsrel: float = 1e-5
+ frequency_max: float = 3.0
+ frequency_points: int = 401
+ phase_samples: int | None = None
+ uniform_auto_nc: bool = True
+ uniform_memory_cutoff: int = 100_000
+ uniform_low_rank_svd: bool = False
+ uniform_truncation: Literal["rel", "abs"] = "rel"
+ uniform_cap_rank: int = 100_000
+ uniform_max_rank: int = 100_000
+
+ def __post_init__(self) -> None:
+ if self.n not in (3, 4):
+ raise ValueError("n must be 3 or 4")
+ if self.sector not in ("even", "odd"):
+ raise ValueError("sector must be 'even' or 'odd'")
+ if self.backend not in ("oqupy", "uniform_tempo"):
+ raise ValueError("backend must be 'oqupy' or 'uniform_tempo'")
+ if self.drive_ratio <= 0:
+ raise ValueError("drive_ratio must be positive")
+ if self.steps_per_period < 2 or self.steady_periods < 1:
+ raise ValueError("insufficient time discretization")
+ if self.delay_periods < 1 or self.memory_steps < 1:
+ raise ValueError("delay and memory controls must be positive")
+ if not 0 < self.epsrel < 1:
+ raise ValueError("epsrel must lie between zero and one")
+ if self.frequency_max <= 0 or self.frequency_points < 2:
+ raise ValueError("invalid frequency grid")
+ if self.phase_samples is not None and (
+ self.phase_samples < 2
+ or self.phase_samples > self.steps_per_period
+ or self.steps_per_period % self.phase_samples != 0
+ ):
+ raise ValueError("phase_samples must divide steps_per_period")
+ if self.uniform_memory_cutoff < 1:
+ raise ValueError("uniform_memory_cutoff must be positive")
+ if self.uniform_truncation not in ("rel", "abs"):
+ raise ValueError("uniform_truncation must be 'rel' or 'abs'")
+ if (
+ self.uniform_cap_rank < 1
+ or self.uniform_max_rank < self.uniform_cap_rank
+ ):
+ raise ValueError("invalid uniform rank limits")
+
+
+@dataclass(frozen=True)
+class PreparedN3:
+ point: N3HeatPoint
+ model: ModelConfig
+ bath: BathConfig
+ sector: Sector
+ h0: ComplexMatrix
+ coupling: ComplexMatrix
+ drive: ComplexMatrix
+ bright_gap: float
+
+ @property
+ def dimension(self) -> int:
+ return int(self.h0.shape[0])
+
+
+def _primary_bright_gap(
+ hamiltonian: ComplexMatrix, coupling: ComplexMatrix
+) -> float:
+ spectrum = diagonalize(hamiltonian)
+ records = transitions(spectrum, spectrum, coupling)
+ candidates = [
+ record.frequency
+ for record in records
+ if record.source == 0 and record.frequency > 1e-12
+ ]
+ if not candidates:
+ raise ValueError("sector has no bright transition from its ground state")
+ # Hermitian eigensolvers may differ in the last one or two binary digits.
+ # Canonicalizing a derived control prevents scientifically identical jobs
+ # from receiving different content-addressed cache keys.
+ return float(f"{min(candidates):.14g}")
+
+
+def prepare_n3_sector(point: N3HeatPoint) -> PreparedN3:
+ """Project the model exactly and select its primary bright resonance."""
+ provisional = ModelConfig(
+ n=point.n,
+ j=point.j,
+ omega=point.omega,
+ drive_amplitude=point.drive_amplitude,
+ drive_frequency=point.omega,
+ normalization=point.normalization,
+ drive_normalization=point.drive_normalization,
+ counterterm=point.counterterm,
+ counterterm_strength=(
+ point.alpha * point.cutoff if point.counterterm else 0.0
+ ),
+ )
+ odd, even = reflection_sectors(point.n)
+ sector = even if point.sector == "even" else odd
+ h0 = project(ising_hamiltonian(provisional), sector)
+ coupling = project(coupling_operator(provisional), sector)
+ drive = project(drive_operator(provisional), sector)
+ bright_gap = _primary_bright_gap(h0, coupling)
+ drive_frequency = (
+ point.drive_frequency
+ if point.drive_frequency is not None
+ else point.drive_ratio * bright_gap
+ )
+ model = ModelConfig(
+ n=point.n,
+ j=point.j,
+ omega=point.omega,
+ drive_amplitude=point.drive_amplitude,
+ drive_frequency=drive_frequency,
+ normalization=point.normalization,
+ drive_normalization=point.drive_normalization,
+ counterterm=point.counterterm,
+ counterterm_strength=provisional.counterterm_strength,
+ )
+ bath = BathConfig(point.alpha, point.cutoff, point.temperature)
+ return PreparedN3(point, model, bath, sector, h0, coupling, drive, bright_gap)
+
+
+def _git_commit() -> str:
+ try:
+ return subprocess.check_output(
+ ["git", "rev-parse", "HEAD"],
+ text=True,
+ stderr=subprocess.DEVNULL,
+ ).strip()
+ except (OSError, subprocess.CalledProcessError):
+ return "unknown"
+
+
+def _complex_values(values: NDArray[np.complex128]) -> dict[str, list[float]]:
+ return {
+ "real": np.real(values).astype(float).tolist(),
+ "imag": np.imag(values).astype(float).tolist(),
+ }
+
+
+def run_n3_heat_point(
+ point: N3HeatPoint,
+ cache: ConvergenceCache | None = None,
+ *,
+ commit: str | None = None,
+) -> dict[str, Any]:
+ """Run or restore one complete PT-TEMPO steady/correlation/heat pipeline."""
+ prepared = prepare_n3_sector(point)
+ revision = _git_commit() if commit is None else commit
+ key = fingerprint(
+ {
+ "experiment": f"n{point.n}_{point.backend}_heat",
+ "point": asdict(point),
+ "model": asdict(prepared.model),
+ "bath": asdict(prepared.bath),
+ },
+ revision,
+ )
+ model_hash = fingerprint(
+ {
+ "model": asdict(prepared.model),
+ "bath": asdict(prepared.bath),
+ "sector": point.sector,
+ },
+ "scientific-model-v1",
+ )
+ projected_model_hash = fingerprint(
+ {
+ "h0": _complex_values(prepared.h0),
+ "coupling": _complex_values(prepared.coupling),
+ "drive": _complex_values(prepared.drive),
+ "drive_amplitude": prepared.model.drive_amplitude,
+ "drive_frequency": prepared.model.drive_frequency,
+ "bath": asdict(prepared.bath),
+ },
+ "projected-open-system-v1",
+ )
+ if cache is not None and cache.contains(key):
+ return cache.load(key)
+
+ model = prepared.model
+ if point.backend == "uniform_tempo":
+ phase_samples = (
+ point.steps_per_period
+ if point.phase_samples is None
+ else point.phase_samples
+ )
+ controls = UniformTempoControls(
+ steps_per_period=point.steps_per_period,
+ tolerance=point.epsrel,
+ phase_samples=phase_samples,
+ delay_periods=point.delay_periods,
+ auto_nc=point.uniform_auto_nc,
+ memory_cutoff=point.uniform_memory_cutoff,
+ low_rank_svd=point.uniform_low_rank_svd,
+ truncation=point.uniform_truncation,
+ cap_rank=point.uniform_cap_rank,
+ max_rank=point.uniform_max_rank,
+ )
+ uniform_run = UniformTempoBackend(
+ tensor_cache_directory=(
+ None if cache is None else cache.directory / "process_tensors"
+ )
+ ).run_periodic(
+ prepared.h0,
+ prepared.coupling,
+ model,
+ prepared.bath,
+ controls,
+ drive_operator=prepared.drive,
+ )
+ correlation = uniform_run.correlation
+ frequencies = np.linspace(
+ 0.0,
+ point.frequency_max,
+ point.frequency_points,
+ )
+ heat = heat_current_spectrum(correlation, prepared.bath, frequencies)
+ connected_tail = float(abs(correlation.connected[-1]))
+ diagnostics = {
+ **uniform_run.diagnostics,
+ **uniform_run.metadata,
+ "phase_residual": uniform_run.diagnostics["fixed_point_residual"],
+ "connected_tail_amplitude": connected_tail,
+ "tau_max": float(correlation.delays[-1]),
+ "epsrel": point.epsrel,
+ "phase_samples": phase_samples,
+ }
+ physical = bool(
+ uniform_run.diagnostics["trace_error"] <= 5e-3
+ and uniform_run.diagnostics["hermiticity_error"] <= 5e-3
+ and uniform_run.diagnostics["minimum_density_eigenvalue"] >= -5e-3
+ and uniform_run.diagnostics["fixed_point_residual"] <= 1e-3
+ and connected_tail <= 5e-2
+ )
+ uniform_payload: dict[str, Any] = {
+ "method": uniform_run.method,
+ "sector": point.sector,
+ "model": asdict(model),
+ "model_hash": model_hash,
+ "projected_model_hash": projected_model_hash,
+ "bath": asdict(prepared.bath),
+ "point": asdict(point),
+ "bright_gap": prepared.bright_gap,
+ "dimension": prepared.dimension,
+ "source_commit": revision,
+ "converged": physical,
+ "diagnostics": diagnostics,
+ "phase_state": _complex_values(uniform_run.floquet_state),
+ "phase_states": _complex_values(uniform_run.phase_states),
+ "correlation": {
+ "delay": correlation.delays.tolist(),
+ "total": _complex_values(correlation.total),
+ "connected": _complex_values(correlation.connected),
+ "coherent": correlation.coherent.tolist(),
+ },
+ "frequency": heat.frequencies.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(peak) for peak in heat.delta_peaks],
+ }
+ uniform_payload["fingerprint"] = key
+ if cache is not None:
+ cache.store(key, uniform_payload)
+ return cache.load(key)
+ return {"complete": True, **uniform_payload}
+
+ def hamiltonian(time: float) -> ComplexMatrix:
+ return np.asarray(
+ prepared.h0
+ + model.drive_amplitude
+ * np.cos(model.drive_frequency * time)
+ * prepared.drive,
+ dtype=np.complex128,
+ )
+
+ ground = diagonalize(prepared.h0).states[:, 0]
+ initial = np.outer(ground, ground.conj())
+ dt = model.period / point.steps_per_period
+ phase_start = point.steady_periods * point.steps_per_period
+ delay_steps = point.delay_periods * point.steps_per_period
+ total_steps = phase_start + point.steps_per_period + delay_steps
+ backend = PtTempoBackend()
+ run = backend.run(
+ hamiltonian,
+ prepared.coupling,
+ initial,
+ prepared.bath,
+ dt,
+ total_steps,
+ point.memory_steps,
+ point.epsrel,
+ )
+ states = run.result.density_matrices
+ phase_state = states[phase_start]
+ phase_states = states[phase_start : phase_start + point.steps_per_period]
+ phase_residual = float(
+ np.linalg.norm(phase_state - states[phase_start - point.steps_per_period])
+ )
+ correlation = backend.period_averaged_correlation(
+ run,
+ prepared.coupling,
+ phase_start,
+ point.steps_per_period,
+ delay_steps,
+ model.drive_frequency,
+ (
+ None
+ if point.phase_samples is None
+ else list(
+ range(
+ 0,
+ point.steps_per_period,
+ point.steps_per_period // point.phase_samples,
+ )
+ )
+ ),
+ )
+ frequencies = np.linspace(0.0, point.frequency_max, point.frequency_points)
+ heat = heat_current_spectrum(correlation, prepared.bath, frequencies)
+ connected_tail = float(abs(correlation.connected[-1]))
+ payload: dict[str, Any] = {
+ "method": "pt_tempo_multitime",
+ "sector": point.sector,
+ "model": asdict(model),
+ "model_hash": model_hash,
+ "projected_model_hash": projected_model_hash,
+ "bath": asdict(prepared.bath),
+ "point": asdict(point),
+ "bright_gap": prepared.bright_gap,
+ "dimension": prepared.dimension,
+ "source_commit": revision,
+ "converged": bool(
+ run.result.converged
+ and phase_residual < 1e-3
+ and connected_tail < 5e-2
+ ),
+ "diagnostics": {
+ **run.result.diagnostics,
+ "phase_residual": phase_residual,
+ "connected_tail_amplitude": connected_tail,
+ "dt": dt,
+ "tau_max": float(correlation.delays[-1]),
+ "memory_steps": point.memory_steps,
+ "epsrel": point.epsrel,
+ "phase_samples": (
+ point.steps_per_period
+ if point.phase_samples is None
+ else point.phase_samples
+ ),
+ },
+ "phase_state": _complex_values(phase_state),
+ "phase_states": _complex_values(phase_states),
+ "correlation": {
+ "delay": correlation.delays.tolist(),
+ "total": _complex_values(correlation.total),
+ "connected": _complex_values(correlation.connected),
+ "coherent": correlation.coherent.tolist(),
+ },
+ "frequency": heat.frequencies.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(peak) for peak in heat.delta_peaks],
+ }
+ payload["fingerprint"] = key
+ if cache is not None:
+ cache.store(key, payload)
+ return cache.load(key)
+ return {"complete": True, **payload}
+
+
+def compare_sector_spectra(
+ even: dict[str, Any], odd: dict[str, Any]
+) -> dict[str, float]:
+ """Return direct differences without interpolating either spectrum."""
+ even_grid = np.asarray(even["frequency"], dtype=float)
+ odd_grid = np.asarray(odd["frequency"], dtype=float)
+ if even_grid.shape != odd_grid.shape or not np.allclose(even_grid, odd_grid):
+ raise ValueError("sector frequency grids do not match")
+ even_heat = np.asarray(even["continuous"], dtype=float)
+ odd_heat = np.asarray(odd["continuous"], dtype=float)
+ difference = even_heat - odd_heat
+ denominator = float(trapezoid(abs(odd_heat), odd_grid)) + 1e-15
+ return {
+ "maximum_absolute_difference": float(np.max(abs(difference))),
+ "normalized_l1_difference": float(
+ trapezoid(abs(difference), even_grid) / denominator
+ ),
+ }
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/operators.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/operators.py
new file mode 100644
index 000000000..7dd506418
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/operators.py
@@ -0,0 +1,70 @@
+"""Spin-half operators with a documented computational-basis convention."""
+
+from __future__ import annotations
+
+import numpy as np
+from numpy.typing import NDArray
+
+ComplexMatrix = NDArray[np.complex128]
+
+_PAULI: dict[str, ComplexMatrix] = {
+ "i": np.eye(2, dtype=np.complex128),
+ "x": np.array([[0, 1], [1, 0]], dtype=np.complex128),
+ "y": np.array([[0, -1j], [1j, 0]], dtype=np.complex128),
+ "z": np.array([[1, 0], [0, -1]], dtype=np.complex128),
+}
+
+
+def pauli(name: str) -> ComplexMatrix:
+ try:
+ return _PAULI[name.lower()].copy()
+ except KeyError as exc:
+ raise ValueError(f"unknown Pauli operator {name!r}") from exc
+
+
+def tensor_product(operators: list[ComplexMatrix]) -> ComplexMatrix:
+ if not operators:
+ raise ValueError("operators must not be empty")
+ result = np.array([[1.0 + 0.0j]])
+ for operator in operators:
+ result = np.kron(result, operator)
+ return result
+
+
+def site_operator(name: str, site: int, n: int) -> ComplexMatrix:
+ if n < 1 or not 0 <= site < n:
+ raise ValueError("site must satisfy 0 <= site < n")
+ factors = [pauli("i") for _ in range(n)]
+ factors[site] = pauli(name)
+ return tensor_product(factors)
+
+
+def product_operator(terms: dict[int, str], n: int) -> ComplexMatrix:
+ factors = [pauli("i") for _ in range(n)]
+ for site, name in terms.items():
+ if not 0 <= site < n:
+ raise ValueError("site must satisfy 0 <= site < n")
+ factors[site] = pauli(name)
+ return tensor_product(factors)
+
+
+def collective_operator(name: str, n: int, eta: float = 1.0) -> ComplexMatrix:
+ if n < 1:
+ raise ValueError("n must be positive")
+ result = np.zeros((2**n, 2**n), dtype=np.complex128)
+ for site in range(n):
+ result += site_operator(name, site, n)
+ return np.asarray(eta * result, dtype=np.complex128)
+
+
+def swap_operator(first: int, second: int, n: int) -> ComplexMatrix:
+ """Permutation matrix that swaps two spin sites."""
+ if first == second or not (0 <= first < n and 0 <= second < n):
+ raise ValueError("swap sites must be distinct valid indices")
+ out = np.zeros((2**n, 2**n), dtype=np.complex128)
+ for column in range(2**n):
+ bits = list(format(column, f"0{n}b"))
+ bits[first], bits[second] = bits[second], bits[first]
+ row = int("".join(bits), 2)
+ out[row, column] = 1
+ return out
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/paper_extension.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/paper_extension.py
new file mode 100644
index 000000000..774fa0516
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/paper_extension.py
@@ -0,0 +1,1054 @@
+"""Resumable publication-grid orchestration for the N=3 extension."""
+
+from __future__ import annotations
+
+import copy
+import json
+import math
+from dataclasses import asdict, replace
+from pathlib import Path
+from typing import Any, Literal, cast
+
+import numpy as np
+from scipy.integrate import trapezoid
+
+from .adaptive import (
+ AdaptiveResult,
+ AdaptiveSchedule,
+ UniformAdaptiveSchedule,
+ run_adaptive,
+ run_uniform_adaptive,
+ run_uniform_compression_audit,
+)
+from .backends.floquet_markov import FloquetMarkovBackend
+from .convergence import ConvergenceCache, atomic_write_result, fingerprint
+from .correlations import superoperator_period_correlation
+from .dark_channels import (
+ dark_candidates,
+ floquet_matrix_elements,
+ harmonic_sum_rule,
+ period_variance,
+)
+from .error_map import audit_grid_manifest, build_error_record
+from .floquet import solve_floquet
+from .heat_current import heat_current_spectrum
+from .model_comparison import model_variants
+from .n2_heat import N2HeatPoint, prepare_n2_triplet, run_n2_heat_point
+from .n3_heat import N3HeatPoint, prepare_n3_sector, run_n3_heat_point
+
+ENGINE_REVISION = "215cc9dbab236d77e0a89e276e3d1ff2b0e26d1f"
+N2_ENGINE_REVISION = "f995eace0d7939b34b599cfbce6baef235f66f7f"
+PHASE_QUADRATURE_EVIDENCE = {
+ "model": "N3 reflection-even, J=0.5, M=12, K=3, epsrel=1e-5",
+ "full_phase_fingerprint": (
+ "b1903593b5ebdbfd0257697086531cf6ff4701fd2deb1153e97a1bb3aa625a0d"
+ ),
+ "three_phase_fingerprint": (
+ "50eeb896cbb9385cb96da4731544cb11a7c2567780709562fe07af2759a07455"
+ ),
+ "correlation_residual": 2.140601839862832e-4,
+ "heat_residual": 6.878849326613947e-4,
+ "maximum_absolute_heat_difference": 3.707806353551828e-5,
+}
+ExactBackend = Literal["uniform_tempo", "oqupy"]
+
+
+def publication_schedule() -> AdaptiveSchedule:
+ return AdaptiveSchedule(
+ memory_steps=(3, 4, 5),
+ steps_per_period=(12, 18),
+ epsrel=(1e-5, 3e-6),
+ state_threshold=8e-2,
+ correlation_threshold=8e-2,
+ heat_threshold=8e-2,
+ phase_threshold=2e-3,
+ trace_threshold=5e-3,
+ )
+
+
+def uniform_publication_schedule() -> UniformAdaptiveSchedule:
+ return UniformAdaptiveSchedule(
+ steps_per_period=(60, 90, 120),
+ tolerances=(3e-7, 1e-7, 3e-8),
+ phase_samples=(3, 15),
+ state_threshold=5e-2,
+ correlation_threshold=8e-2,
+ heat_threshold=8e-2,
+ phase_threshold=1e-3,
+ trace_threshold=5e-3,
+ hermiticity_threshold=5e-3,
+ )
+
+
+def uniform_error_schedule() -> UniformAdaptiveSchedule:
+ """Use a deeper compression ladder for the inexpensive N=2 error grid."""
+ return replace(
+ uniform_publication_schedule(),
+ tolerances=(3e-7, 1e-7, 3e-8, 1e-8, 3e-9),
+ )
+
+
+def n4_pilot_schedule() -> UniformAdaptiveSchedule:
+ """A bounded two-rung gate before spending publication-scale N=4 resources."""
+ return UniformAdaptiveSchedule(
+ steps_per_period=(30, 60),
+ tolerances=(1e-5, 3e-6),
+ phase_samples=(3, 15),
+ state_threshold=8e-2,
+ correlation_threshold=1e-1,
+ heat_threshold=1e-1,
+ phase_threshold=2e-3,
+ trace_threshold=5e-3,
+ hermiticity_threshold=5e-3,
+ )
+
+
+def n2_correlation_delay_periods(alpha: float) -> int:
+ """Choose a weak-coupling correlation window with a fixed decay budget."""
+ if alpha <= 0:
+ raise ValueError("alpha must be positive")
+ return max(4, math.ceil(0.3 / alpha))
+
+
+def _runner(point: N3HeatPoint, cache: ConvergenceCache | None) -> dict[str, Any]:
+ result = run_n3_heat_point(
+ point,
+ cache,
+ commit=ENGINE_REVISION if point.backend == "oqupy" else None,
+ )
+ if point.backend == "uniform_tempo":
+ return result
+ diagnostics = result["diagnostics"]
+ accepted = (
+ float(diagnostics["trace_error"]) < 2e-2
+ and float(diagnostics["minimum_density_eigenvalue"]) > -5e-2
+ and float(diagnostics["phase_residual"]) < 1e-2
+ and float(diagnostics["connected_tail_amplitude"]) < 1e-1
+ )
+ return {**result, "converged": accepted}
+
+
+def _n2_runner(point: N2HeatPoint, cache: ConvergenceCache | None) -> dict[str, Any]:
+ result = run_n2_heat_point(
+ point,
+ cache,
+ commit=N2_ENGINE_REVISION if point.backend == "oqupy" else None,
+ )
+ if point.backend == "uniform_tempo":
+ return result
+ diagnostics = result["diagnostics"]
+ accepted = (
+ float(diagnostics["trace_error"]) < 2e-2
+ and float(diagnostics["minimum_density_eigenvalue"]) > -5e-2
+ and float(diagnostics["phase_residual"]) < 1e-2
+ and float(diagnostics["connected_tail_amplitude"]) < 1e-1
+ )
+ return {**result, "converged": accepted}
+
+
+def n2_publication_schedule() -> AdaptiveSchedule:
+ return AdaptiveSchedule(
+ memory_steps=(4, 5, 6),
+ steps_per_period=(16, 24),
+ epsrel=(1e-5, 3e-6),
+ state_threshold=8e-2,
+ correlation_threshold=8e-2,
+ heat_threshold=8e-2,
+ phase_threshold=2e-3,
+ trace_threshold=5e-3,
+ )
+
+
+def _adaptive_payload(result: AdaptiveResult) -> dict[str, Any]:
+ payload = dict(result.final_result)
+ payload["adaptive_status"] = result.status
+ payload["adaptive_converged"] = result.converged
+ payload["evidence"] = [asdict(item) for item in result.evidence]
+ payload["final_point"] = asdict(result.final_point)
+ payload["failed_parameter"] = result.failed_parameter
+ return payload
+
+
+def _odd_equivalent_payload(
+ reference: dict[str, Any],
+ j: float,
+) -> dict[str, Any]:
+ """Reuse an odd-sector record after proving the projected model is identical."""
+ payload = copy.deepcopy(reference)
+ point = N3HeatPoint(**payload["final_point"])
+ target_point = replace(point, j=j)
+ prepared_reference = prepare_n3_sector(point)
+ prepared_target = prepare_n3_sector(target_point)
+ h0_residual = float(np.linalg.norm(prepared_reference.h0 - prepared_target.h0))
+ coupling_residual = float(
+ np.linalg.norm(prepared_reference.coupling - prepared_target.coupling)
+ )
+ drive_residual = float(
+ np.linalg.norm(prepared_reference.drive - prepared_target.drive)
+ )
+ if (
+ h0_residual > 1e-13
+ or coupling_residual > 1e-13
+ or drive_residual > 1e-13
+ ):
+ raise ValueError("odd-sector projected models are not equivalent")
+
+ source_fingerprint = str(reference["fingerprint"])
+ payload["point"]["j"] = j
+ payload["final_point"]["j"] = j
+ payload["model"]["j"] = j
+ payload["bright_gap"] = prepared_target.bright_gap
+ payload["model_hash"] = fingerprint(
+ {
+ "model": asdict(prepared_target.model),
+ "bath": asdict(prepared_target.bath),
+ "sector": "odd",
+ },
+ "scientific-model-v1",
+ )
+ payload["projected_model_hash"] = reference["projected_model_hash"]
+ payload["fingerprint"] = fingerprint(
+ {
+ "kind": "exact-odd-sector-equivalence",
+ "source_fingerprint": source_fingerprint,
+ "target_j": j,
+ "projected_model_hash": payload["projected_model_hash"],
+ },
+ str(reference.get("source_commit", "unknown")),
+ )
+ payload["numerical_reuse"] = {
+ "reason": "reflection-odd projected Hamiltonian and coupling are J-independent",
+ "source_j": point.j,
+ "source_fingerprint": source_fingerprint,
+ "h0_frobenius_residual": h0_residual,
+ "coupling_frobenius_residual": coupling_residual,
+ "drive_frobenius_residual": drive_residual,
+ }
+ return payload
+
+
+def _complex_values(values: np.ndarray[Any, np.dtype[np.complex128]]) -> dict[str, Any]:
+ return {
+ "real": np.real(values).astype(float).tolist(),
+ "imag": np.imag(values).astype(float).tolist(),
+ }
+
+
+def _complex_array(value: dict[str, Any]) -> np.ndarray[Any, np.dtype[np.complex128]]:
+ return cast(
+ np.ndarray[Any, np.dtype[np.complex128]],
+ np.asarray(value["real"], dtype=float)
+ + 1j * np.asarray(value["imag"], dtype=float),
+ )
+
+
+def _markov_result(point: N3HeatPoint, model_hash: str) -> dict[str, Any]:
+ prepared = prepare_n3_sector(point)
+ model = prepared.model
+
+ def hamiltonian(time: float) -> np.ndarray[Any, np.dtype[np.complex128]]:
+ return np.asarray(
+ prepared.h0
+ + model.drive_amplitude
+ * np.cos(model.drive_frequency * time)
+ * prepared.drive,
+ dtype=np.complex128,
+ )
+
+ backend = FloquetMarkovBackend()
+ run = backend.run(
+ hamiltonian,
+ prepared.coupling,
+ prepared.bath,
+ model.period,
+ point.steps_per_period,
+ harmonic_cutoff=5,
+ )
+ if run.step_maps is None:
+ raise RuntimeError("Floquet-Markov backend returned no step maps")
+ delay_steps = point.delay_periods * point.steps_per_period
+ correlation = superoperator_period_correlation(
+ run.step_maps,
+ run.density_matrices[:-1],
+ prepared.coupling,
+ model.period / point.steps_per_period,
+ delay_steps,
+ model.drive_frequency,
+ )
+ frequencies = np.linspace(0, point.frequency_max, point.frequency_points)
+ heat = heat_current_spectrum(correlation, prepared.bath, frequencies)
+ return {
+ "method": "floquet_markov_qr",
+ "converged": run.converged,
+ "model_hash": model_hash,
+ "model": asdict(model),
+ "bath": asdict(prepared.bath),
+ "diagnostics": run.diagnostics,
+ "phase_state": _complex_values(run.density_matrices[0]),
+ "correlation": {
+ "delay": correlation.delays.tolist(),
+ "connected": _complex_values(correlation.connected),
+ },
+ "frequency": heat.frequencies.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(peak) for peak in heat.delta_peaks],
+ }
+
+
+def _markov_n2_result(point: N2HeatPoint, model_hash: str) -> dict[str, Any]:
+ prepared = prepare_n2_triplet(point)
+ model = prepared.model
+
+ def hamiltonian(time: float) -> np.ndarray[Any, np.dtype[np.complex128]]:
+ return np.asarray(
+ prepared.h0
+ + model.drive_amplitude
+ * np.cos(model.drive_frequency * time)
+ * prepared.coupling,
+ dtype=np.complex128,
+ )
+
+ backend = FloquetMarkovBackend()
+ run = backend.run(
+ hamiltonian,
+ prepared.coupling,
+ prepared.bath,
+ model.period,
+ point.steps_per_period,
+ harmonic_cutoff=5,
+ )
+ if run.step_maps is None:
+ raise RuntimeError("Floquet-Markov backend returned no step maps")
+ delay_steps = point.delay_periods * point.steps_per_period
+ correlation = superoperator_period_correlation(
+ run.step_maps,
+ run.density_matrices[:-1],
+ prepared.coupling,
+ model.period / point.steps_per_period,
+ delay_steps,
+ model.drive_frequency,
+ )
+ frequencies = np.linspace(0, point.frequency_max, point.frequency_points)
+ heat = heat_current_spectrum(correlation, prepared.bath, frequencies)
+ return {
+ "method": "floquet_markov_qr",
+ "converged": run.converged,
+ "model_hash": model_hash,
+ "model": asdict(model),
+ "bath": asdict(prepared.bath),
+ "diagnostics": run.diagnostics,
+ "phase_state": _complex_values(run.density_matrices[0]),
+ "correlation": {
+ "delay": correlation.delays.tolist(),
+ "connected": _complex_values(correlation.connected),
+ },
+ "frequency": heat.frequencies.tolist(),
+ "continuous": heat.continuous.tolist(),
+ "delta_peaks": [asdict(peak) for peak in heat.delta_peaks],
+ }
+
+
+def _dark_diagnostic(result: dict[str, Any]) -> dict[str, Any]:
+ point = N3HeatPoint(**result["final_point"])
+ prepared = prepare_n3_sector(point)
+
+ def hamiltonian(time: float) -> np.ndarray[Any, np.dtype[np.complex128]]:
+ return np.asarray(
+ prepared.h0
+ + prepared.model.drive_amplitude
+ * np.cos(prepared.model.drive_frequency * time)
+ * prepared.drive,
+ dtype=np.complex128,
+ )
+
+ solution = solve_floquet(
+ hamiltonian, prepared.model.period, max(96, 4 * point.steps_per_period)
+ )
+ harmonic_cutoff = min(40, len(solution.step_propagators) // 2 - 1)
+ records = floquet_matrix_elements(
+ solution,
+ prepared.coupling,
+ harmonic_cutoff=harmonic_cutoff,
+ threshold=1e-14,
+ )
+ candidates = dark_candidates(records, relative_threshold=1e-5)
+ strongest = sorted(records, key=lambda item: item.weight, reverse=True)[:24]
+ phase_states = _complex_array(result["phase_states"])
+ heat = np.asarray(result["continuous"], dtype=float)
+ frequencies = np.asarray(result["frequency"], dtype=float)
+ return {
+ "j": point.j,
+ "sector": point.sector,
+ "model_hash": result["model_hash"],
+ "integrated_continuous_heat": float(trapezoid(heat, frequencies)),
+ "period_variance": period_variance(phase_states, prepared.coupling),
+ "harmonic_sum_rule_residual": harmonic_sum_rule(
+ solution, prepared.coupling, harmonic_cutoff
+ ),
+ "harmonic_cutoff": harmonic_cutoff,
+ "strongest_transitions": [asdict(item) for item in strongest],
+ "small_matrix_element_candidates": [
+ {
+ "transition": asdict(item.transition),
+ "relative_weight": item.relative_weight,
+ }
+ for item in candidates[:24]
+ ],
+ }
+
+
+def run_n3_heat_grid(
+ output: Path,
+ cache_directory: Path,
+ *,
+ schedule: AdaptiveSchedule | UniformAdaptiveSchedule | None = None,
+ exact_backend: ExactBackend = "uniform_tempo",
+) -> dict[str, Any]:
+ cache = ConvergenceCache(cache_directory)
+ if exact_backend == "uniform_tempo":
+ active_schedule: AdaptiveSchedule | UniformAdaptiveSchedule = (
+ uniform_publication_schedule() if schedule is None else schedule
+ )
+ if not isinstance(active_schedule, UniformAdaptiveSchedule):
+ raise TypeError("uniform_tempo requires UniformAdaptiveSchedule")
+ else:
+ active_schedule = publication_schedule() if schedule is None else schedule
+ if not isinstance(active_schedule, AdaptiveSchedule):
+ raise TypeError("oqupy requires AdaptiveSchedule")
+ records: list[dict[str, Any]] = []
+ odd_reference: dict[str, Any] | None = None
+ for sector in ("even", "odd"):
+ for j in (0.25, 0.5, 1.0):
+ if (
+ exact_backend == "uniform_tempo"
+ and sector == "odd"
+ and odd_reference is not None
+ ):
+ payload = _odd_equivalent_payload(odd_reference, j)
+ atomic_write_result(output / f"n3_{sector}_j{j:.2f}.json", payload)
+ records.append(payload)
+ continue
+ if exact_backend == "uniform_tempo":
+ uniform_schedule = cast(UniformAdaptiveSchedule, active_schedule)
+ point = N3HeatPoint(
+ j=j,
+ sector=sector,
+ backend="uniform_tempo",
+ steps_per_period=uniform_schedule.steps_per_period[0],
+ epsrel=uniform_schedule.tolerances[0],
+ phase_samples=uniform_schedule.phase_samples[0],
+ uniform_low_rank_svd=True,
+ uniform_truncation="abs",
+ uniform_cap_rank=5_000,
+ uniform_max_rank=10_000,
+ )
+ adaptive = run_uniform_adaptive(
+ point,
+ uniform_schedule,
+ _runner,
+ cache,
+ )
+ else:
+ point = N3HeatPoint(j=j, sector=sector, phase_samples=3)
+ adaptive = run_adaptive(
+ point,
+ cast(AdaptiveSchedule, active_schedule),
+ _runner,
+ cache,
+ )
+ payload = _adaptive_payload(adaptive)
+ if exact_backend == "uniform_tempo" and sector == "odd":
+ odd_reference = payload
+ atomic_write_result(output / f"n3_{sector}_j{j:.2f}.json", payload)
+ records.append(payload)
+ diagnostics = []
+ for item in records:
+ diagnostic = _dark_diagnostic(item)
+ diagnostic["pt_convergence_status"] = item["adaptive_status"]
+ diagnostic["heat_feature_accepted"] = item["adaptive_converged"]
+ diagnostics.append(diagnostic)
+ odd = [item for item in records if item["sector"] == "odd"]
+ odd_difference = None
+ if len(odd) == 3:
+ curves = [np.asarray(item["continuous"], dtype=float) for item in odd]
+ denominator = max(float(np.max(abs(curves[0]))), 1e-15)
+ odd_difference = float(
+ max(np.max(abs(curve - curves[0])) for curve in curves[1:]) / denominator
+ )
+ manifest = {
+ "method": (
+ "uniform_tempo_floquet_multitime"
+ if exact_backend == "uniform_tempo"
+ else "pt_tempo_multitime"
+ ),
+ "exact_backend": exact_backend,
+ "converged": all(item["adaptive_converged"] for item in records),
+ "schedule": asdict(active_schedule),
+ "engine_revision": (
+ records[0].get("source_commit", "unknown")
+ if exact_backend == "uniform_tempo" and records
+ else ENGINE_REVISION
+ ),
+ "phase_quadrature_evidence": (
+ {
+ "source": "per-point adaptive evidence",
+ "phase_samples": list(
+ cast(UniformAdaptiveSchedule, active_schedule).phase_samples
+ ),
+ }
+ if exact_backend == "uniform_tempo"
+ else PHASE_QUADRATURE_EVIDENCE
+ ),
+ "points": records,
+ "dark_diagnostics": diagnostics,
+ "odd_cross_j_relative_max_difference": odd_difference,
+ }
+ atomic_write_result(output / "n3_heat_manifest.json", manifest)
+ return manifest
+
+
+def run_n3_error_map(
+ exact_manifest: Path,
+ output: Path,
+) -> dict[str, Any]:
+ """Compare every converged N=3 production point to the same-model Markov result."""
+ source = json.loads(exact_manifest.read_text(encoding="utf-8"))
+ if not isinstance(source, dict):
+ raise ValueError("N=3 exact manifest must be a JSON object")
+ records: list[dict[str, Any]] = []
+ for exact in source.get("points", []):
+ j = float(exact["model"]["j"])
+ sector = str(exact["sector"])
+ if not bool(exact.get("adaptive_converged", exact.get("converged", False))):
+ records.append(
+ {
+ "j": j,
+ "sector": sector,
+ "status": "resource_ceiling",
+ "metrics": None,
+ }
+ )
+ continue
+ point = N3HeatPoint(**exact["final_point"])
+ markov = _markov_result(point, str(exact["model_hash"]))
+ compatible_exact = {**exact, "converged": True}
+ comparison = build_error_record(compatible_exact, markov)
+ record = {"j": j, "sector": sector, **comparison}
+ records.append(record)
+ atomic_write_result(
+ output / f"n3_error_{sector}_j{j:.2f}.json",
+ {
+ "exact_fingerprint": exact.get("fingerprint"),
+ "exact": compatible_exact,
+ "markov": markov,
+ "comparison": record,
+ },
+ )
+ manifest = {
+ "method": "n3_uniform_tempo_vs_floquet_markov_qr",
+ "exact_backend": source.get("exact_backend"),
+ "model_scope": "same N=3 sector, Hamiltonian, drive and bath parameters",
+ "source_manifest": str(exact_manifest),
+ "converged": bool(records) and all(
+ item["status"] == "converged" for item in records
+ ),
+ "points": records,
+ }
+ atomic_write_result(output / "n3_error_map_manifest.json", manifest)
+ return manifest
+
+
+def run_n4_pilot(
+ output: Path,
+ cache_directory: Path,
+ *,
+ sector: Literal["even", "odd"],
+ j: float = 0.25,
+) -> dict[str, Any]:
+ """Run a convergence-gated N=4 sector point and a same-model Markov check."""
+ schedule = n4_pilot_schedule()
+ point = N3HeatPoint(
+ n=4,
+ j=j,
+ sector=sector,
+ backend="uniform_tempo",
+ alpha=0.05,
+ steps_per_period=schedule.steps_per_period[0],
+ epsrel=schedule.tolerances[0],
+ phase_samples=schedule.phase_samples[0],
+ delay_periods=6 if sector == "even" else 3,
+ uniform_low_rank_svd=True,
+ uniform_truncation="abs",
+ uniform_cap_rank=5_000,
+ uniform_max_rank=10_000,
+ )
+ adaptive = run_uniform_adaptive(
+ point,
+ schedule,
+ _runner,
+ ConvergenceCache(cache_directory),
+ )
+ exact = _adaptive_payload(adaptive)
+ exact["converged"] = adaptive.converged
+ payload: dict[str, Any] = {
+ "method": "n4_uniform_tempo_convergence_pilot",
+ "n": 4,
+ "sector": sector,
+ "j": j,
+ "schedule": asdict(schedule),
+ "adaptive_status": adaptive.status,
+ "converged": adaptive.converged,
+ "failed_parameter": adaptive.failed_parameter,
+ "exact": exact,
+ "markov": None,
+ "comparison": None,
+ }
+ if adaptive.converged:
+ final_point = adaptive.final_point
+ markov = _markov_result(final_point, str(exact["model_hash"]))
+ payload["markov"] = markov
+ payload["comparison"] = build_error_record(exact, markov)
+ atomic_write_result(output / f"n4_{sector}_j{j:.2f}.json", payload)
+ return payload
+
+
+def run_error_grid(
+ output: Path,
+ cache_directory: Path,
+ *,
+ schedule: AdaptiveSchedule | UniformAdaptiveSchedule | None = None,
+ exact_backend: ExactBackend = "uniform_tempo",
+) -> dict[str, Any]:
+ cache = ConvergenceCache(cache_directory)
+ if exact_backend == "uniform_tempo":
+ active_schedule: AdaptiveSchedule | UniformAdaptiveSchedule = (
+ uniform_error_schedule() if schedule is None else schedule
+ )
+ if not isinstance(active_schedule, UniformAdaptiveSchedule):
+ raise TypeError("uniform_tempo requires UniformAdaptiveSchedule")
+ else:
+ active_schedule = n2_publication_schedule() if schedule is None else schedule
+ if not isinstance(active_schedule, AdaptiveSchedule):
+ raise TypeError("oqupy requires AdaptiveSchedule")
+ points: list[dict[str, Any]] = []
+ for alpha in (0.025, 0.05, 0.1):
+ for ratio in (0.75, 1.0, 1.25):
+ if exact_backend == "uniform_tempo":
+ uniform_schedule = cast(UniformAdaptiveSchedule, active_schedule)
+ base = N2HeatPoint(
+ j=0.5,
+ backend="uniform_tempo",
+ alpha=alpha,
+ drive_ratio=ratio,
+ steps_per_period=uniform_schedule.steps_per_period[0],
+ epsrel=uniform_schedule.tolerances[0],
+ phase_samples=uniform_schedule.phase_samples[0],
+ delay_periods=n2_correlation_delay_periods(alpha),
+ uniform_low_rank_svd=True,
+ uniform_truncation="abs",
+ uniform_cap_rank=5_000,
+ uniform_max_rank=10_000,
+ )
+ adaptive = cast(
+ Any,
+ run_uniform_adaptive(
+ cast(Any, base),
+ uniform_schedule,
+ cast(Any, _n2_runner),
+ cache,
+ ),
+ )
+ else:
+ base = N2HeatPoint(
+ j=0.5,
+ alpha=alpha,
+ drive_ratio=ratio,
+ )
+ adaptive = cast(
+ Any,
+ run_adaptive(
+ cast(Any, base),
+ cast(AdaptiveSchedule, active_schedule),
+ cast(Any, _n2_runner),
+ cache,
+ ),
+ )
+ if not adaptive.converged:
+ points.append(
+ {
+ "alpha": alpha,
+ "drive_ratio": ratio,
+ "status": "resource_ceiling",
+ "metrics": None,
+ "failed_parameter": (
+ adaptive.failed_parameter or "steady_state_gate"
+ ),
+ "adaptive_status": adaptive.status,
+ "evidence": [asdict(item) for item in adaptive.evidence],
+ }
+ )
+ continue
+ exact = _adaptive_payload(adaptive)
+ exact["converged"] = True
+ markov = _markov_n2_result(adaptive.final_point, exact["model_hash"])
+ record = build_error_record(exact, markov)
+ points.append({"alpha": alpha, "drive_ratio": ratio, **record})
+ atomic_write_result(
+ output / f"error_a{alpha:.3f}_r{ratio:.2f}.json",
+ {"exact": exact, "markov": markov, "comparison": record},
+ )
+ manifest: dict[str, Any] = {
+ "method": (
+ "uniform_tempo_vs_floquet_markov_qr"
+ if exact_backend == "uniform_tempo"
+ else "pt_tempo_vs_floquet_markov_qr"
+ ),
+ "exact_backend": exact_backend,
+ "model_scope": "N=2 interacting triplet calibration",
+ "points": points,
+ "schedule": asdict(active_schedule),
+ "engine_revision": (
+ "per-point-source-commit"
+ if exact_backend == "uniform_tempo"
+ else N2_ENGINE_REVISION
+ ),
+ "phase_quadrature_evidence": (
+ {
+ "source": "per-point adaptive evidence",
+ "phase_samples": list(
+ cast(UniformAdaptiveSchedule, active_schedule).phase_samples
+ ),
+ }
+ if exact_backend == "uniform_tempo"
+ else PHASE_QUADRATURE_EVIDENCE
+ ),
+ }
+ audit = audit_grid_manifest(manifest)
+ manifest["audit"] = audit
+ manifest["converged"] = audit["masked_points"] == 0
+ atomic_write_result(output / "error_map_manifest.json", manifest)
+ return manifest
+
+
+def run_model_comparison(
+ output: Path,
+ cache_directory: Path,
+ *,
+ schedule: AdaptiveSchedule | UniformAdaptiveSchedule | None = None,
+ exact_backend: ExactBackend = "uniform_tempo",
+ full_kac: bool = False,
+) -> dict[str, Any]:
+ cache = ConvergenceCache(cache_directory)
+ if exact_backend == "uniform_tempo":
+ active_schedule: AdaptiveSchedule | UniformAdaptiveSchedule = (
+ uniform_publication_schedule() if schedule is None else schedule
+ )
+ if not isinstance(active_schedule, UniformAdaptiveSchedule):
+ raise TypeError("uniform_tempo requires UniformAdaptiveSchedule")
+ uniform_schedule = active_schedule
+ bath_point = N3HeatPoint(
+ j=0.5,
+ sector="even",
+ backend="uniform_tempo",
+ steps_per_period=uniform_schedule.steps_per_period[0],
+ epsrel=uniform_schedule.tolerances[0],
+ phase_samples=uniform_schedule.phase_samples[0],
+ uniform_low_rank_svd=True,
+ uniform_truncation="abs",
+ uniform_cap_rank=5_000,
+ uniform_max_rank=10_000,
+ )
+ else:
+ active_schedule = publication_schedule() if schedule is None else schedule
+ if not isinstance(active_schedule, AdaptiveSchedule):
+ raise TypeError("oqupy requires AdaptiveSchedule")
+ bath_point = N3HeatPoint(j=0.5, sector="even", phase_samples=3)
+ prepared = prepare_n3_sector(bath_point)
+ variants = model_variants(
+ n=3,
+ j=0.5,
+ bath=prepared.bath,
+ drive_frequency=prepared.bright_gap,
+ )
+ records: list[dict[str, Any]] = []
+ for variant in variants:
+ point = replace(
+ bath_point,
+ normalization=variant.config.normalization,
+ counterterm=variant.config.counterterm,
+ drive_frequency=variant.config.drive_frequency,
+ )
+ if exact_backend == "uniform_tempo":
+ if variant.config.normalization == "kac" and not full_kac:
+ adaptive = run_uniform_compression_audit(
+ point,
+ cast(UniformAdaptiveSchedule, active_schedule),
+ _runner,
+ cache,
+ )
+ else:
+ adaptive = run_uniform_adaptive(
+ point,
+ cast(UniformAdaptiveSchedule, active_schedule),
+ _runner,
+ cache,
+ )
+ payload = _adaptive_payload(adaptive)
+ else:
+ raw = _runner(point, cache)
+ payload = {
+ **raw,
+ "adaptive_status": "exploratory_unconverged",
+ "adaptive_converged": False,
+ "evidence": [],
+ "final_point": asdict(point),
+ "failed_parameter": "publication_convergence_resource_ceiling",
+ }
+ payload["variant"] = variant.name
+ payload["variant_metadata"] = variant.metadata
+ eta = variant.config.eta
+ payload["continuous_eta_rescaled"] = (
+ np.asarray(payload["continuous"], dtype=float) / eta**2
+ ).tolist()
+ atomic_write_result(output / f"model_{variant.name}.json", payload)
+ records.append(payload)
+ bounded_complete = all(
+ item.get("adaptive_converged") is True
+ for item in records
+ if str(item.get("variant", "")).startswith("bounded_")
+ )
+ kac_locally_audited = all(
+ item.get("adaptive_converged") is True
+ or (
+ item.get("adaptive_status") == "resource_ceiling"
+ and item.get("failed_parameter") == "steps_per_period"
+ and any(
+ evidence.get("parameter") == "epsrel"
+ and evidence.get("passed") is True
+ for evidence in item.get("evidence", [])
+ )
+ )
+ for item in records
+ if str(item.get("variant", "")).startswith("kac_")
+ )
+ locally_complete = (
+ len(records) == 4 and bounded_complete and kac_locally_audited
+ )
+ manifest = {
+ "method": (
+ "uniform_tempo_model_variants"
+ if exact_backend == "uniform_tempo"
+ else "pt_tempo_model_variants"
+ ),
+ "exact_backend": exact_backend,
+ "converged": all(item["adaptive_converged"] for item in records),
+ "complete": len(records) == 4,
+ "locally_complete": locally_complete,
+ "status": (
+ "converged"
+ if records and all(item["adaptive_converged"] for item in records)
+ else (
+ "local_resource_ceiling"
+ if locally_complete
+ else "resource_ceiling"
+ )
+ ),
+ "points": records,
+ "schedule": asdict(active_schedule),
+ "engine_revision": (
+ records[0].get("source_commit", "unknown")
+ if exact_backend == "uniform_tempo" and records
+ else ENGINE_REVISION
+ ),
+ "phase_quadrature_evidence": (
+ {
+ "source": "per-point adaptive evidence",
+ "phase_samples": list(
+ cast(UniformAdaptiveSchedule, active_schedule).phase_samples
+ ),
+ }
+ if exact_backend == "uniform_tempo"
+ else PHASE_QUADRATURE_EVIDENCE
+ ),
+ "resource_policy": {
+ "full_kac": full_kac,
+ "local_default": (
+ "Kac variants stop after compression convergence; use "
+ "--full-kac on a cluster for timestep and phase refinement"
+ ),
+ },
+ }
+ atomic_write_result(output / "model_comparison_manifest.json", manifest)
+ return manifest
+
+
+def audit_paper_results(directory: Path) -> tuple[bool, list[str]]:
+ """Audit the three publication manifests against the declared final gates."""
+
+ def evidence_failures(
+ records: Any,
+ label: str,
+ ) -> list[str]:
+ local: list[str] = []
+ if not isinstance(records, list):
+ return [f"{label} has no convergence evidence"]
+ passed = [item for item in records if item.get("passed") is True]
+ parameters = {item.get("parameter") for item in passed}
+ required = {"epsrel", "steps_per_period", "phase_samples"}
+ if not required.issubset(parameters):
+ local.append(
+ f"{label} lacks passed compression/timestep/phase evidence"
+ )
+ return local
+ timestep_records = [
+ item for item in passed if item.get("parameter") == "steps_per_period"
+ ]
+ compression_steps = {
+ int(item["refined_steps_per_period"])
+ for item in passed
+ if item.get("parameter") == "epsrel"
+ and item.get("refined_steps_per_period") is not None
+ }
+ for item in timestep_records:
+ compared = {
+ int(item["coarse_steps_per_period"]),
+ int(item["refined_steps_per_period"]),
+ }
+ if not compared.issubset(compression_steps):
+ local.append(
+ f"{label} did not converge compression on both timestep grids"
+ )
+ break
+ return local
+
+ def point_failures(point: dict[str, Any], label: str) -> list[str]:
+ local: list[str] = []
+ if point.get("adaptive_status") != "converged":
+ local.append(f"{label} status is not converged")
+ if point.get("adaptive_converged") is not True:
+ local.append(f"{label} adaptive_converged is not true")
+ diagnostics = point.get("diagnostics", {})
+ gates = {
+ "fixed_point_residual": (1e-3, "maximum"),
+ "trace_error": (5e-3, "maximum"),
+ "hermiticity_error": (5e-3, "maximum"),
+ "connected_tail_amplitude": (5e-2, "maximum"),
+ "minimum_density_eigenvalue": (-5e-3, "minimum"),
+ }
+ for name, (threshold, direction) in gates.items():
+ try:
+ value = float(diagnostics[name])
+ except (KeyError, TypeError, ValueError):
+ local.append(f"{label} lacks finite diagnostic {name}")
+ continue
+ if not np.isfinite(value):
+ local.append(f"{label} diagnostic {name} is non-finite")
+ elif direction == "maximum" and value > threshold:
+ local.append(f"{label} diagnostic {name} exceeds {threshold:g}")
+ elif direction == "minimum" and value < threshold:
+ local.append(f"{label} diagnostic {name} is below {threshold:g}")
+ local.extend(evidence_failures(point.get("evidence"), label))
+ return local
+
+ failures: list[str] = []
+ required = (
+ "n3_heat_manifest.json",
+ "error_map_manifest.json",
+ "model_comparison_manifest.json",
+ )
+ import json
+
+ loaded: dict[str, dict[str, Any]] = {}
+ for name in required:
+ path = directory / name
+ if not path.is_file():
+ failures.append(f"missing {name}")
+ continue
+ loaded[name] = json.loads(path.read_text(encoding="utf-8"))
+ if "n3_heat_manifest.json" in loaded:
+ value = loaded["n3_heat_manifest.json"]
+ points = value.get("points", [])
+ if value.get("exact_backend") != "uniform_tempo":
+ failures.append("N=3 manifest does not use uniform_tempo")
+ if value.get("converged") is not True:
+ failures.append("N=3 manifest is not converged")
+ if len(points) != 6:
+ failures.append("N=3 manifest must contain six points")
+ observed = {
+ (point.get("sector"), float(point.get("model", {}).get("j", np.nan)))
+ for point in points
+ }
+ expected = {
+ (sector, j)
+ for sector in ("even", "odd")
+ for j in (0.25, 0.5, 1.0)
+ }
+ if observed != expected:
+ failures.append("N=3 manifest sector/J grid is incomplete")
+ for point in points:
+ label = (
+ f"N=3 {point.get('sector')} "
+ f"J={point.get('model', {}).get('j')}"
+ )
+ failures.extend(point_failures(point, label))
+ if value.get("odd_cross_j_relative_max_difference") is None:
+ failures.append("N=3 odd-sector invariance diagnostic is missing")
+ elif float(value["odd_cross_j_relative_max_difference"]) > 1e-12:
+ failures.append("N=3 odd-sector J-invariance check failed")
+ if "error_map_manifest.json" in loaded:
+ try:
+ value = loaded["error_map_manifest.json"]
+ audit = audit_grid_manifest(value)
+ if value.get("exact_backend") != "uniform_tempo":
+ failures.append("error map does not use uniform_tempo")
+ if audit["masked_points"] != 0 or value.get("converged") is not True:
+ failures.append("error map contains unconverged or masked points")
+ for point in value.get("points", []):
+ label = (
+ f"error grid alpha={point.get('alpha')} "
+ f"ratio={point.get('drive_ratio')}"
+ )
+ metrics = point.get("metrics", {})
+ if set(metrics) != {"trace_distance", "correlation", "heat"}:
+ failures.append(f"{label} lacks the three error metrics")
+ elif not all(np.isfinite(float(item)) for item in metrics.values()):
+ failures.append(f"{label} has a non-finite error metric")
+ failures.extend(
+ evidence_failures(point.get("convergence_evidence"), label)
+ )
+ except ValueError as exc:
+ failures.append(str(exc))
+ if "model_comparison_manifest.json" in loaded:
+ value = loaded["model_comparison_manifest.json"]
+ points = value.get("points", [])
+ if value.get("exact_backend") != "uniform_tempo":
+ failures.append("model comparison does not use uniform_tempo")
+ if len(points) != 4:
+ failures.append("model manifest must contain four variants")
+ if not value.get("complete"):
+ failures.append("model comparison is incomplete")
+ if value.get("locally_complete") is not True:
+ failures.append("model comparison has not reached its declared local endpoint")
+ if len({point.get("variant") for point in points}) != 4:
+ failures.append("model comparison variants are not distinct")
+ for point in points:
+ label = f"model variant {point.get('variant')}"
+ if point.get("adaptive_converged") is True:
+ failures.extend(point_failures(point, label))
+ continue
+ if not str(point.get("variant", "")).startswith("kac_"):
+ failures.append(f"{label} is not converged")
+ continue
+ if (
+ point.get("adaptive_status") != "resource_ceiling"
+ or point.get("failed_parameter") != "steps_per_period"
+ ):
+ failures.append(f"{label} lacks an audited timestep resource ceiling")
+ compression = [
+ item
+ for item in point.get("evidence", [])
+ if item.get("parameter") == "epsrel" and item.get("passed") is True
+ ]
+ if not compression:
+ failures.append(f"{label} lacks passed compression evidence")
+ return not failures, failures
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/plotting.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/plotting.py
new file mode 100644
index 000000000..67abdd80f
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/plotting.py
@@ -0,0 +1,632 @@
+"""Publication-oriented deterministic baseline plots."""
+
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Any
+
+import matplotlib
+
+matplotlib.use("Agg")
+import matplotlib.pyplot as plt
+import numpy as np
+from matplotlib.figure import Figure
+from matplotlib.patches import Circle, Rectangle
+
+from .heat_valve_audit import audit_heat_valve_manifest
+
+
+def _save(figure: Figure, stem: Path) -> None:
+ stem.parent.mkdir(parents=True, exist_ok=True)
+ figure.savefig(
+ stem.with_suffix(".pdf"),
+ bbox_inches="tight",
+ metadata={"Creator": "floquet-if"},
+ )
+ figure.savefig(stem.with_suffix(".png"), dpi=180, bbox_inches="tight")
+ plt.close(figure)
+
+
+def plot_n2(result: dict[str, Any], stem: Path) -> None:
+ rows = result["data"]
+ j = np.array([row["j"] for row in rows])
+ figure, axes = plt.subplots(1, 2, figsize=(9, 3.6))
+ axes[0].plot(j, [row["gap_low"] for row in rows], label=r"$\Delta_{\rm low}$")
+ axes[0].plot(j, [row["gap_high"] for row in rows], label=r"$\Delta_{\rm high}$")
+ axes[0].set(xlabel=r"$J/\Omega$", ylabel=r"gap$/\Omega$")
+ axes[0].legend(frameon=False)
+ axes[1].plot(j, [row["weight_low"] for row in rows], label="low")
+ axes[1].plot(j, [row["weight_high"] for row in rows], label="high")
+ axes[1].set(xlabel=r"$J/\Omega$", ylabel=r"$|\langle f|S_2|i\rangle|^2$")
+ axes[1].legend(frameon=False)
+ figure.suptitle("N=2 interacting triplet — exact diagonalization")
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_n3(result: dict[str, Any], stem: Path) -> None:
+ rows = result["data"]
+ j = np.array([row["j"] for row in rows])
+ gaps = np.array([row["primary_even_gap"] for row in rows])
+ weights = np.array([row["primary_even_weight"] for row in rows])
+ figure, axes = plt.subplots(1, 2, figsize=(9, 3.6))
+ axes[0].loglog(j[j > 0], gaps[j > 0], "o-", label="exact primary gap")
+ asymptotic = 1 / (4 * j[j > 0] ** 2)
+ axes[0].loglog(j[j > 0], asymptotic, "--", label=r"$\Omega^3/(4J^2)$")
+ axes[0].set(xlabel=r"$J/\Omega$", ylabel=r"gap$/\Omega$")
+ axes[0].legend(frameon=False)
+ axes[1].plot(j, weights, "o-", label="reflection-even")
+ axes[1].set(xlabel=r"$J/\Omega$", ylabel="primary bright weight")
+ axes[1].legend(frameon=False)
+ figure.suptitle("N=3 symmetry-resolved collective mode")
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_backend_comparison(result: dict[str, Any], stem: Path) -> None:
+ rows = result["data"]
+ alpha = [row["alpha"] for row in rows]
+ distance = [row["trace_distance"] for row in rows]
+ figure, axis = plt.subplots(figsize=(5.2, 3.7))
+ axis.plot(alpha, distance, "o-", color="#D55E00")
+ axis.set(
+ xlabel=r"bath coupling $\alpha$",
+ ylabel="trace distance",
+ title="Finite-memory IF vs Floquet-Markov\n(both approximate)",
+ )
+ axis.grid(alpha=0.25)
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_heat_spectrum(result: dict[str, Any], stem: Path) -> None:
+ rows = result["data"]
+ frequencies = np.array([row["frequency"] for row in rows])
+ current = np.array([row["continuous"] for row in rows])
+ figure, axis = plt.subplots(figsize=(6.2, 3.8))
+ axis.plot(frequencies, current, color="#0072B2", label="continuous")
+ delta_axis = axis.twinx()
+ peak_frequencies = [peak["frequency"] for peak in result["delta_peaks"]]
+ peak_weights = [peak["weight"] for peak in result["delta_peaks"]]
+ delta_axis.semilogy(
+ peak_frequencies,
+ peak_weights,
+ "D",
+ color="#D55E00",
+ label=r"coherent $\delta$ weight",
+ )
+ delta_axis.set_ylabel(r"analytic $\delta$ weight", color="#D55E00")
+ delta_axis.tick_params(axis="y", colors="#D55E00")
+ method_title = (
+ "PT-TEMPO multitime"
+ if result["method"] == "pt_tempo_multitime"
+ else "Floquet-Markov/QRT"
+ )
+ axis.set(
+ xlabel=r"bath frequency $\omega/\Omega$",
+ ylabel=r"$\bar j(\omega)$",
+ title=f"N=2 heat-current spectrum — {method_title}",
+ )
+ handles, labels = axis.get_legend_handles_labels()
+ delta_handles, delta_labels = delta_axis.get_legend_handles_labels()
+ axis.legend(handles + delta_handles, labels + delta_labels, frameon=False)
+ axis.grid(alpha=0.2)
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_n3_pt_dynamics(result: dict[str, Any], stem: Path) -> None:
+ rows = result["data"]
+ phase = np.array([row["phase_index"] for row in rows]) / len(rows)
+ magnetization = np.array([row["magnetization"] for row in rows])
+ figure, axis = plt.subplots(figsize=(5.5, 3.6))
+ axis.plot(phase, magnetization, "o-", color="#009E73")
+ axis.set(
+ xlabel=r"drive phase $t/T$",
+ ylabel=r"$\langle S_3\rangle$",
+ title="N=3 reflection-even periodic state — PT-TEMPO",
+ )
+ axis.grid(alpha=0.2)
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_n3_sector_heat(manifest: dict[str, Any], stem: Path) -> None:
+ backend_label = (
+ "uniform TEMPO"
+ if manifest.get("exact_backend") == "uniform_tempo"
+ else "PT-TEMPO"
+ )
+ figure, axes = plt.subplots(1, 2, figsize=(10, 3.8), sharey=True)
+ for axis, sector in zip(axes, ("even", "odd"), strict=True):
+ for point in manifest["points"]:
+ if point["sector"] != sector:
+ continue
+ axis.plot(
+ point["frequency"],
+ point["continuous"],
+ "--" if not point["adaptive_converged"] else "-",
+ label=(
+ rf"$J/\Omega={point['model']['j']:g}$ "
+ f"({point.get('adaptive_status', 'converged')})"
+ ),
+ )
+ axis.set(
+ xlabel=r"bath frequency $\omega/\Omega$",
+ title=f"reflection-{sector} — {backend_label}",
+ )
+ axis.grid(alpha=0.2)
+ if axis.lines:
+ axis.legend(frameon=False, fontsize=8)
+ axes[0].set_ylabel(r"continuous $\bar j(\omega)$")
+ qualifier = (
+ "converged grid"
+ if manifest.get("converged")
+ else "dashed curves are resource-limited"
+ )
+ figure.suptitle(rf"$N=3$ symmetry-resolved calorimetry — {qualifier}")
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_odd_sector_difference(manifest: dict[str, Any], stem: Path) -> None:
+ odd = [
+ point
+ for point in manifest["points"]
+ if point["sector"] == "odd"
+ ]
+ figure, axis = plt.subplots(figsize=(6.1, 3.7))
+ if odd:
+ reference = np.asarray(odd[0]["continuous"], dtype=float)
+ frequency = np.asarray(odd[0]["frequency"], dtype=float)
+ for point in odd[1:]:
+ difference = np.asarray(point["continuous"], dtype=float) - reference
+ axis.plot(
+ frequency,
+ difference,
+ label=rf"$J={point['model']['j']:g}$ minus $J={odd[0]['model']['j']:g}$",
+ )
+ axis.axhline(0, color="black", lw=0.7)
+ axis.set(
+ xlabel=r"bath frequency $\omega/\Omega$",
+ ylabel=r"$\Delta\bar j(\omega)$",
+ title=r"Reflection-odd heat spectrum: exact $J$-invariance check",
+ )
+ axis.grid(alpha=0.2)
+ if axis.lines:
+ axis.legend(frameon=False)
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_error_maps(manifest: dict[str, Any], stem: Path) -> None:
+ alphas = [0.025, 0.05, 0.1]
+ ratios = [0.75, 1.0, 1.25]
+ names = (
+ ("trace_distance", r"$D_\rho$"),
+ ("correlation", r"$\epsilon_C$"),
+ ("heat", r"$\epsilon_j$"),
+ )
+ figure, axes = plt.subplots(1, 3, figsize=(11.5, 3.5))
+ for axis, (name, label) in zip(axes, names, strict=True):
+ values = np.full((len(alphas), len(ratios)), np.nan)
+ for point in manifest["points"]:
+ if point["status"] != "converged":
+ continue
+ row = alphas.index(float(point["alpha"]))
+ column = ratios.index(float(point["drive_ratio"]))
+ values[row, column] = point["metrics"][name]
+ image = axis.imshow(values, origin="lower", aspect="auto", cmap="magma")
+ axis.set_xticks(range(len(ratios)), labels=ratios)
+ axis.set_yticks(range(len(alphas)), labels=alphas)
+ axis.set(
+ xlabel=r"$\omega_d/\Delta_g$",
+ ylabel=r"$\alpha$",
+ title=label,
+ )
+ for row in range(len(alphas)):
+ for column in range(len(ratios)):
+ if np.isnan(values[row, column]):
+ text = "masked"
+ elif name == "trace_distance":
+ text = f"{values[row, column]:.4f}"
+ else:
+ text = f"{values[row, column]:.2g}"
+ if np.isnan(values[row, column]):
+ axis.add_patch(
+ Rectangle(
+ (column - 0.5, row - 0.5),
+ 1,
+ 1,
+ fill=False,
+ hatch="///",
+ edgecolor="#777777",
+ linewidth=0.0,
+ )
+ )
+ axis.text(
+ column,
+ row,
+ text,
+ ha="center",
+ va="center",
+ color="black" if np.isnan(values[row, column]) else "white",
+ fontsize=8,
+ )
+ figure.colorbar(image, ax=axis, fraction=0.046)
+ scope = manifest.get("model_scope", "audited calibration grid")
+ exact_label = (
+ "uniform TEMPO"
+ if manifest.get("exact_backend") == "uniform_tempo"
+ else "PT-TEMPO"
+ )
+ figure.suptitle(f"{exact_label} vs Floquet-Markov/QRT — {scope}")
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_n3_error_maps(manifest: dict[str, Any], stem: Path) -> None:
+ """Plot same-parameter N=3 exact-versus-Markov errors by sector and J."""
+ sectors = ("even", "odd")
+ couplings = (0.25, 0.5, 1.0)
+ names = (
+ ("trace_distance", r"$D_\rho$"),
+ ("correlation", r"$\epsilon_C$"),
+ ("heat", r"$\epsilon_j$"),
+ )
+ figure, axes = plt.subplots(1, 3, figsize=(11.5, 3.5))
+ for axis, (name, label) in zip(axes, names, strict=True):
+ values = np.full((len(sectors), len(couplings)), np.nan)
+ for point in manifest["points"]:
+ if point["status"] != "converged":
+ continue
+ row = sectors.index(str(point["sector"]))
+ column = couplings.index(float(point["j"]))
+ values[row, column] = point["metrics"][name]
+ image = axis.imshow(values, origin="upper", aspect="auto", cmap="magma")
+ axis.set_xticks(range(len(couplings)), labels=couplings)
+ axis.set_yticks(range(len(sectors)), labels=sectors)
+ axis.set(xlabel=r"$J/\Omega$", ylabel="reflection sector", title=label)
+ for row in range(len(sectors)):
+ for column in range(len(couplings)):
+ value = values[row, column]
+ axis.text(
+ column,
+ row,
+ "masked" if np.isnan(value) else f"{value:.2g}",
+ ha="center",
+ va="center",
+ color="white",
+ fontsize=8,
+ )
+ figure.colorbar(image, ax=axis, fraction=0.046, pad=0.04)
+ figure.suptitle("N=3 same-model UniformTEMPO versus Floquet-Markov/QRT")
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_n4_pilot_comparison(result: dict[str, Any], stem: Path) -> None:
+ """Plot one convergence-gated N=4 spectrum against its same-model benchmark."""
+ if not result.get("converged") or result.get("markov") is None:
+ raise ValueError("N=4 pilot must converge before plotting a comparison")
+ exact = result["exact"]
+ markov = result["markov"]
+ metrics = result["comparison"]["metrics"]
+ figure, axis = plt.subplots(figsize=(6.5, 3.9))
+ axis.plot(
+ exact["frequency"],
+ exact["continuous"],
+ label="UniformTEMPO",
+ color="#0072B2",
+ )
+ axis.plot(
+ markov["frequency"],
+ markov["continuous"],
+ "--",
+ label="Floquet-Markov/QRT",
+ color="#D55E00",
+ )
+ for peak in exact["delta_peaks"]:
+ frequency = float(peak["frequency"])
+ if frequency <= 3:
+ axis.axvline(frequency, color="black", alpha=0.25, lw=0.7)
+ axis.set(
+ xlim=(0, 3),
+ xlabel=r"bath frequency $\omega/\Omega$",
+ ylabel=r"continuous $\bar j(\omega)$",
+ title=(
+ rf"$N=4$ reflection-{result['sector']}, $J/\Omega={result['j']:g}$"
+ "\n"
+ rf"same-model heat error $\epsilon_j={metrics['heat']:.3g}$"
+ ),
+ )
+ axis.grid(alpha=0.2)
+ axis.legend(frameon=False)
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_dark_diagnostics(manifest: dict[str, Any], stem: Path) -> None:
+ diagnostics = sorted(
+ [
+ item
+ for item in manifest.get("dark_diagnostics", [])
+ if item["sector"] == "even"
+ ],
+ key=lambda item: item["j"],
+ )
+ figure, axes = plt.subplots(1, 2, figsize=(9.5, 3.7))
+ j_values = [item["j"] for item in diagnostics]
+ strongest = [
+ max(
+ (
+ record["weight"]
+ for record in item["strongest_transitions"]
+ if record["source"] != record["target"]
+ ),
+ default=np.nan,
+ )
+ for item in diagnostics
+ ]
+ axes[0].semilogy(j_values, strongest, "o-", color="#0072B2")
+ axes[0].set(
+ xlabel=r"$J/\Omega$",
+ ylabel=r"largest off-diagonal $|S_{\alpha\beta}^{(m)}|^2$",
+ title="Floquet matrix-element diagnostic",
+ )
+ axes[1].plot(
+ j_values,
+ [item["integrated_continuous_heat"] for item in diagnostics],
+ "s-",
+ color="#D55E00",
+ label="integrated heat",
+ )
+ axes[1].plot(
+ j_values,
+ [item["period_variance"] for item in diagnostics],
+ "o--",
+ color="#009E73",
+ label=r"$\overline{\mathrm{Var}(S)}$",
+ )
+ axes[1].set(xlabel=r"$J/\Omega$", title="Heat and collective variance")
+ axes[1].legend(frameon=False)
+ for axis in axes:
+ axis.grid(alpha=0.2)
+ qualifier = "converged heat" if manifest.get("converged") else "provisional heat"
+ figure.suptitle(f"Floquet diagnostics with {qualifier}", fontsize=12)
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_model_variants(manifest: dict[str, Any], stem: Path) -> None:
+ figure, axes = plt.subplots(1, 2, figsize=(10, 3.8))
+ for point in manifest["points"]:
+ style = "-" if point.get("adaptive_converged") else "--"
+ axes[0].plot(
+ point["frequency"], point["continuous"], style, label=point["variant"]
+ )
+ axes[1].plot(
+ point["frequency"],
+ point["continuous_eta_rescaled"],
+ style,
+ label=point["variant"],
+ )
+ axes[0].set(title="Raw heat spectra", ylabel=r"$\bar j(\omega)$")
+ axes[1].set(title=r"Diagnostic $\bar j(\omega)/\eta^2$")
+ for axis in axes:
+ axis.set_xlabel(r"bath frequency $\omega/\Omega$")
+ axis.grid(alpha=0.2)
+ axis.legend(frameon=False, fontsize=8)
+ backend_label = (
+ "uniform TEMPO"
+ if manifest.get("exact_backend") == "uniform_tempo"
+ else "PT-TEMPO"
+ )
+ if manifest.get("converged"):
+ qualifier = "fully converged"
+ elif manifest.get("locally_complete"):
+ qualifier = "bounded converged; Kac compression-audited"
+ else:
+ qualifier = "exploratory"
+ figure.suptitle(
+ f"N=3 normalization/counterterm comparison — {qualifier} {backend_label}"
+ )
+ figure.tight_layout()
+ _save(figure, stem)
+
+
+def plot_heat_valve_hero(manifest: dict[str, Any], stem: Path) -> None:
+ """Render the audited four-panel Floquet heat-valve summary."""
+ audit = audit_heat_valve_manifest(manifest)
+ points = list(manifest.get("points", ()))
+ figure, axes = plt.subplots(2, 2, figsize=(11.2, 8.0))
+ colors = {1: "#0072B2", 2: "#E69F00", 3: "#009E73"}
+
+ for n in (1, 2, 3):
+ rows = sorted(
+ [item for item in points if int(item["point"]["n"]) == n],
+ key=lambda item: float(item["point"]["xi"]),
+ )
+ if not rows:
+ continue
+ xi = np.asarray([item["point"]["xi"] for item in rows], dtype=float)
+ heat = np.asarray(
+ [item["integrated_absolute_heat"] for item in rows],
+ dtype=float,
+ )
+ residue = np.asarray(
+ [item["visible_residue_weight"] for item in rows],
+ dtype=float,
+ )
+ heat_scale = float(np.max(heat)) + 1e-15
+ residue_scale = float(np.max(residue)) + 1e-15
+ style = "-" if all(item.get("converged", False) for item in rows) else ":"
+ axes[0, 0].plot(
+ xi,
+ heat / heat_scale,
+ marker="o",
+ linestyle=style,
+ color=colors[n],
+ label=rf"$N={n}$ heat",
+ )
+ axes[0, 0].plot(
+ xi,
+ residue / residue_scale,
+ marker="s",
+ linestyle="--",
+ color=colors[n],
+ alpha=0.75,
+ label=rf"$N={n}$ residue",
+ )
+ axes[0, 0].set(
+ xlabel=r"$\xi=2A/\omega_d$",
+ ylabel="within-size normalized weight",
+ title="Heat and observable transfer-mode weight",
+ )
+ axes[0, 0].grid(alpha=0.2)
+ axes[0, 0].legend(frameon=False, fontsize=7, ncol=2)
+
+ target: dict[str, Any] | None = None
+ selected_n3 = [
+ item
+ for item in manifest.get("selected_points", ())
+ if int(item["n"]) == 3
+ ]
+ if len(selected_n3) == 3:
+ target_xi = float(selected_n3[1]["xi"])
+ target = next(
+ (
+ item
+ for item in points
+ if int(item["point"]["n"]) == 3
+ and np.isclose(float(item["point"]["xi"]), target_xi)
+ ),
+ None,
+ )
+ if target is None and points:
+ target = points[0]
+
+ unit_axis = axes[0, 1]
+ unit_axis.add_patch(
+ Circle((0, 0), 1, fill=False, color="#777777", linestyle="--")
+ )
+ if target is not None:
+ poles = list(target.get("poles", ()))
+ real = np.asarray(
+ [item["eigenvalue"].get("real", 0.0) for item in poles],
+ dtype=float,
+ )
+ imag = np.asarray(
+ [item["eigenvalue"].get("imag", 0.0) for item in poles],
+ dtype=float,
+ )
+ log_residue = np.log10(
+ np.asarray(
+ [item["residue"]["abs"] for item in poles],
+ dtype=float,
+ )
+ + 1e-15
+ )
+ if len(poles):
+ scatter = unit_axis.scatter(
+ real,
+ imag,
+ c=log_residue,
+ cmap="viridis",
+ edgecolor="black",
+ linewidth=0.3,
+ )
+ figure.colorbar(
+ scatter,
+ ax=unit_axis,
+ label=r"$\log_{10}|A_a|$",
+ fraction=0.046,
+ )
+ unit_axis.set(
+ xlabel=r"$\mathrm{Re}\,\lambda_a$",
+ ylabel=r"$\mathrm{Im}\,\lambda_a$",
+ title=r"Floquet transfer poles ($N=3$ selected minimum)",
+ xlim=(-1.08, 1.08),
+ ylim=(-1.08, 1.08),
+ aspect="equal",
+ )
+ unit_axis.axhline(0, color="#BBBBBB", lw=0.5)
+ unit_axis.axvline(0, color="#BBBBBB", lw=0.5)
+
+ spectrum_axis = axes[1, 0]
+ n3_rows = sorted(
+ [item for item in points if int(item["point"]["n"]) == 3],
+ key=lambda item: float(item["point"]["xi"]),
+ )
+ for index, item in enumerate(n3_rows):
+ role = ("lower flank", "minimum", "upper flank")[min(index, 2)]
+ spectrum_axis.plot(
+ item.get("frequency", ()),
+ item.get("continuous", ()),
+ "-" if item.get("converged", False) else ":",
+ label=rf"{role}, $\xi={float(item['point']['xi']):.2f}$",
+ )
+ if target is not None:
+ for item in target.get("poles", ())[:4]:
+ center = abs(float(item.get("quasifrequency", 0.0)))
+ width = max(float(item.get("decay_rate", 0.0)), 0.0)
+ spectrum_axis.axvline(center, color="#555555", lw=0.7, alpha=0.5)
+ spectrum_axis.axvspan(
+ max(0.0, center - width),
+ center + width,
+ color="#999999",
+ alpha=0.08,
+ )
+ spectrum_axis.set(
+ xlabel=r"bath frequency $\omega/\Omega$",
+ ylabel=r"continuous $\bar j(\omega)$",
+ title="Exact heat spectrum with pole centres/widths",
+ )
+ spectrum_axis.grid(alpha=0.2)
+ if spectrum_axis.lines:
+ spectrum_axis.legend(frameon=False, fontsize=7)
+
+ contrast_axis = axes[1, 1]
+ sizes = np.asarray([1, 2, 3])
+ heat_contrast = np.asarray(
+ [audit.metrics.get(f"heat_contrast_n{n}", np.nan) for n in sizes]
+ )
+ residue_contrast = np.asarray(
+ [
+ 1 / audit.metrics.get(f"residue_ratio_n{n}", np.nan)
+ for n in sizes
+ ]
+ )
+ contrast_axis.bar(
+ sizes - 0.16,
+ heat_contrast,
+ width=0.32,
+ color="#0072B2",
+ label="heat contrast",
+ )
+ contrast_axis.bar(
+ sizes + 0.16,
+ residue_contrast,
+ width=0.32,
+ color="#CC79A7",
+ label="residue contrast",
+ )
+ contrast_axis.axhline(10, color="#D55E00", linestyle="--", label="dark gate")
+ contrast_axis.set(
+ xlabel="system size $N$",
+ ylabel="weaker-flank / minimum",
+ title="Size dependence and tenfold claim gate",
+ xticks=sizes,
+ yscale="log",
+ )
+ contrast_axis.grid(axis="y", alpha=0.2)
+ contrast_axis.legend(frameon=False, fontsize=8)
+
+ title = (
+ "audited dark channel"
+ if audit.dark_channel_passed
+ else "candidate; claim gates not met"
+ )
+ figure.suptitle(f"Pole-resolved Floquet heat valve — {title}")
+ figure.tight_layout()
+ _save(figure, stem)
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/poles.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/poles.py
new file mode 100644
index 000000000..1b308003c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/poles.py
@@ -0,0 +1,189 @@
+"""Observable residues and tracking for Floquet transfer poles."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+import numpy as np
+from numpy.typing import NDArray
+from scipy.optimize import linear_sum_assignment
+
+
+@dataclass(frozen=True)
+class TransferPole:
+ eigenvalue: complex
+ decay_rate: float
+ quasifrequency: float
+ eigenpair_residual: float
+
+
+@dataclass(frozen=True)
+class PoleResidue:
+ pole: TransferPole
+ residue: complex
+
+
+@dataclass(frozen=True)
+class PoleFit:
+ residues: tuple[PoleResidue, ...]
+ reconstruction: NDArray[np.complex128]
+ stroboscopic_delays: NDArray[np.float64]
+ reconstruction_residual: float
+ condition_number: float
+
+
+@dataclass(frozen=True)
+class PoleMatch:
+ previous_index: int
+ current_index: int
+ distance: float
+ ambiguous: bool
+
+
+def transfer_poles(
+ eigenvalues: NDArray[np.complex128],
+ eigenpair_residuals: NDArray[np.float64],
+ period: float,
+ *,
+ steady_tolerance: float = 5e-3,
+) -> tuple[TransferPole, ...]:
+ """Remove the resolved steady pole and convert the rest to rates."""
+ values = np.asarray(eigenvalues, dtype=np.complex128)
+ residuals = np.asarray(eigenpair_residuals, dtype=float)
+ if values.ndim != 1 or residuals.ndim != 1 or values.shape != residuals.shape:
+ raise ValueError("transfer eigenvalues and residuals must be equal vectors")
+ if values.size < 2:
+ raise ValueError("at least one steady and one decaying pole are required")
+ if period <= 0 or steady_tolerance <= 0:
+ raise ValueError("period and steady_tolerance must be positive")
+ if not np.all(np.isfinite(values)) or not np.all(np.isfinite(residuals)):
+ raise ValueError("transfer pole data must be finite")
+ if np.any(residuals < 0):
+ raise ValueError("eigenpair residuals must be nonnegative")
+
+ steady = int(np.argmin(abs(values - 1)))
+ if abs(values[steady] - 1) > steady_tolerance:
+ raise ValueError("transfer spectrum has no resolved steady pole")
+
+ records: list[TransferPole] = []
+ for index, (value, residual) in enumerate(
+ zip(values, residuals, strict=True)
+ ):
+ if index == steady:
+ continue
+ magnitude = float(abs(value))
+ if magnitude <= np.finfo(float).tiny:
+ raise ValueError("zero transfer eigenvalues cannot define finite rates")
+ records.append(
+ TransferPole(
+ eigenvalue=complex(value),
+ decay_rate=float(-np.log(magnitude) / period),
+ quasifrequency=float(np.angle(value) / period),
+ eigenpair_residual=float(residual),
+ )
+ )
+ return tuple(
+ sorted(records, key=lambda item: abs(item.eigenvalue), reverse=True)
+ )
+
+
+def fit_pole_residues(
+ poles: tuple[TransferPole, ...],
+ delays: NDArray[np.float64],
+ connected: NDArray[np.complex128],
+ period: float,
+ max_modes: int,
+) -> PoleFit:
+ """Fit transfer-pole residues to stroboscopic connected correlations."""
+ delay_values = np.asarray(delays, dtype=float)
+ data_values = np.asarray(connected, dtype=np.complex128)
+ if (
+ delay_values.ndim != 1
+ or data_values.ndim != 1
+ or delay_values.shape != data_values.shape
+ ):
+ raise ValueError("delays and connected correlation must be equal vectors")
+ if period <= 0:
+ raise ValueError("period must be positive")
+ if isinstance(max_modes, bool) or max_modes < 1 or max_modes > len(poles):
+ raise ValueError("max_modes must select one or more available poles")
+ if not np.all(np.isfinite(delay_values)) or not np.all(np.isfinite(data_values)):
+ raise ValueError("correlation fit data must be finite")
+ if np.any(delay_values < 0):
+ raise ValueError("delays must be nonnegative")
+
+ scaled = delay_values / period
+ orders = np.rint(scaled).astype(int)
+ mask = np.isclose(scaled, orders, rtol=0.0, atol=1e-8)
+ stroboscopic_delays = delay_values[mask]
+ stroboscopic_orders = orders[mask]
+ stroboscopic_data = data_values[mask]
+ if len(stroboscopic_data) <= max_modes:
+ raise ValueError(
+ "the pole fit requires more stroboscopic samples than modes"
+ )
+
+ selected = poles[:max_modes]
+ design = np.column_stack(
+ [item.eigenvalue**stroboscopic_orders for item in selected]
+ ).astype(np.complex128, copy=False)
+ coefficients, _, _, _ = np.linalg.lstsq(
+ design,
+ stroboscopic_data,
+ rcond=None,
+ )
+ reconstruction = np.asarray(design @ coefficients, dtype=np.complex128)
+ denominator = float(np.sum(abs(stroboscopic_data))) + 1e-15
+ reconstruction_residual = float(
+ np.sum(abs(reconstruction - stroboscopic_data)) / denominator
+ )
+ return PoleFit(
+ residues=tuple(
+ PoleResidue(pole=pole, residue=complex(residue))
+ for pole, residue in zip(selected, coefficients, strict=True)
+ ),
+ reconstruction=reconstruction,
+ stroboscopic_delays=np.asarray(stroboscopic_delays, dtype=float),
+ reconstruction_residual=reconstruction_residual,
+ condition_number=float(np.linalg.cond(design)),
+ )
+
+
+def match_transfer_poles(
+ previous: tuple[TransferPole, ...],
+ current: tuple[TransferPole, ...],
+ *,
+ ambiguity_tolerance: float = 1e-6,
+) -> tuple[PoleMatch, ...]:
+ """Match two transfer spectra by minimum total complex-plane distance."""
+ if ambiguity_tolerance < 0:
+ raise ValueError("ambiguity_tolerance must be nonnegative")
+ if not previous or not current:
+ return ()
+ cost = np.asarray(
+ [
+ [
+ abs(previous_pole.eigenvalue - current_pole.eigenvalue)
+ for current_pole in current
+ ]
+ for previous_pole in previous
+ ],
+ dtype=float,
+ )
+ rows, columns = linear_sum_assignment(cost)
+ records: list[PoleMatch] = []
+ for row, column in zip(rows, columns, strict=True):
+ ordered = np.sort(cost[row])
+ ambiguous = bool(
+ len(ordered) > 1
+ and ordered[1] - ordered[0] <= ambiguity_tolerance
+ )
+ records.append(
+ PoleMatch(
+ previous_index=int(row),
+ current_index=int(column),
+ distance=float(cost[row, column]),
+ ambiguous=ambiguous,
+ )
+ )
+ return tuple(sorted(records, key=lambda item: item.previous_index))
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/pt_experiments.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/pt_experiments.py
new file mode 100644
index 000000000..e0056d51b
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/pt_experiments.py
@@ -0,0 +1,192 @@
+"""Long-running PT-TEMPO baselines kept separate from fast CI experiments."""
+
+from __future__ import annotations
+
+from dataclasses import asdict
+
+import numpy as np
+
+from .backends.pt_tempo import PtTempoBackend
+from .config import BathConfig, ModelConfig
+from .heat_current import heat_current_spectrum
+from .models import coupling_operator, ising_hamiltonian
+from .spectra import diagonalize
+from .symmetry import Sector, n2_sectors, n3_reflection_sectors, project
+
+
+def _projected_model(config: ModelConfig, sector: Sector) -> tuple[np.ndarray, np.ndarray]:
+ return (
+ project(ising_hamiltonian(config), sector),
+ project(coupling_operator(config), sector),
+ )
+
+
+def n2_pt_tempo_heat() -> dict[str, object]:
+ """Non-Markovian N=2 heat spectrum with an explicit memory comparison."""
+ j = 0.5
+ gap = float(np.sqrt(1 + j**2) - j)
+ model = ModelConfig(
+ n=2,
+ j=j,
+ drive_amplitude=0.2,
+ drive_frequency=gap,
+ )
+ bath = BathConfig(alpha=0.1, cutoff=2.5)
+ _, triplet = n2_sectors()
+ h0, coupling = _projected_model(model, triplet)
+
+ def hamiltonian(time: float) -> np.ndarray:
+ return np.asarray(
+ h0
+ + model.drive_amplitude
+ * np.cos(model.drive_frequency * time)
+ * coupling,
+ dtype=np.complex128,
+ )
+
+ ground = diagonalize(h0).states[:, 0]
+ initial = np.outer(ground, ground.conj())
+ period_steps = 16
+ steady_periods = 10
+ delay_periods = 4
+ total_periods = steady_periods + 1 + delay_periods
+ dt = model.period / period_steps
+ backend = PtTempoBackend()
+ reference = backend.run(
+ hamiltonian,
+ coupling,
+ initial,
+ bath,
+ dt,
+ total_periods * period_steps,
+ memory_steps=5,
+ epsrel=1e-5,
+ )
+ shorter_memory = backend.run(
+ hamiltonian,
+ coupling,
+ initial,
+ bath,
+ dt,
+ steady_periods * period_steps,
+ memory_steps=4,
+ epsrel=1e-5,
+ )
+ phase_start = steady_periods * period_steps
+ phase_residual = float(
+ np.linalg.norm(
+ reference.result.density_matrices[phase_start]
+ - reference.result.density_matrices[phase_start - period_steps]
+ )
+ )
+ memory_residual = float(
+ np.linalg.norm(
+ reference.result.density_matrices[phase_start]
+ - shorter_memory.result.density_matrices[-1]
+ )
+ )
+ correlation = backend.period_averaged_correlation(
+ reference,
+ coupling,
+ phase_start,
+ period_steps,
+ delay_periods * period_steps,
+ model.drive_frequency,
+ )
+ frequencies = np.linspace(0, 3, 401)
+ heat = heat_current_spectrum(correlation, bath, frequencies)
+ tail = float(abs(correlation.connected[-1]))
+ converged = (
+ reference.result.converged
+ and phase_residual < 1e-3
+ and memory_residual < 5e-2
+ and tail < 5e-2
+ )
+ return {
+ "method": "pt_tempo_multitime",
+ "converged": converged,
+ "diagnostics": {
+ **reference.result.diagnostics,
+ "phase_residual": phase_residual,
+ "memory_k4_to_k5_residual": memory_residual,
+ "connected_tail_amplitude": tail,
+ "tau_max": float(correlation.delays[-1]),
+ "dt": dt,
+ "memory_steps": 5,
+ "epsrel": 1e-5,
+ },
+ "model": asdict(model),
+ "bath": asdict(bath),
+ "delta_peaks": [asdict(peak) for peak in heat.delta_peaks],
+ "data": [
+ {"frequency": float(frequency), "continuous": float(current)}
+ for frequency, current in zip(
+ heat.frequencies, heat.continuous, strict=True
+ )
+ ],
+ }
+
+
+def n3_pt_tempo_dynamics() -> dict[str, object]:
+ """N=3 reflection-even non-Markovian periodic-state convergence baseline."""
+ model = ModelConfig(
+ n=3,
+ j=0.5,
+ drive_amplitude=0.2,
+ drive_frequency=0.4450418679126287,
+ )
+ bath = BathConfig(alpha=0.1, cutoff=2.5)
+ _, even = n3_reflection_sectors()
+ h0, coupling = _projected_model(model, even)
+
+ def hamiltonian(time: float) -> np.ndarray:
+ return np.asarray(
+ h0
+ + model.drive_amplitude
+ * np.cos(model.drive_frequency * time)
+ * coupling,
+ dtype=np.complex128,
+ )
+
+ ground = diagonalize(h0).states[:, 0]
+ initial = np.outer(ground, ground.conj())
+ period_steps = 12
+ periods = 30
+ dt = model.period / period_steps
+ run = PtTempoBackend().run(
+ hamiltonian,
+ coupling,
+ initial,
+ bath,
+ dt,
+ periods * period_steps,
+ memory_steps=3,
+ epsrel=1e-5,
+ )
+ phase_residual = float(
+ np.linalg.norm(
+ run.result.density_matrices[-1]
+ - run.result.density_matrices[-1 - period_steps]
+ )
+ )
+ magnetization = [
+ float(np.real(np.trace(coupling @ state)))
+ for state in run.result.density_matrices[-1 - period_steps : -1]
+ ]
+ return {
+ "method": "pt_tempo",
+ "converged": run.result.converged and phase_residual < 1e-3,
+ "diagnostics": {
+ **run.result.diagnostics,
+ "phase_residual": phase_residual,
+ "dt": dt,
+ "memory_steps": 3,
+ "epsrel": 1e-5,
+ },
+ "model": asdict(model),
+ "bath": asdict(bath),
+ "data": [
+ {"phase_index": index, "magnetization": value}
+ for index, value in enumerate(magnetization)
+ ],
+ }
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/spectra.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/spectra.py
new file mode 100644
index 000000000..30f32bcc7
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/spectra.py
@@ -0,0 +1,76 @@
+"""Hermitian spectra and symmetry-resolved bright transitions."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+import numpy as np
+from numpy.typing import NDArray
+
+from .operators import ComplexMatrix
+
+
+@dataclass(frozen=True)
+class Spectrum:
+ energies: NDArray[np.float64]
+ states: ComplexMatrix
+
+
+@dataclass(frozen=True)
+class Transition:
+ source: int
+ target: int
+ frequency: float
+ weight: float
+ amplitude: complex
+
+
+def diagonalize(hamiltonian: ComplexMatrix) -> Spectrum:
+ if not np.allclose(hamiltonian, hamiltonian.conj().T, atol=1e-12):
+ raise ValueError("hamiltonian must be Hermitian")
+ energies, states = np.linalg.eigh(hamiltonian)
+ for column in range(states.shape[1]):
+ pivot = int(np.argmax(np.abs(states[:, column])))
+ phase = np.angle(states[pivot, column])
+ states[:, column] *= np.exp(-1j * phase)
+ return Spectrum(energies.astype(np.float64), states)
+
+
+def transitions(
+ source: Spectrum,
+ target: Spectrum,
+ operator: ComplexMatrix,
+ threshold: float = 1e-12,
+) -> list[Transition]:
+ if operator.shape != (target.states.shape[0], source.states.shape[0]):
+ raise ValueError("transition operator has incompatible dimensions")
+ matrix = target.states.conj().T @ operator @ source.states
+ out: list[Transition] = []
+ for target_index in range(len(target.energies)):
+ for source_index in range(len(source.energies)):
+ amplitude = matrix[target_index, source_index]
+ weight = float(abs(amplitude) ** 2)
+ if weight >= threshold:
+ out.append(
+ Transition(
+ source_index,
+ target_index,
+ float(target.energies[target_index] - source.energies[source_index]),
+ weight,
+ complex(amplitude),
+ )
+ )
+ return out
+
+
+def ground_bright_transitions(
+ ground_sector: Spectrum,
+ opposite_sector: Spectrum,
+ cross_operator: ComplexMatrix,
+ threshold: float = 1e-12,
+) -> list[Transition]:
+ candidates = transitions(ground_sector, opposite_sector, cross_operator, threshold)
+ return sorted(
+ [item for item in candidates if item.source == 0 and item.frequency > 0],
+ key=lambda item: item.frequency,
+ )
diff --git a/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/symmetry.py b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/symmetry.py
new file mode 100644
index 000000000..31f770b90
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/src/floquet_if_manybody/symmetry.py
@@ -0,0 +1,76 @@
+"""Exact Hilbert-space symmetry sectors for short open spin chains."""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+import numpy as np
+from numpy.typing import NDArray
+
+from .operators import ComplexMatrix, swap_operator
+
+
+@dataclass(frozen=True)
+class Sector:
+ name: str
+ isometry: ComplexMatrix
+
+ def __post_init__(self) -> None:
+ gram = self.isometry.conj().T @ self.isometry
+ if not np.allclose(gram, np.eye(gram.shape[0]), atol=1e-13):
+ raise ValueError(f"{self.name} isometry is not orthonormal")
+
+ @property
+ def dimension(self) -> int:
+ return int(self.isometry.shape[1])
+
+
+def _eigenspace(operator: ComplexMatrix, eigenvalue: float, name: str) -> Sector:
+ values, vectors = np.linalg.eigh(operator)
+ selected = vectors[:, np.isclose(values, eigenvalue, atol=1e-12)]
+ return Sector(name, selected)
+
+
+def n2_sectors() -> tuple[Sector, Sector]:
+ swap = swap_operator(0, 1, 2)
+ singlet = _eigenspace(swap, -1, "singlet")
+ triplet = _eigenspace(swap, +1, "triplet")
+ return singlet, triplet
+
+
+def n3_reflection_sectors() -> tuple[Sector, Sector]:
+ return reflection_sectors(3)
+
+
+def reflection_sectors(n: int) -> tuple[Sector, Sector]:
+ """Return odd/even sectors of full spatial reflection for an open chain."""
+ if n < 2:
+ raise ValueError("reflection sectors require at least two sites")
+ reflection = np.eye(2**n, dtype=np.complex128)
+ for site in range(n // 2):
+ reflection = swap_operator(site, n - 1 - site, n) @ reflection
+ odd = _eigenspace(reflection, -1, "odd")
+ even = _eigenspace(reflection, +1, "even")
+ return odd, even
+
+
+def n4_reflection_sectors() -> tuple[Sector, Sector]:
+ return reflection_sectors(4)
+
+
+def project(operator: ComplexMatrix, sector: Sector) -> ComplexMatrix:
+ if operator.shape[0] != sector.isometry.shape[0]:
+ raise ValueError("operator and sector dimensions do not match")
+ return sector.isometry.conj().T @ operator @ sector.isometry
+
+
+def cross_project(
+ operator: ComplexMatrix, left: Sector, right: Sector
+) -> NDArray[np.complex128]:
+ return left.isometry.conj().T @ operator @ right.isometry
+
+
+def sector_residual(operator: ComplexMatrix, sector: Sector) -> float:
+ identity = np.eye(operator.shape[0], dtype=np.complex128)
+ projector = sector.isometry @ sector.isometry.conj().T
+ return float(np.linalg.norm((identity - projector) @ operator @ sector.isometry))
diff --git a/tracks/mps/solutions/Ranger-123/tests/heat_valve_fixtures.py b/tracks/mps/solutions/Ranger-123/tests/heat_valve_fixtures.py
new file mode 100644
index 000000000..dfe5be707
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/heat_valve_fixtures.py
@@ -0,0 +1,86 @@
+from __future__ import annotations
+
+from copy import deepcopy
+from typing import Any
+
+
+def valid_heat_valve_manifest() -> dict[str, Any]:
+ selected_points: list[dict[str, Any]] = []
+ points: list[dict[str, Any]] = []
+ flank_heat = {1: 1.0, 2: 2.0, 3: 6.0}
+ for n in (1, 2, 3):
+ for role, xi in zip(
+ ("lower_flank", "minimum", "upper_flank"),
+ (2.0, 2.2, 2.4),
+ strict=True,
+ ):
+ selected_points.append({"n": n, "xi": xi})
+ heat = 0.05 if role == "minimum" else flank_heat[n]
+ residue = 0.05 if role == "minimum" else flank_heat[n]
+ points.append(
+ {
+ "complete": True,
+ "converged": True,
+ "point": {"n": n, "xi": xi},
+ "model": {
+ "n": n,
+ "j": 1.0,
+ "omega": 1.0,
+ "drive_amplitude": 1.5 * xi,
+ "drive_frequency": 3.0,
+ "normalization": "bounded",
+ "drive_normalization": "per_spin",
+ },
+ "bath": {
+ "alpha": 0.05,
+ "cutoff": 2.5,
+ "temperature": 0.0,
+ },
+ "numerics": {
+ "steps_per_period": 60,
+ "tolerance": 1e-6,
+ "phase_samples": 3,
+ "delay_periods": 12,
+ "pole_count": 8,
+ },
+ "diagnostics": {
+ "trace_error": 1e-10,
+ "hermiticity_error": 1e-10,
+ "minimum_density_eigenvalue": 0.01,
+ "fixed_point_residual": 1e-10,
+ "connected_tail": 1e-3,
+ "maximum_eigenpair_residual": 1e-12,
+ "maximum_pole_modulus": 0.9,
+ },
+ "pole_fit": {
+ "reconstruction_residual": 1e-3,
+ "condition_number": 10.0,
+ },
+ "poles": [
+ {
+ "eigenvalue": {
+ "real": 0.85,
+ "imag": 0.1,
+ "abs": 0.9,
+ },
+ "decay_rate": 0.05,
+ "quasifrequency": 0.1,
+ "eigenpair_residual": 1e-12,
+ "residue": {"abs": residue},
+ }
+ ],
+ "frequency": [0.0, 1.0, 2.0, 3.0],
+ "continuous": [0.0, heat, heat / 2, 0.0],
+ "integrated_absolute_heat": heat,
+ "dominant_residue": {"abs": residue},
+ "visible_residue_weight": residue,
+ }
+ )
+ return deepcopy(
+ {
+ "complete": True,
+ "selected_points": selected_points,
+ "points": points,
+ "markov_comparison": {"passed": True},
+ }
+ )
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_adaptive.py b/tracks/mps/solutions/Ranger-123/tests/test_adaptive.py
new file mode 100644
index 000000000..52eb302f3
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_adaptive.py
@@ -0,0 +1,312 @@
+from __future__ import annotations
+
+from dataclasses import asdict
+from pathlib import Path
+from typing import Any
+
+import numpy as np
+
+from floquet_if_manybody.adaptive import (
+ AdaptiveSchedule,
+ UniformAdaptiveSchedule,
+ run_adaptive,
+ run_uniform_adaptive,
+ run_uniform_compression_audit,
+)
+from floquet_if_manybody.convergence import ConvergenceCache, fingerprint
+from floquet_if_manybody.n3_heat import N3HeatPoint
+
+
+def _fake_runner(counter: dict[str, int]):
+ def run(point: N3HeatPoint, cache: ConvergenceCache | None) -> dict[str, Any]:
+ key = fingerprint(asdict(point), "fake")
+ if cache is not None and cache.contains(key):
+ return cache.load(key)
+ counter["calls"] += 1
+ error = (
+ (1 / point.steps_per_period) ** 2
+ + np.exp(-point.memory_steps)
+ + point.epsrel
+ )
+ grid = np.linspace(0, 1, 9)
+ payload: dict[str, Any] = {
+ "fingerprint": key,
+ "complete": True,
+ "converged": True,
+ "diagnostics": {
+ "phase_residual": 1e-5,
+ "trace_error": 1e-8,
+ "minimum_density_eigenvalue": 0.0,
+ "connected_tail_amplitude": 1e-4,
+ },
+ "phase_state": {"real": [1 - error, error], "imag": [0.0, 0.0]},
+ "correlation": {
+ "delay": grid.tolist(),
+ "connected": {
+ "real": (np.exp(-grid) + error).tolist(),
+ "imag": np.zeros_like(grid).tolist(),
+ },
+ },
+ "frequency": grid.tolist(),
+ "continuous": (grid * (1 + error)).tolist(),
+ }
+ if cache is not None:
+ cache.store(key, payload)
+ return cache.load(key)
+ return payload
+
+ return run
+
+
+def test_adaptive_refines_all_controls_and_resumes(tmp_path: Path) -> None:
+ counter = {"calls": 0}
+ runner = _fake_runner(counter)
+ cache = ConvergenceCache(tmp_path)
+ point = N3HeatPoint(
+ steps_per_period=4,
+ memory_steps=1,
+ epsrel=0.1,
+ steady_periods=1,
+ delay_periods=1,
+ frequency_points=9,
+ )
+ schedule = AdaptiveSchedule(
+ memory_steps=(1, 3, 6),
+ steps_per_period=(4, 8, 16),
+ epsrel=(0.1, 0.01, 0.001),
+ state_threshold=0.1,
+ correlation_threshold=0.1,
+ heat_threshold=0.1,
+ )
+ result = run_adaptive(point, schedule, runner, cache)
+ assert result.converged
+ assert result.final_point.memory_steps >= 3
+ assert result.final_point.steps_per_period >= 8
+ assert result.final_point.epsrel <= 0.01
+ assert result.final_point.memory_steps >= 12
+ assert {record.parameter for record in result.evidence} == {
+ "memory_steps",
+ "steps_per_period",
+ "epsrel",
+ }
+ first_calls = counter["calls"]
+ resumed = run_adaptive(point, schedule, runner, cache)
+ assert resumed.converged
+ assert counter["calls"] == first_calls
+
+
+def test_adaptive_reports_resource_ceiling() -> None:
+ counter = {"calls": 0}
+ point = N3HeatPoint(
+ steps_per_period=4,
+ memory_steps=1,
+ epsrel=0.1,
+ steady_periods=1,
+ delay_periods=1,
+ frequency_points=9,
+ )
+ schedule = AdaptiveSchedule(
+ memory_steps=(1, 2),
+ steps_per_period=(4, 8),
+ epsrel=(0.1, 0.05),
+ state_threshold=1e-12,
+ correlation_threshold=1e-12,
+ heat_threshold=1e-12,
+ )
+ result = run_adaptive(point, schedule, _fake_runner(counter), None)
+ assert not result.converged
+ assert result.status == "resource_ceiling"
+ assert result.failed_parameter == "memory_steps"
+
+
+def test_uniform_adaptive_refines_compression_timestep_and_phase() -> None:
+ calls: list[tuple[float, int, int | None]] = []
+
+ def runner(
+ point: N3HeatPoint, cache: ConvergenceCache | None
+ ) -> dict[str, Any]:
+ del cache
+ calls.append((point.epsrel, point.steps_per_period, point.phase_samples))
+ error = point.epsrel + 1 / point.steps_per_period**2 + 0.02 / (
+ point.phase_samples or point.steps_per_period
+ )
+ grid = np.linspace(0, 1, 9)
+ return {
+ "fingerprint": fingerprint(asdict(point), "uniform-fake"),
+ "complete": True,
+ "converged": True,
+ "diagnostics": {
+ "phase_residual": 1e-5,
+ "fixed_point_residual": 1e-5,
+ "trace_error": 1e-8,
+ "hermiticity_error": 1e-8,
+ "minimum_density_eigenvalue": 0.0,
+ "connected_tail_amplitude": 1e-4,
+ "bond_dimension": int(5 - np.log10(point.epsrel)),
+ },
+ "phase_state": {"real": [1 - error, error], "imag": [0.0, 0.0]},
+ "correlation": {
+ "delay": grid.tolist(),
+ "connected": {
+ "real": (np.exp(-grid) + error).tolist(),
+ "imag": np.zeros_like(grid).tolist(),
+ },
+ },
+ "frequency": grid.tolist(),
+ "continuous": (grid * (1 + error)).tolist(),
+ }
+
+ point = N3HeatPoint(
+ backend="uniform_tempo",
+ steps_per_period=12,
+ phase_samples=3,
+ epsrel=1e-3,
+ delay_periods=1,
+ frequency_points=9,
+ )
+ schedule = UniformAdaptiveSchedule(
+ steps_per_period=(12, 18),
+ tolerances=(1e-3, 1e-4),
+ phase_samples=(3, 6),
+ state_threshold=0.1,
+ correlation_threshold=0.1,
+ heat_threshold=0.1,
+ )
+ result = run_uniform_adaptive(point, schedule, runner, None)
+ assert result.converged
+ assert result.final_point.steps_per_period == 18
+ assert result.final_point.epsrel == 1e-4
+ assert result.final_point.phase_samples == 6
+ assert {record.parameter for record in result.evidence} == {
+ "epsrel",
+ "steps_per_period",
+ "phase_samples",
+ }
+ assert [record.parameter for record in result.evidence] == [
+ "epsrel",
+ "epsrel",
+ "steps_per_period",
+ "phase_samples",
+ ]
+ assert all(record.refined_bond_dimension is not None for record in result.evidence)
+ assert calls == [
+ (1e-3, 12, 3),
+ (1e-4, 12, 3),
+ (1e-3, 18, 3),
+ (1e-4, 18, 3),
+ (1e-4, 18, 6),
+ ]
+
+
+def test_uniform_schedule_requires_common_phase_divisors() -> None:
+ with np.testing.assert_raises_regex(ValueError, "phase_samples"):
+ UniformAdaptiveSchedule(
+ steps_per_period=(60, 90),
+ tolerances=(1e-6, 3e-7),
+ phase_samples=(3, 8),
+ )
+
+
+def test_uniform_adaptive_skips_compression_unstable_coarse_grid() -> None:
+ def runner(
+ point: N3HeatPoint, cache: ConvergenceCache | None
+ ) -> dict[str, Any]:
+ del cache
+ compression_scale = 10.0 if point.steps_per_period == 12 else 0.01
+ error = (
+ compression_scale * point.epsrel
+ + 1 / point.steps_per_period**2
+ + 0.001 / (point.phase_samples or 3)
+ )
+ grid = np.linspace(0, 1, 9)
+ return {
+ "fingerprint": fingerprint(asdict(point), "uniform-skip-fake"),
+ "complete": True,
+ "converged": True,
+ "diagnostics": {
+ "phase_residual": 1e-5,
+ "fixed_point_residual": 1e-5,
+ "trace_error": 1e-8,
+ "hermiticity_error": 1e-8,
+ "minimum_density_eigenvalue": 0.0,
+ "connected_tail_amplitude": 1e-4,
+ "bond_dimension": 10,
+ },
+ "phase_state": {"real": [1 - error, error], "imag": [0.0, 0.0]},
+ "correlation": {
+ "delay": grid.tolist(),
+ "connected": {
+ "real": (np.exp(-grid) + error).tolist(),
+ "imag": np.zeros_like(grid).tolist(),
+ },
+ },
+ "frequency": grid.tolist(),
+ "continuous": (grid * (1 + error)).tolist(),
+ }
+
+ point = N3HeatPoint(
+ backend="uniform_tempo",
+ steps_per_period=12,
+ phase_samples=3,
+ epsrel=0.1,
+ delay_periods=1,
+ frequency_points=9,
+ )
+ result = run_uniform_adaptive(
+ point,
+ UniformAdaptiveSchedule(
+ steps_per_period=(12, 18, 24),
+ tolerances=(0.1, 0.01),
+ phase_samples=(3, 6),
+ state_threshold=0.1,
+ correlation_threshold=0.1,
+ heat_threshold=0.1,
+ ),
+ runner,
+ None,
+ )
+ assert result.converged
+ assert result.final_point.steps_per_period == 24
+ assert any(
+ item.parameter == "epsrel"
+ and item.coarse_steps_per_period == 12
+ and not item.passed
+ for item in result.evidence
+ )
+ assert any(
+ item.parameter == "steps_per_period"
+ and item.coarse_steps_per_period == 18
+ and item.refined_steps_per_period == 24
+ and item.passed
+ for item in result.evidence
+ )
+
+
+def test_uniform_compression_audit_never_claims_full_convergence() -> None:
+ point = N3HeatPoint(
+ backend="uniform_tempo",
+ steps_per_period=12,
+ phase_samples=3,
+ epsrel=1e-3,
+ delay_periods=1,
+ frequency_points=9,
+ )
+ result = run_uniform_compression_audit(
+ point,
+ UniformAdaptiveSchedule(
+ steps_per_period=(12, 18),
+ tolerances=(1e-3, 1e-4),
+ phase_samples=(3, 6),
+ state_threshold=0.1,
+ correlation_threshold=0.1,
+ heat_threshold=0.1,
+ ),
+ _fake_runner({"calls": 0}),
+ None,
+ )
+ assert not result.converged
+ assert result.status == "resource_ceiling"
+ assert result.failed_parameter == "steps_per_period"
+ assert len(result.evidence) == 1
+ assert result.evidence[0].parameter == "epsrel"
+ assert result.evidence[0].passed
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_bath.py b/tracks/mps/solutions/Ranger-123/tests/test_bath.py
new file mode 100644
index 000000000..e62b61acc
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_bath.py
@@ -0,0 +1,12 @@
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.bath import bath_correlation
+from floquet_if_manybody.config import BathConfig
+
+
+def test_zero_temperature_ohmic_correlation():
+ bath = BathConfig(alpha=0.05, cutoff=2.5)
+ for time in [0, 0.1, 1.0, 3.0]:
+ expected = bath.alpha * bath.cutoff**2 / (1 + 1j * bath.cutoff * time) ** 2
+ assert_allclose(bath_correlation(time, bath), expected)
+ assert_allclose(bath_correlation(-time, bath), expected.conjugate())
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_cli.py b/tracks/mps/solutions/Ranger-123/tests/test_cli.py
new file mode 100644
index 000000000..62b707b57
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_cli.py
@@ -0,0 +1,70 @@
+import json
+from pathlib import Path
+
+from heat_valve_fixtures import valid_heat_valve_manifest
+
+from floquet_if_manybody.cli import build_parser, main
+
+
+def test_quick_baseline_and_audit(tmp_path):
+ results = tmp_path / "results"
+ figures = tmp_path / "figures"
+ assert main(["baselines", "--output", str(results), "--figures", str(figures), "--quick"]) == 0
+ assert main(["audit", str(results), "--allow-unconverged"]) == 0
+ for path in results.glob("*.json"):
+ payload = json.loads(path.read_text())
+ assert payload["schema_version"] == 1
+ assert payload["config_hash"]
+ assert payload["method"]
+ assert "environment" in payload
+ assert len(list(figures.glob("*.pdf"))) == 4
+ assert len(list(figures.glob("*.png"))) == 4
+
+
+def test_audit_ignores_artifact_provenance(tmp_path) -> None:
+ results = tmp_path / "results"
+ results.mkdir()
+ (results / "ARTIFACT_PROVENANCE.json").write_text(
+ json.dumps({"schema_version": 1, "artifacts": []}),
+ encoding="utf-8",
+ )
+ assert (
+ main(
+ [
+ "baselines",
+ "--output",
+ str(results),
+ "--figures",
+ str(tmp_path / "figures"),
+ "--quick",
+ ]
+ )
+ == 0
+ )
+ assert main(["audit", str(results), "--allow-unconverged"]) == 0
+
+
+def test_publication_commands_default_to_uniform_tempo() -> None:
+ parser = build_parser()
+ for command in ("n3-heat-grid", "error-map", "model-comparison"):
+ arguments = parser.parse_args([command])
+ assert arguments.exact_backend == "uniform_tempo"
+ explicit = parser.parse_args([command, "--exact-backend", "oqupy"])
+ assert explicit.exact_backend == "oqupy"
+
+
+def test_heat_valve_cli_defaults() -> None:
+ arguments = build_parser().parse_args(["heat-valve"])
+ assert arguments.output == Path("results/heat-valve")
+ assert arguments.cache == Path("results/cache/uniform_tempo")
+ assert arguments.figures == Path("figures/heat-valve")
+ assert not arguments.full
+
+
+def test_heat_valve_audit_command_accepts_a_valid_manifest(tmp_path) -> None:
+ manifest = valid_heat_valve_manifest()
+ (tmp_path / "heat_valve_manifest.json").write_text(
+ json.dumps(manifest),
+ encoding="utf-8",
+ )
+ assert main(["heat-valve-audit", str(tmp_path)]) == 0
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_config.py b/tracks/mps/solutions/Ranger-123/tests/test_config.py
new file mode 100644
index 000000000..0a97a9e79
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_config.py
@@ -0,0 +1,25 @@
+import pytest
+
+from floquet_if_manybody.config import ModelConfig, RunConfig
+
+
+def test_default_normalization_and_units():
+ cfg = RunConfig()
+ assert cfg.model.omega == 1.0
+ assert cfg.model.normalization == "bounded"
+ assert cfg.model.eta == 1 / cfg.model.n
+
+
+def test_normalizations():
+ assert ModelConfig(n=3, normalization="bounded").eta == pytest.approx(1 / 3)
+ assert ModelConfig(n=3, normalization="kac").eta == pytest.approx(1 / 3**0.5)
+ assert ModelConfig(n=3, normalization="collective").eta == 1
+
+
+def test_invalid_parameters_rejected():
+ with pytest.raises(ValueError, match="omega"):
+ ModelConfig(omega=0)
+
+
+def test_model_config_accepts_n4():
+ assert ModelConfig(n=4).n == 4
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_convergence.py b/tracks/mps/solutions/Ranger-123/tests/test_convergence.py
new file mode 100644
index 000000000..c929bd0a4
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_convergence.py
@@ -0,0 +1,35 @@
+import numpy as np
+import pytest
+
+from floquet_if_manybody.convergence import (
+ ConvergenceCache,
+ atomic_write_result,
+ curve_residual,
+ fingerprint,
+ state_residual,
+)
+
+
+def test_fingerprint_is_order_independent_and_commit_sensitive():
+ first = fingerprint({"alpha": 0.1, "dt": 0.2}, "abc")
+ second = fingerprint({"dt": 0.2, "alpha": 0.1}, "abc")
+ assert first == second
+ assert first != fingerprint({"alpha": 0.1, "dt": 0.2}, "def")
+
+
+def test_curve_and_state_residuals():
+ grid = np.linspace(0, 1, 11)
+ assert curve_residual(grid, grid, grid, grid) == 0
+ assert state_residual(np.eye(2), np.eye(2)) == 0
+ with pytest.raises(ValueError, match="grid"):
+ curve_residual(np.arange(3.0), np.ones(3), np.arange(4.0), np.ones(4))
+
+
+def test_cache_rejects_incomplete_or_wrong_key(tmp_path):
+ key = fingerprint({"x": 1}, "abc")
+ cache = ConvergenceCache(tmp_path)
+ cache.store(key, {"value": 3})
+ assert cache.load(key)["value"] == 3
+ atomic_write_result(cache.path_for(key), {"fingerprint": key, "complete": False})
+ with pytest.raises(ValueError, match="incomplete"):
+ cache.load(key)
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_correlations.py b/tracks/mps/solutions/Ranger-123/tests/test_correlations.py
new file mode 100644
index 000000000..d82451e4a
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_correlations.py
@@ -0,0 +1,26 @@
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.correlations import coherent_decomposition
+
+
+def test_single_cosine_has_one_coherent_harmonic():
+ steps = 128
+ omega = 1.7
+ amplitude = 0.6
+ period = 2 * np.pi / omega
+ times = np.arange(steps) * period / steps
+ delays = np.linspace(0, 3 * period, 301)
+ coherent, peaks = coherent_decomposition(amplitude * np.cos(omega * times), omega, delays)
+ assert len(peaks) == 1
+ assert peaks[0].harmonic == 1
+ assert_allclose(peaks[0].correlation_weight, amplitude**2 / 2, atol=1e-14)
+ assert_allclose(coherent, amplitude**2 / 2 * np.cos(omega * delays), atol=1e-14)
+
+
+def test_half_period_antisymmetry_removes_even_harmonics():
+ steps = 128
+ times = np.arange(steps) * 2 * np.pi / steps
+ signal = 0.4 * np.cos(times) + 0.1 * np.cos(3 * times)
+ _, peaks = coherent_decomposition(signal, 1.0, times)
+ assert {peak.harmonic for peak in peaks} == {1, 3}
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_dark_channels.py b/tracks/mps/solutions/Ranger-123/tests/test_dark_channels.py
new file mode 100644
index 000000000..c355cb6a7
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_dark_channels.py
@@ -0,0 +1,31 @@
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.dark_channels import (
+ dark_candidates,
+ floquet_matrix_elements,
+ harmonic_sum_rule,
+ period_variance,
+)
+from floquet_if_manybody.floquet import solve_floquet
+
+
+def test_static_system_has_only_zero_harmonic_matrix_elements():
+ hamiltonian = np.diag([-0.2, 0.3]).astype(complex)
+ operator = np.array([[0, 1], [1, 0]], dtype=complex)
+ solution = solve_floquet(lambda _time: hamiltonian, period=1.0, steps=64)
+ records = floquet_matrix_elements(solution, operator, harmonic_cutoff=2, threshold=1e-14)
+ bright = [record for record in records if record.weight > 1e-12]
+ assert {record.harmonic for record in bright} == {0}
+ assert_allclose(sorted(record.weight for record in bright), [1, 1], atol=1e-12)
+ assert harmonic_sum_rule(solution, operator, 2) < 1e-12
+
+
+def test_dark_candidates_and_variance():
+ hamiltonian = np.diag([-0.2, 0.3]).astype(complex)
+ operator = np.diag([1, -1]).astype(complex)
+ solution = solve_floquet(lambda _time: hamiltonian, period=1.0, steps=32)
+ records = floquet_matrix_elements(solution, operator, 1)
+ assert len(dark_candidates(records, 1e-8)) > 0
+ densities = np.repeat(np.eye(2, dtype=complex)[None, :, :] / 2, 8, axis=0)
+ assert_allclose(period_variance(densities, operator), 1)
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_error_map.py b/tracks/mps/solutions/Ranger-123/tests/test_error_map.py
new file mode 100644
index 000000000..db950bcf6
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_error_map.py
@@ -0,0 +1,99 @@
+from __future__ import annotations
+
+from copy import deepcopy
+
+import numpy as np
+import pytest
+
+from floquet_if_manybody.error_map import (
+ audit_grid_manifest,
+ build_error_record,
+ correlation_error,
+ heat_error,
+ trace_distance,
+)
+
+
+def _result(method: str) -> dict[str, object]:
+ return {
+ "method": method,
+ "converged": True,
+ "model_hash": "same",
+ "model": {"normalization": "bounded"},
+ "phase_state": {
+ "real": [[1.0, 0.0], [0.0, 0.0]],
+ "imag": [[0.0, 0.0], [0.0, 0.0]],
+ },
+ "correlation": {
+ "delay": [0.0, 1.0],
+ "connected": {"real": [1.0, 0.5], "imag": [0.0, 0.0]},
+ },
+ "frequency": [0.0, 1.0],
+ "continuous": [0.0, 1.0],
+ "evidence": [],
+ }
+
+
+def test_trace_distance_diagonal_example() -> None:
+ first = np.diag([0.75, 0.25]).astype(complex)
+ second = np.diag([0.5, 0.5]).astype(complex)
+ assert trace_distance(first, second) == pytest.approx(0.25)
+
+
+def test_identical_curves_have_zero_error() -> None:
+ grid = np.linspace(0, 1, 5)
+ curve = np.exp(-grid) + 1j * grid
+ assert correlation_error(grid, curve, grid, curve) == pytest.approx(0.0)
+ assert heat_error(grid, curve.real, grid, curve.real) == pytest.approx(0.0)
+
+
+@pytest.mark.parametrize("field", ["model_hash", "normalization", "frequency"])
+def test_build_record_rejects_incompatible_inputs(field: str) -> None:
+ exact = _result("pt_tempo_multitime")
+ markov = deepcopy(exact)
+ markov["method"] = "floquet_markov_qr"
+ if field == "model_hash":
+ markov["model_hash"] = "different"
+ elif field == "normalization":
+ markov["model"]["normalization"] = "kac" # type: ignore[index]
+ else:
+ markov["frequency"] = [0.0, 2.0]
+ with pytest.raises(ValueError, match=field):
+ build_error_record(exact, markov)
+
+
+def test_build_record_rejects_unconverged_exact_input() -> None:
+ exact = _result("pt_tempo_multitime")
+ exact["converged"] = False
+ with pytest.raises(ValueError, match="converged"):
+ build_error_record(exact, _result("floquet_markov_qr"))
+
+
+@pytest.mark.parametrize(
+ "method",
+ ["pt_tempo_multitime", "uniform_tempo_floquet_multitime"],
+)
+def test_build_record_accepts_approved_process_tensor_methods(method: str) -> None:
+ record = build_error_record(_result(method), _result("floquet_markov_qr"))
+ assert record["status"] == "converged"
+ assert record["exact_method"] == method
+
+
+def test_grid_audit_accepts_explicit_resource_masks() -> None:
+ alphas = (0.025, 0.05, 0.1)
+ ratios = (0.75, 1.0, 1.25)
+ points = [
+ {
+ "alpha": alpha,
+ "drive_ratio": ratio,
+ "status": (
+ "resource_ceiling" if (alpha, ratio) == (0.1, 1.25) else "converged"
+ ),
+ "metrics": None if (alpha, ratio) == (0.1, 1.25) else {"heat": 0.1},
+ }
+ for alpha in alphas
+ for ratio in ratios
+ ]
+ audit = audit_grid_manifest({"points": points}, alphas, ratios)
+ assert audit["complete"]
+ assert audit["masked_points"] == 1
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_fig3_validation.py b/tracks/mps/solutions/Ranger-123/tests/test_fig3_validation.py
new file mode 100644
index 000000000..0dd5b9955
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_fig3_validation.py
@@ -0,0 +1,54 @@
+from __future__ import annotations
+
+import importlib.util
+from pathlib import Path
+
+import numpy as np
+
+
+def _module():
+ path = Path(__file__).parents[1] / "scripts" / "run_fig3_validation.py"
+ spec = importlib.util.spec_from_file_location("run_fig3_validation", path)
+ assert spec is not None and spec.loader is not None
+ module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(module)
+ return module
+
+
+def test_reference_names_match_published_archive() -> None:
+ module = _module()
+ assert "ω_d_1.5" in module._reference_name(1.5)
+ assert module.REFERENCE_FREQUENCY.shape == (3000,)
+ assert np.isclose(module.REFERENCE_FREQUENCY[-1], 15.0)
+
+
+def test_comparison_metrics_separate_shape_and_amplitude() -> None:
+ module = _module()
+ reference = np.exp(-module.REFERENCE_FREQUENCY)
+ metrics = module.comparison_metrics(reference, 2 * reference)
+ assert np.isclose(metrics["continuous_relative_l1"], 0.5)
+ assert np.isclose(metrics["normalized_shape_relative_l1"], 0.0)
+ assert np.isclose(metrics["integrated_magnitude_ratio"], 2.0)
+
+
+def test_plot_summary_writes_both_publication_formats(tmp_path: Path) -> None:
+ module = _module()
+ curve = np.exp(-module.REFERENCE_FREQUENCY)
+ results = []
+ for drive_frequency in (1.0, 1.5, 2.0):
+ results.append(
+ {
+ "model": {"drive_frequency": drive_frequency},
+ "frequency": module.REFERENCE_FREQUENCY.tolist(),
+ "reference_continuous": curve.tolist(),
+ "continuous": curve.tolist(),
+ "delta_peaks": [
+ {"frequency": drive_frequency, "harmonic": 1, "weight": 1.0}
+ ],
+ "metrics": {"normalized_shape_relative_l1": 0.0},
+ }
+ )
+ stem = tmp_path / "summary"
+ module.plot_summary(results, stem)
+ assert stem.with_suffix(".png").stat().st_size > 0
+ assert stem.with_suffix(".pdf").stat().st_size > 0
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_finite_memory.py b/tracks/mps/solutions/Ranger-123/tests/test_finite_memory.py
new file mode 100644
index 000000000..b494a64b9
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_finite_memory.py
@@ -0,0 +1,24 @@
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.backends.finite_memory import FiniteMemoryBackend
+from floquet_if_manybody.config import BathConfig
+
+
+def test_zero_bath_matches_unitary_evolution():
+ h = np.array([[0, 0.4], [0.4, 0]], dtype=complex)
+ coupling = np.diag([1, -1]).astype(complex)
+ rho0 = np.array([[1, 0], [0, 0]], dtype=complex)
+ dt = 0.05
+ result = FiniteMemoryBackend().run(
+ lambda _time: h, coupling, rho0, BathConfig(alpha=0), dt, 10, 2
+ )
+ unitary = expm_for_test(h, 10 * dt)
+ assert_allclose(result.density_matrices[-1], unitary @ rho0 @ unitary.conj().T, atol=1e-12)
+ assert result.diagnostics["trace_error"] < 1e-12
+
+
+def expm_for_test(hamiltonian, time):
+ from scipy.linalg import expm
+
+ return expm(-1j * hamiltonian * time)
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_floquet.py b/tracks/mps/solutions/Ranger-123/tests/test_floquet.py
new file mode 100644
index 000000000..991fe5a96
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_floquet.py
@@ -0,0 +1,30 @@
+import numpy as np
+from numpy.testing import assert_allclose
+from scipy.linalg import expm
+
+from floquet_if_manybody.floquet import solve_floquet
+
+
+def test_static_floquet_matches_matrix_exponential():
+ h = np.array([[0.2, 0.3], [0.3, -0.2]], dtype=complex)
+ period = 1.7
+ solution = solve_floquet(lambda _time: h, period, 32)
+ assert_allclose(solution.propagator, expm(-1j * h * period), atol=1e-13)
+ assert solution.unitarity_residual < 1e-13
+ assert solution.eigen_residual < 1e-12
+ assert np.all(solution.quasienergies >= -np.pi / period)
+ assert np.all(solution.quasienergies < np.pi / period)
+
+
+def test_midpoint_rule_converges_quadratically():
+ period = 2 * np.pi
+
+ def h(t):
+ return np.array([[0.4, 0.2 * np.cos(t)], [0.2 * np.cos(t), -0.4]])
+
+ reference = solve_floquet(h, period, 4096).propagator
+ errors = [
+ np.linalg.norm(solve_floquet(h, period, steps).propagator - reference)
+ for steps in (32, 64)
+ ]
+ assert errors[0] / errors[1] > 3.8
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_floquet_markov.py b/tracks/mps/solutions/Ranger-123/tests/test_floquet_markov.py
new file mode 100644
index 000000000..4e0180ba1
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_floquet_markov.py
@@ -0,0 +1,15 @@
+import numpy as np
+
+from floquet_if_manybody.backends.floquet_markov import FloquetMarkovBackend
+from floquet_if_manybody.config import BathConfig
+
+
+def test_markov_result_is_trace_preserving_and_labeled():
+ h = np.array([[0.5, 0.2], [0.2, -0.5]], dtype=complex)
+ s = np.diag([1, -1]).astype(complex)
+ result = FloquetMarkovBackend().run(
+ lambda _time: h, s, BathConfig(alpha=0.01), 2 * np.pi, 64, 2
+ )
+ assert result.method == "floquet_markov"
+ assert result.diagnostics["trace_error"] < 1e-12
+ assert result.diagnostics["minimum_population"] >= -1e-12
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_heat_current.py b/tracks/mps/solutions/Ranger-123/tests/test_heat_current.py
new file mode 100644
index 000000000..5e05ae22f
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_heat_current.py
@@ -0,0 +1,34 @@
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.config import BathConfig
+from floquet_if_manybody.correlations import CorrelationResult, DeltaCorrelationPeak
+from floquet_if_manybody.heat_current import heat_current_spectrum
+
+
+def test_coherent_delta_peak_is_not_smeared_into_continuum():
+ delays = np.linspace(0, 20, 2001)
+ weight = 0.18
+ frequency = 1.7
+ coherent = weight * np.cos(frequency * delays)
+ correlation = CorrelationResult(
+ delays,
+ coherent.astype(complex),
+ np.zeros_like(delays, dtype=complex),
+ coherent,
+ (DeltaCorrelationPeak(1, frequency, weight),),
+ "analytic_test",
+ {},
+ )
+ bath = BathConfig(alpha=0.05, cutoff=2.5)
+ result = heat_current_spectrum(correlation, bath, np.linspace(0, 4, 101))
+ assert_allclose(result.continuous, 0)
+ expected = (
+ np.pi
+ * bath.alpha
+ * frequency
+ * np.exp(-frequency / bath.cutoff)
+ * frequency
+ * weight
+ )
+ assert_allclose(result.delta_peaks[0].weight, expected)
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_heat_valve.py b/tracks/mps/solutions/Ranger-123/tests/test_heat_valve.py
new file mode 100644
index 000000000..591ce4ddc
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_heat_valve.py
@@ -0,0 +1,193 @@
+from __future__ import annotations
+
+from dataclasses import asdict
+from pathlib import Path
+
+import numpy as np
+import pytest
+from numpy.testing import assert_allclose
+from scipy.special import jn_zeros
+
+import floquet_if_manybody.heat_valve as heat_valve_module
+from floquet_if_manybody.backends.uniform_tempo import UniformTempoResult
+from floquet_if_manybody.convergence import ConvergenceCache
+from floquet_if_manybody.correlations import CorrelationResult
+from floquet_if_manybody.heat_valve import (
+ HeatValvePoint,
+ ValveNumerics,
+ build_heat_valve_manifest,
+ isolated_valve_scan,
+ prepare_heat_valve_point,
+ run_uniform_valve_point,
+)
+
+
+class FakePoleBackend:
+ def __init__(self, **_kwargs: object) -> None:
+ pass
+
+ def run_periodic(
+ self,
+ h0: np.ndarray,
+ coupling: np.ndarray,
+ model: object,
+ _bath: object,
+ controls: object,
+ *,
+ drive_operator: np.ndarray,
+ ) -> UniformTempoResult:
+ assert_allclose(drive_operator, 3 * coupling)
+ dimension = h0.shape[0]
+ period = model.period
+ dt = period / controls.steps_per_period
+ delays = np.arange(controls.delay_steps + 1) * dt
+ eigenvalues = np.array(
+ [1.0, 0.85, 0.75, 0.65, 0.55, 0.45, 0.4, 0.35],
+ dtype=complex,
+ )
+ residues = np.linspace(0.7, 0.1, 7).astype(complex)
+ connected = np.zeros(len(delays), dtype=complex)
+ for index, delay in enumerate(delays):
+ scaled = delay / period
+ if np.isclose(scaled, round(scaled), atol=1e-10):
+ order = round(scaled)
+ connected[index] = np.sum(residues * eigenvalues[1:] ** order)
+ correlation = CorrelationResult(
+ delays=delays,
+ total=connected,
+ connected=connected,
+ coherent=np.zeros(len(delays)),
+ delta_peaks=(),
+ method="uniform_tempo_floquet_multitime",
+ metadata={"dt": dt},
+ )
+ state = np.eye(dimension, dtype=complex) / dimension
+ return UniformTempoResult(
+ method="uniform_tempo_floquet_multitime",
+ floquet_state=state,
+ phase_states=np.repeat(
+ state[None, ...],
+ controls.phase_samples,
+ axis=0,
+ ),
+ correlation=correlation,
+ diagnostics={
+ "trace_error": 1e-12,
+ "hermiticity_error": 1e-12,
+ "minimum_density_eigenvalue": 1 / dimension,
+ "fixed_point_residual": 1e-12,
+ "floquet_transfer_residual": 1e-12,
+ },
+ metadata={
+ "dt": dt,
+ "period_steps": controls.steps_per_period,
+ "phase_samples": controls.phase_samples,
+ "bond_dimension": 2,
+ "tolerance": controls.tolerance,
+ "julia_version": "1.12.6",
+ "uniform_tempo_revision": "test",
+ "manifest_sha256": "a" * 64,
+ "process_tensor_cache_hit": 0,
+ "transfer_dimension": 48,
+ "pole_count": 8,
+ },
+ transfer_eigenvalues=eigenvalues,
+ transfer_eigenpair_residuals=np.full(8, 1e-12),
+ )
+
+
+def test_heat_valve_uses_common_physical_drive_for_all_sizes() -> None:
+ prepared = [
+ prepare_heat_valve_point(HeatValvePoint(n=n, xi=2.2))
+ for n in (1, 2, 3)
+ ]
+ assert_allclose(
+ [item.model.drive_amplitude for item in prepared],
+ [prepared[0].model.drive_frequency * 2.2 / 2] * 3,
+ )
+ assert_allclose(
+ [
+ np.linalg.norm(item.drive) / np.linalg.norm(item.coupling)
+ for item in prepared
+ ],
+ [1, 2, 3],
+ )
+
+
+def test_single_spin_high_frequency_gap_minimum_tracks_first_bessel_zero() -> None:
+ xis = np.linspace(2.2, 2.6, 41)
+ manifest = isolated_valve_scan(
+ HeatValvePoint(
+ n=1,
+ j=0.0,
+ drive_frequency=6.0,
+ xi=float(xi),
+ floquet_steps=360,
+ )
+ for xi in xis
+ )
+ minimum = min(manifest["points"], key=lambda item: item["cat_gap"])
+ assert abs(minimum["xi"] - jn_zeros(0, 1)[0]) <= xis[1] - xis[0]
+
+
+def test_interacting_scan_returns_resolved_cat_diagnostics() -> None:
+ manifest = isolated_valve_scan(
+ HeatValvePoint(n=n, xi=xi, drive_frequency=3.0, floquet_steps=180)
+ for n in (2, 3)
+ for xi in (2.2, 2.4, 2.6)
+ )
+ assert manifest["complete"]
+ assert len(manifest["points"]) == 6
+ for point in manifest["points"]:
+ assert point["cat_overlap"] >= 0.5
+ assert point["cat_gap"] >= 0
+ assert point["cat_brightness"] >= 0
+ assert point["unitarity_residual"] < 1e-10
+ assert point["floquet_eigen_residual"] < 1e-10
+
+
+def test_uniform_valve_point_records_poles_residues_and_fixed_controls(
+ tmp_path: Path,
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ monkeypatch.setattr(
+ heat_valve_module,
+ "UniformTempoBackend",
+ FakePoleBackend,
+ )
+ result = run_uniform_valve_point(
+ HeatValvePoint(n=3, xi=2.4, drive_frequency=3.0),
+ ValveNumerics(
+ steps_per_period=60,
+ tolerance=1e-6,
+ phase_samples=3,
+ delay_periods=12,
+ pole_count=8,
+ ),
+ ConvergenceCache(tmp_path),
+ source_revision="test",
+ )
+ assert result["model"]["drive_frequency"] == 3.0
+ assert result["bath"]["cutoff"] == 2.5
+ assert result["pole_fit"]["reconstruction_residual"] < 0.05
+ assert len(result["poles"]) == 7
+
+
+def test_manifest_selects_minimum_and_two_resolved_flanks() -> None:
+ records = []
+ for n in (1, 2, 3):
+ for xi, gap in ((2.0, 0.2), (2.2, 0.01), (2.4, 0.3)):
+ records.append(
+ {
+ **asdict(HeatValvePoint(n=n, xi=xi)),
+ "cat_overlap": 0.9,
+ "cat_gap": gap,
+ }
+ )
+ manifest = build_heat_valve_manifest(
+ {"complete": True, "points": records}
+ )
+ assert not manifest["complete"]
+ assert [
+ point["xi"] for point in manifest["selected_points"]
+ ] == [2.0, 2.2, 2.4] * 3
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_heat_valve_audit.py b/tracks/mps/solutions/Ranger-123/tests/test_heat_valve_audit.py
new file mode 100644
index 000000000..5f3fa24cd
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_heat_valve_audit.py
@@ -0,0 +1,71 @@
+from __future__ import annotations
+
+from collections.abc import Callable
+from typing import Any
+
+import pytest
+from heat_valve_fixtures import valid_heat_valve_manifest
+
+from floquet_if_manybody.heat_valve_audit import audit_heat_valve_manifest
+
+
+@pytest.mark.parametrize(
+ ("mutation", "failure"),
+ [
+ (
+ lambda manifest: manifest["points"][0]["model"].update(
+ drive_frequency=2.9
+ ),
+ "fixed drive frequency",
+ ),
+ (
+ lambda manifest: manifest["points"][1]["pole_fit"].update(
+ reconstruction_residual=0.08
+ ),
+ "pole reconstruction",
+ ),
+ (
+ lambda manifest: manifest["points"][1].update(
+ integrated_absolute_heat=0.2
+ ),
+ "tenfold heat suppression",
+ ),
+ (
+ lambda manifest: manifest["points"][1].update(
+ visible_residue_weight=0.2
+ ),
+ "tenfold residue suppression",
+ ),
+ (
+ lambda manifest: manifest["points"][1]["poles"][0].update(
+ eigenpair_residual=1e-6
+ ),
+ "eigenpair residual",
+ ),
+ (
+ lambda manifest: manifest["points"][1]["poles"][0][
+ "eigenvalue"
+ ].update(abs=1.01),
+ "unit disk",
+ ),
+ ],
+)
+def test_audit_rejects_unsupported_dark_claim(
+ mutation: Callable[[dict[str, Any]], None],
+ failure: str,
+) -> None:
+ manifest = valid_heat_valve_manifest()
+ mutation(manifest)
+ audit = audit_heat_valve_manifest(manifest)
+ assert not audit.dark_channel_passed
+ assert any(failure in item for item in audit.failures)
+
+
+def test_audit_accepts_fixed_frequency_many_body_valve() -> None:
+ audit = audit_heat_valve_manifest(valid_heat_valve_manifest())
+ assert audit.complete
+ assert audit.dark_channel_passed
+ assert audit.many_body_amplification_passed
+ assert audit.markov_payoff_passed
+ assert audit.failures == ()
+ assert audit.metrics["heat_contrast_n3"] == 120.0
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_influence.py b/tracks/mps/solutions/Ranger-123/tests/test_influence.py
new file mode 100644
index 000000000..ce7704b51
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_influence.py
@@ -0,0 +1,18 @@
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.config import BathConfig
+from floquet_if_manybody.influence import discretize_influence
+
+
+def test_zero_coupling_has_zero_coefficients():
+ coefficients = discretize_influence(BathConfig(alpha=0), 0.1, 3)
+ assert_allclose(coefficients.values, 0, atol=1e-15)
+
+
+def test_small_cell_diagonal_limit():
+ bath = BathConfig(alpha=0.05, cutoff=2.5)
+ dt = 1e-3
+ coefficient = discretize_influence(bath, dt, 1).values[0]
+ assert_allclose(coefficient, 0.5 * bath.alpha * bath.cutoff**2 * dt**2, rtol=2e-3)
+ assert np.imag(coefficient) < 0
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_model_comparison.py b/tracks/mps/solutions/Ranger-123/tests/test_model_comparison.py
new file mode 100644
index 000000000..2cf27a2b7
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_model_comparison.py
@@ -0,0 +1,41 @@
+from __future__ import annotations
+
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.config import BathConfig
+from floquet_if_manybody.model_comparison import (
+ diagnostic_heat_rescaling,
+ model_variants,
+ variant_operators,
+)
+
+
+def test_variants_have_expected_coupling_norms() -> None:
+ variants = model_variants(n=3, j=0.5, bath=BathConfig(alpha=0.1, cutoff=2.5))
+ bounded = next(item for item in variants if item.name == "bounded_no_ct")
+ kac = next(item for item in variants if item.name == "kac_no_ct")
+ _, bounded_s = variant_operators(bounded)
+ _, kac_s = variant_operators(kac)
+ assert_allclose(np.linalg.norm(bounded_s, 2), 1.0)
+ assert_allclose(np.linalg.norm(kac_s, 2), np.sqrt(3))
+
+
+def test_counterterm_difference_is_explicit_s_squared() -> None:
+ bath = BathConfig(alpha=0.1, cutoff=2.5)
+ variants = model_variants(n=3, j=0.5, bath=bath)
+ no_ct = next(item for item in variants if item.name == "bounded_no_ct")
+ with_ct = next(item for item in variants if item.name == "bounded_ct")
+ h0, coupling = variant_operators(no_ct)
+ hct, _ = variant_operators(with_ct)
+ assert_allclose(hct - h0, bath.alpha * bath.cutoff * coupling @ coupling)
+ assert with_ct.metadata["counterterm_strength"] == 0.25
+ assert with_ct.metadata["normalization"] == "bounded"
+
+
+def test_diagnostic_rescaling_never_overwrites_raw_heat() -> None:
+ values = np.array([1.0, 2.0])
+ raw, diagnostic = diagnostic_heat_rescaling(values, eta=1 / 3)
+ assert_allclose(raw, values)
+ assert_allclose(diagnostic, 9 * values)
+ assert not np.shares_memory(raw, values)
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_models.py b/tracks/mps/solutions/Ranger-123/tests/test_models.py
new file mode 100644
index 000000000..cd1bb7675
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_models.py
@@ -0,0 +1,46 @@
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.config import ModelConfig
+from floquet_if_manybody.models import (
+ coupling_operator,
+ drive_operator,
+ ising_hamiltonian,
+)
+
+
+def test_n3_ising_diagonal_is_open_boundary():
+ cfg = ModelConfig(n=3, j=1, omega=1)
+ assert_allclose(
+ ising_hamiltonian(cfg).diagonal(),
+ [-2, 0, 2, 0, 0, 2, 0, -2],
+ )
+
+
+def test_counterterm_has_explicit_physical_coefficient():
+ bare = ModelConfig(n=2, counterterm_strength=0)
+ dressed = ModelConfig(n=2, counterterm=True, counterterm_strength=0.125)
+ s = coupling_operator(bare)
+ assert_allclose(
+ ising_hamiltonian(dressed) - ising_hamiltonian(bare),
+ 0.125 * (s @ s),
+ )
+
+
+def test_per_spin_drive_is_independent_of_bath_normalization() -> None:
+ bounded = ModelConfig(
+ n=3,
+ normalization="bounded",
+ drive_normalization="per_spin",
+ )
+ kac = ModelConfig(
+ n=3,
+ normalization="kac",
+ drive_normalization="per_spin",
+ )
+ assert_allclose(drive_operator(bounded), drive_operator(kac))
+ assert_allclose(drive_operator(bounded), 3 * coupling_operator(bounded))
+
+
+def test_default_drive_operator_preserves_existing_semantics() -> None:
+ config = ModelConfig(n=3, normalization="bounded")
+ assert_allclose(drive_operator(config), coupling_operator(config))
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_n2_heat.py b/tracks/mps/solutions/Ranger-123/tests/test_n2_heat.py
new file mode 100644
index 000000000..1248c564f
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_n2_heat.py
@@ -0,0 +1,26 @@
+from __future__ import annotations
+
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.n2_heat import N2HeatPoint, prepare_n2_triplet
+
+
+def test_n2_triplet_preparation_tracks_exact_low_gap() -> None:
+ prepared = prepare_n2_triplet(N2HeatPoint(j=0.5))
+ assert prepared.dimension == 3
+ assert_allclose(prepared.bright_gap, (1.25) ** 0.5 - 0.5)
+ assert_allclose(prepared.model.drive_frequency, prepared.bright_gap)
+
+
+def test_n2_drive_ratio_and_counterterm_are_explicit() -> None:
+ prepared = prepare_n2_triplet(
+ N2HeatPoint(
+ j=0.5,
+ drive_ratio=1.25,
+ alpha=0.1,
+ cutoff=2.5,
+ counterterm=True,
+ )
+ )
+ assert_allclose(prepared.model.drive_frequency, 1.25 * prepared.bright_gap)
+ assert prepared.model.counterterm_strength == 0.25
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_n3_heat.py b/tracks/mps/solutions/Ranger-123/tests/test_n3_heat.py
new file mode 100644
index 000000000..17bbc92a2
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_n3_heat.py
@@ -0,0 +1,181 @@
+from __future__ import annotations
+
+import numpy as np
+from numpy.testing import assert_allclose
+
+import floquet_if_manybody.n3_heat as n3_heat_module
+from floquet_if_manybody.backends.uniform_tempo import UniformTempoResult
+from floquet_if_manybody.correlations import CorrelationResult
+from floquet_if_manybody.n3_heat import (
+ N3HeatPoint,
+ compare_sector_spectra,
+ prepare_n3_sector,
+ run_n3_heat_point,
+)
+
+
+def test_odd_point_is_j_independent_before_backend() -> None:
+ a = prepare_n3_sector(N3HeatPoint(j=0.25, sector="odd"))
+ b = prepare_n3_sector(N3HeatPoint(j=1.0, sector="odd"))
+ assert_allclose(a.h0, b.h0, atol=1e-13)
+ assert_allclose(a.coupling, b.coupling, atol=1e-13)
+ assert a.dimension == 2
+
+
+def test_default_drive_tracks_sector_bright_gap() -> None:
+ even = prepare_n3_sector(N3HeatPoint(j=0.5, sector="even"))
+ odd = prepare_n3_sector(N3HeatPoint(j=0.5, sector="odd"))
+ assert_allclose(even.bright_gap, 0.4450418679126287, rtol=1e-10)
+ assert_allclose(even.model.drive_frequency, even.bright_gap)
+ assert_allclose(odd.bright_gap, 1.0, atol=1e-13)
+ assert_allclose(odd.model.drive_frequency, 1.0, atol=1e-13)
+
+
+def test_n3_per_spin_drive_projection_differs_from_bounded_bath() -> None:
+ prepared = prepare_n3_sector(
+ N3HeatPoint(
+ j=0.5,
+ sector="even",
+ drive_normalization="per_spin",
+ )
+ )
+ assert_allclose(prepared.drive, 3 * prepared.coupling)
+
+
+def test_derived_drive_frequency_is_stable_at_cache_precision() -> None:
+ prepared = prepare_n3_sector(N3HeatPoint(j=0.5, sector="even"))
+ assert prepared.bright_gap == 0.44504186791263
+
+
+def test_drive_ratio_and_counterterm_are_explicit() -> None:
+ prepared = prepare_n3_sector(
+ N3HeatPoint(
+ j=0.5,
+ sector="even",
+ drive_ratio=1.25,
+ alpha=0.1,
+ cutoff=2.5,
+ counterterm=True,
+ )
+ )
+ assert_allclose(prepared.model.drive_frequency, 1.25 * prepared.bright_gap)
+ assert prepared.model.counterterm_strength == 0.25
+
+
+def test_phase_sample_count_must_divide_period_steps() -> None:
+ with np.testing.assert_raises_regex(ValueError, "phase_samples"):
+ N3HeatPoint(steps_per_period=12, phase_samples=5)
+
+
+def test_uniform_backend_controls_are_explicit() -> None:
+ point = N3HeatPoint(
+ backend="uniform_tempo",
+ steps_per_period=60,
+ phase_samples=3,
+ epsrel=1e-7,
+ uniform_auto_nc=False,
+ uniform_memory_cutoff=500,
+ uniform_low_rank_svd=True,
+ uniform_truncation="abs",
+ uniform_cap_rank=400,
+ uniform_max_rank=800,
+ )
+ assert point.backend == "uniform_tempo"
+ assert point.uniform_memory_cutoff == 500
+ assert point.uniform_truncation == "abs"
+
+
+def test_backend_label_is_validated() -> None:
+ with np.testing.assert_raises_regex(ValueError, "backend"):
+ N3HeatPoint(backend="unknown") # type: ignore[arg-type]
+
+
+def test_uniform_backend_routes_through_existing_heat_transform(monkeypatch) -> None:
+ class FakeUniformBackend:
+ def __init__(self, **kwargs) -> None:
+ assert kwargs["tensor_cache_directory"] is None
+
+ def run_periodic(
+ self,
+ h0,
+ coupling,
+ model,
+ bath,
+ controls,
+ *,
+ drive_operator=None,
+ ):
+ assert h0.shape == (6, 6)
+ assert coupling.shape == (6, 6)
+ assert_allclose(drive_operator, coupling)
+ assert controls.steps_per_period == 4
+ assert controls.phase_samples == 2
+ delays = np.linspace(0.0, model.period, 5)
+ total = np.linspace(0.1, 0.01, 5).astype(complex)
+ correlation = CorrelationResult(
+ delays,
+ total,
+ total.copy(),
+ np.zeros(5),
+ (),
+ "uniform_tempo_floquet_multitime",
+ {"dt": model.period / 4},
+ )
+ return UniformTempoResult(
+ "uniform_tempo_floquet_multitime",
+ np.eye(6, dtype=complex) / 6,
+ np.repeat((np.eye(6, dtype=complex) / 6)[None, ...], 2, axis=0),
+ correlation,
+ {
+ "trace_error": 1e-8,
+ "hermiticity_error": 1e-8,
+ "minimum_density_eigenvalue": 1 / 6,
+ "fixed_point_residual": 1e-8,
+ "floquet_transfer_residual": 1e-8,
+ },
+ {
+ "dt": model.period / 4,
+ "period_steps": 4,
+ "phase_samples": 2,
+ "bond_dimension": 3,
+ "tolerance": controls.tolerance,
+ "julia_version": "1.12.6",
+ "uniform_tempo_revision": "b76a018",
+ "manifest_sha256": "a" * 64,
+ },
+ )
+
+ monkeypatch.setattr(
+ n3_heat_module,
+ "UniformTempoBackend",
+ FakeUniformBackend,
+ )
+ result = run_n3_heat_point(
+ N3HeatPoint(
+ backend="uniform_tempo",
+ steps_per_period=4,
+ phase_samples=2,
+ delay_periods=1,
+ epsrel=1e-4,
+ frequency_points=9,
+ ),
+ commit="test",
+ )
+ assert result["converged"]
+ assert result["method"] == "uniform_tempo_floquet_multitime"
+ assert result["diagnostics"]["bond_dimension"] == 3
+ assert len(result["continuous"]) == 9
+
+
+def test_compare_sector_spectra_requires_matching_grids() -> None:
+ even = {
+ "frequency": [0.0, 1.0, 2.0],
+ "continuous": [0.0, 2.0, 0.0],
+ }
+ odd = {
+ "frequency": [0.0, 1.0, 2.0],
+ "continuous": [0.0, 1.0, 0.0],
+ }
+ comparison = compare_sector_spectra(even, odd)
+ assert comparison["maximum_absolute_difference"] == 1.0
+ assert np.isclose(comparison["normalized_l1_difference"], 1.0)
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_operators.py b/tracks/mps/solutions/Ranger-123/tests/test_operators.py
new file mode 100644
index 000000000..fc3d90d3a
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_operators.py
@@ -0,0 +1,17 @@
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.operators import collective_operator, pauli, site_operator
+
+
+def test_collective_z_eigenvalues():
+ s = collective_operator("z", n=2, eta=0.5)
+ assert_allclose(np.diag(s), [1, 0, 0, -1])
+
+
+def test_site_algebra():
+ x0 = site_operator("x", 0, 2)
+ y0 = site_operator("y", 0, 2)
+ z0 = site_operator("z", 0, 2)
+ assert_allclose(x0 @ y0, 1j * z0)
+ assert_allclose(pauli("x") @ pauli("x"), np.eye(2))
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_paper_audit.py b/tracks/mps/solutions/Ranger-123/tests/test_paper_audit.py
new file mode 100644
index 000000000..3a7d74b08
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_paper_audit.py
@@ -0,0 +1,176 @@
+from __future__ import annotations
+
+import json
+from pathlib import Path
+from typing import Any
+
+from floquet_if_manybody.paper_extension import audit_paper_results
+
+
+def _evidence() -> list[dict[str, Any]]:
+ common = {
+ "coarse_fingerprint": "a" * 64,
+ "refined_fingerprint": "b" * 64,
+ "state_residual": 1e-3,
+ "correlation_residual": 2e-3,
+ "heat_residual": 3e-3,
+ "passed": True,
+ "coarse_bond_dimension": 10,
+ "refined_bond_dimension": 12,
+ "coarse_phase_samples": 3,
+ "refined_phase_samples": 3,
+ }
+ return [
+ {
+ **common,
+ "parameter": "epsrel",
+ "coarse_value": 3e-7,
+ "refined_value": 1e-7,
+ "coarse_steps_per_period": 60,
+ "refined_steps_per_period": 60,
+ "coarse_tolerance": 3e-7,
+ "refined_tolerance": 1e-7,
+ },
+ {
+ **common,
+ "parameter": "epsrel",
+ "coarse_value": 3e-7,
+ "refined_value": 1e-7,
+ "coarse_steps_per_period": 90,
+ "refined_steps_per_period": 90,
+ "coarse_tolerance": 3e-7,
+ "refined_tolerance": 1e-7,
+ },
+ {
+ **common,
+ "parameter": "steps_per_period",
+ "coarse_value": 60,
+ "refined_value": 90,
+ "coarse_steps_per_period": 60,
+ "refined_steps_per_period": 90,
+ "coarse_tolerance": 1e-7,
+ "refined_tolerance": 1e-7,
+ },
+ {
+ **common,
+ "parameter": "phase_samples",
+ "coarse_value": 3,
+ "refined_value": 15,
+ "coarse_steps_per_period": 90,
+ "refined_steps_per_period": 90,
+ "coarse_tolerance": 1e-7,
+ "refined_tolerance": 1e-7,
+ "refined_phase_samples": 15,
+ },
+ ]
+
+
+def _diagnostics() -> dict[str, float]:
+ return {
+ "fixed_point_residual": 1e-5,
+ "trace_error": 1e-5,
+ "hermiticity_error": 1e-5,
+ "connected_tail_amplitude": 1e-3,
+ "minimum_density_eigenvalue": 0.0,
+ }
+
+
+def _write_manifests(directory: Path) -> None:
+ n3_points = [
+ {
+ "sector": sector,
+ "model": {"j": j},
+ "adaptive_status": "converged",
+ "adaptive_converged": True,
+ "diagnostics": _diagnostics(),
+ "evidence": _evidence(),
+ }
+ for sector in ("even", "odd")
+ for j in (0.25, 0.5, 1.0)
+ ]
+ error_points = [
+ {
+ "alpha": alpha,
+ "drive_ratio": ratio,
+ "status": "converged",
+ "metrics": {
+ "trace_distance": 0.1,
+ "correlation": 0.2,
+ "heat": 0.3,
+ },
+ "convergence_evidence": _evidence(),
+ }
+ for alpha in (0.025, 0.05, 0.1)
+ for ratio in (0.75, 1.0, 1.25)
+ ]
+ model_points = [
+ {
+ "variant": variant,
+ "adaptive_status": "converged",
+ "adaptive_converged": True,
+ "diagnostics": _diagnostics(),
+ "evidence": _evidence(),
+ }
+ for variant in ("bounded", "bounded_ct", "kac", "kac_ct")
+ ]
+ payloads = {
+ "n3_heat_manifest.json": {
+ "exact_backend": "uniform_tempo",
+ "converged": True,
+ "points": n3_points,
+ "odd_cross_j_relative_max_difference": 0.0,
+ },
+ "error_map_manifest.json": {
+ "exact_backend": "uniform_tempo",
+ "converged": True,
+ "points": error_points,
+ },
+ "model_comparison_manifest.json": {
+ "exact_backend": "uniform_tempo",
+ "complete": True,
+ "locally_complete": True,
+ "converged": True,
+ "points": model_points,
+ },
+ }
+ for name, payload in payloads.items():
+ (directory / name).write_text(json.dumps(payload), encoding="utf-8")
+
+
+def test_paper_audit_requires_nested_convergence_and_all_points(
+ tmp_path: Path,
+) -> None:
+ _write_manifests(tmp_path)
+ passed, failures = audit_paper_results(tmp_path)
+ assert passed
+ assert failures == []
+
+ path = tmp_path / "n3_heat_manifest.json"
+ payload = json.loads(path.read_text(encoding="utf-8"))
+ payload["points"][0]["evidence"] = payload["points"][0]["evidence"][1:]
+ path.write_text(json.dumps(payload), encoding="utf-8")
+ passed, failures = audit_paper_results(tmp_path)
+ assert not passed
+ assert any("both timestep grids" in failure for failure in failures)
+
+
+def test_paper_audit_accepts_explicit_kac_timestep_resource_ceiling(
+ tmp_path: Path,
+) -> None:
+ _write_manifests(tmp_path)
+ path = tmp_path / "model_comparison_manifest.json"
+ payload = json.loads(path.read_text(encoding="utf-8"))
+ payload["converged"] = False
+ for point in payload["points"]:
+ if not point["variant"].startswith("kac_"):
+ continue
+ point["adaptive_status"] = "resource_ceiling"
+ point["adaptive_converged"] = False
+ point["failed_parameter"] = "steps_per_period"
+ point["evidence"] = [
+ item for item in point["evidence"] if item["parameter"] == "epsrel"
+ ][:1]
+ path.write_text(json.dumps(payload), encoding="utf-8")
+ passed, failures = audit_paper_results(tmp_path)
+ assert passed
+ assert failures == []
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_paper_extension.py b/tracks/mps/solutions/Ranger-123/tests/test_paper_extension.py
new file mode 100644
index 000000000..2824138d1
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_paper_extension.py
@@ -0,0 +1,61 @@
+from __future__ import annotations
+
+from copy import deepcopy
+
+from floquet_if_manybody.n3_heat import N3HeatPoint, prepare_n3_sector
+from floquet_if_manybody.paper_extension import (
+ _odd_equivalent_payload,
+ n2_correlation_delay_periods,
+ uniform_error_schedule,
+ uniform_publication_schedule,
+)
+
+
+def test_odd_equivalent_payload_reuses_only_the_projected_model() -> None:
+ point = N3HeatPoint(j=0.25, sector="odd", backend="uniform_tempo")
+ prepared = prepare_n3_sector(point)
+ reference = {
+ "fingerprint": "a" * 64,
+ "source_commit": "test",
+ "point": {"j": 0.25},
+ "final_point": {
+ **point.__dict__,
+ "steps_per_period": 60,
+ "phase_samples": 3,
+ },
+ "model": {
+ "n": 3,
+ "j": 0.25,
+ "drive_frequency": prepared.model.drive_frequency,
+ },
+ "model_hash": "b" * 64,
+ "projected_model_hash": "c" * 64,
+ "bright_gap": prepared.bright_gap,
+ "continuous": [0.0, 1.0],
+ "adaptive_converged": True,
+ }
+ untouched = deepcopy(reference)
+ target = _odd_equivalent_payload(reference, 1.0)
+ assert reference == untouched
+ assert target["point"]["j"] == 1.0
+ assert target["final_point"]["j"] == 1.0
+ assert target["model"]["j"] == 1.0
+ assert target["continuous"] == reference["continuous"]
+ assert target["projected_model_hash"] == reference["projected_model_hash"]
+ assert target["numerical_reuse"]["h0_frobenius_residual"] < 1e-13
+ assert target["numerical_reuse"]["coupling_frobenius_residual"] < 1e-13
+
+
+def test_n2_correlation_window_grows_at_weak_coupling() -> None:
+ assert n2_correlation_delay_periods(0.1) == 4
+ assert n2_correlation_delay_periods(0.05) == 6
+ assert n2_correlation_delay_periods(0.025) == 12
+
+
+def test_n2_error_grid_has_a_deeper_compression_ladder() -> None:
+ publication = uniform_publication_schedule()
+ error = uniform_error_schedule()
+ assert error.steps_per_period == publication.steps_per_period
+ assert error.phase_samples == publication.phase_samples
+ assert error.tolerances[: len(publication.tolerances)] == publication.tolerances
+ assert error.tolerances[-1] < publication.tolerances[-1]
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_paper_plotting.py b/tracks/mps/solutions/Ranger-123/tests/test_paper_plotting.py
new file mode 100644
index 000000000..72e1e1cea
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_paper_plotting.py
@@ -0,0 +1,90 @@
+from __future__ import annotations
+
+from pathlib import Path
+
+from heat_valve_fixtures import valid_heat_valve_manifest
+
+from floquet_if_manybody.plotting import (
+ plot_dark_diagnostics,
+ plot_error_maps,
+ plot_heat_valve_hero,
+ plot_model_variants,
+ plot_n3_sector_heat,
+ plot_odd_sector_difference,
+)
+
+
+def _n3_manifest() -> dict[str, object]:
+ points = []
+ diagnostics = []
+ for sector in ("even", "odd"):
+ for j in (0.25, 0.5, 1.0):
+ points.append(
+ {
+ "sector": sector,
+ "adaptive_converged": True,
+ "model": {"j": j},
+ "frequency": [0.0, 1.0, 2.0],
+ "continuous": [0.0, j, 0.0],
+ }
+ )
+ diagnostics.append(
+ {
+ "sector": sector,
+ "j": j,
+ "integrated_continuous_heat": j,
+ "period_variance": 0.5,
+ "strongest_transitions": [
+ {"source": 0, "target": 1, "weight": j}
+ ],
+ }
+ )
+ return {"points": points, "dark_diagnostics": diagnostics}
+
+
+def test_all_paper_plots_render_pdf_and_png(tmp_path: Path) -> None:
+ n3 = _n3_manifest()
+ plot_n3_sector_heat(n3, tmp_path / "sector")
+ plot_odd_sector_difference(n3, tmp_path / "odd")
+ plot_dark_diagnostics(n3, tmp_path / "dark")
+ error = {
+ "points": [
+ {
+ "alpha": alpha,
+ "drive_ratio": ratio,
+ "status": "converged",
+ "metrics": {
+ "trace_distance": 0.1,
+ "correlation": 0.2,
+ "heat": 0.3,
+ },
+ }
+ for alpha in (0.025, 0.05, 0.1)
+ for ratio in (0.75, 1.0, 1.25)
+ ]
+ }
+ plot_error_maps(error, tmp_path / "errors")
+ models = {
+ "points": [
+ {
+ "adaptive_converged": True,
+ "variant": name,
+ "frequency": [0.0, 1.0],
+ "continuous": [0.0, 1.0],
+ "continuous_eta_rescaled": [0.0, 2.0],
+ }
+ for name in ("bounded_no_ct", "bounded_ct", "kac_no_ct", "kac_ct")
+ ]
+ }
+ plot_model_variants(models, tmp_path / "models")
+ assert len(list(tmp_path.glob("*.pdf"))) == 5
+ assert len(list(tmp_path.glob("*.png"))) == 5
+
+
+def test_heat_valve_hero_writes_png_and_pdf(tmp_path: Path) -> None:
+ plot_heat_valve_hero(
+ valid_heat_valve_manifest(),
+ tmp_path / "heat_valve_hero",
+ )
+ assert (tmp_path / "heat_valve_hero.png").is_file()
+ assert (tmp_path / "heat_valve_hero.pdf").is_file()
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_poles.py b/tracks/mps/solutions/Ranger-123/tests/test_poles.py
new file mode 100644
index 000000000..5470d5700
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_poles.py
@@ -0,0 +1,111 @@
+from __future__ import annotations
+
+import numpy as np
+import pytest
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.poles import (
+ TransferPole,
+ fit_pole_residues,
+ match_transfer_poles,
+ transfer_poles,
+)
+
+
+def _poles(values: list[complex]) -> tuple[TransferPole, ...]:
+ return tuple(
+ TransferPole(
+ eigenvalue=value,
+ decay_rate=float(-np.log(abs(value))),
+ quasifrequency=float(np.angle(value)),
+ eigenpair_residual=1e-13,
+ )
+ for value in values
+ )
+
+
+def test_transfer_poles_convert_eigenvalues_to_rates() -> None:
+ period = 2.0
+ values = np.array([1.0, np.exp((-0.2 + 0.7j) * period)])
+ poles = transfer_poles(values, np.array([1e-13, 2e-13]), period)
+ assert len(poles) == 1
+ assert_allclose(poles[0].decay_rate, 0.2, atol=1e-12)
+ assert_allclose(poles[0].quasifrequency, 0.7, atol=1e-12)
+
+
+def test_transfer_poles_accept_resolved_approximate_steady_mode() -> None:
+ poles = transfer_poles(
+ np.array([0.9991 + 1e-15j, 0.8 + 0.1j]),
+ np.array([1e-13, 1e-13]),
+ period=1.0,
+ )
+ assert len(poles) == 1
+ assert poles[0].eigenvalue == 0.8 + 0.1j
+
+
+def test_fit_recovers_complex_residues() -> None:
+ period = 1.5
+ eigenvalues = np.array([0.8 * np.exp(0.2j), 0.55 * np.exp(-0.4j)])
+ residues = np.array([0.7 - 0.1j, -0.2 + 0.3j])
+ n = np.arange(16)
+ connected = sum(
+ residue * eigenvalue**n
+ for residue, eigenvalue in zip(residues, eigenvalues, strict=True)
+ )
+ fit = fit_pole_residues(
+ transfer_poles(
+ np.r_[1.0, eigenvalues],
+ np.full(3, 1e-13),
+ period,
+ ),
+ n * period,
+ connected,
+ period,
+ max_modes=2,
+ )
+ assert_allclose(
+ [item.residue for item in fit.residues],
+ residues,
+ atol=1e-10,
+ )
+ assert fit.reconstruction_residual < 1e-12
+
+
+def test_fit_uses_only_stroboscopic_delays() -> None:
+ poles = _poles([0.8 + 0.1j])
+ delays = np.arange(9) * 0.5
+ connected = np.full(9, 99 + 0j)
+ connected[::2] = (0.3 - 0.2j) * poles[0].eigenvalue ** np.arange(5)
+ fit = fit_pole_residues(
+ poles,
+ delays,
+ connected,
+ period=1.0,
+ max_modes=1,
+ )
+ assert_allclose(fit.residues[0].residue, 0.3 - 0.2j)
+ assert_allclose(fit.stroboscopic_delays, delays[::2])
+
+
+def test_fit_requires_an_overdetermined_stroboscopic_window() -> None:
+ with pytest.raises(ValueError, match="stroboscopic samples"):
+ fit_pole_residues(
+ _poles([0.8, 0.7]),
+ np.array([0.0, 1.0]),
+ np.array([1.0, 0.5], dtype=complex),
+ period=1.0,
+ max_modes=2,
+ )
+
+
+def test_mode_matching_follows_nearest_complex_poles() -> None:
+ previous = _poles([0.9 + 0.1j, 0.7 - 0.2j])
+ current = _poles([0.69 - 0.19j, 0.89 + 0.11j])
+ matched = match_transfer_poles(previous, current)
+ assert [item.current_index for item in matched] == [1, 0]
+
+
+def test_degenerate_matching_is_marked_ambiguous() -> None:
+ previous = _poles([0.8 + 0.1j, 0.8 + 0.1j])
+ current = _poles([0.8 + 0.1j, 0.8 + 0.1j])
+ assert all(item.ambiguous for item in match_transfer_poles(previous, current))
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_pt_tempo.py b/tracks/mps/solutions/Ranger-123/tests/test_pt_tempo.py
new file mode 100644
index 000000000..4b5773760
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_pt_tempo.py
@@ -0,0 +1,30 @@
+import numpy as np
+import pytest
+
+from floquet_if_manybody.backends.pt_tempo import PtTempoBackend
+from floquet_if_manybody.config import BathConfig
+
+oqupy = pytest.importorskip("oqupy")
+if np.lib.NumpyVersion(np.__version__) >= "2.0.0":
+ pytest.skip("OQuPy 0.5 requires NumPy <2", allow_module_level=True)
+
+
+def test_pt_tempo_short_run_is_labeled_and_trace_preserving():
+ h = np.array([[0, 0.5], [0.5, 0]], dtype=complex)
+ s = np.diag([1, -1]).astype(complex)
+ rho = np.array([[1, 0], [0, 0]], dtype=complex)
+ run = PtTempoBackend().run(
+ lambda _time: h,
+ s,
+ rho,
+ BathConfig(alpha=0.01),
+ dt=0.1,
+ steps=6,
+ memory_steps=2,
+ epsrel=1e-5,
+ )
+ assert run.result.method == "pt_tempo"
+ assert run.result.diagnostics["trace_error"] < 1e-3
+ assert run.result.metadata["spectral_density_convention"].startswith(
+ "OQuPy alpha divided"
+ )
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_spectra_n2.py b/tracks/mps/solutions/Ranger-123/tests/test_spectra_n2.py
new file mode 100644
index 000000000..e0afc072f
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_spectra_n2.py
@@ -0,0 +1,31 @@
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.config import ModelConfig
+from floquet_if_manybody.models import coupling_operator, ising_hamiltonian
+from floquet_if_manybody.spectra import diagonalize, transitions
+from floquet_if_manybody.symmetry import n2_sectors, project
+
+
+def test_n2_analytic_triplet_spectrum_and_weights():
+ _, triplet = n2_sectors()
+ omega = 1.0
+ for j in [0.0, 0.25, 0.5, 1.0, 2.0]:
+ cfg = ModelConfig(n=2, j=j, omega=omega)
+ spectrum = diagonalize(project(ising_hamiltonian(cfg), triplet))
+ e = np.sqrt(j**2 + omega**2)
+ assert_allclose(spectrum.energies, [-e, -j, e], atol=1e-12)
+ items = transitions(
+ spectrum, spectrum, project(coupling_operator(cfg), triplet), threshold=1e-10
+ )
+ from_ground = sorted(
+ [x for x in items if x.source == 0 and x.frequency > 0],
+ key=lambda x: x.frequency,
+ )
+ assert_allclose([x.frequency for x in from_ground], [e - j], atol=1e-12)
+ expected_low = 2 * cfg.eta**2 * (1 + j / e)
+ assert_allclose(from_ground[0].weight, expected_low, atol=1e-12)
+ high = [x for x in items if x.source == 1 and x.target == 2]
+ expected_high = 2 * cfg.eta**2 * (1 - j / e)
+ assert_allclose(high[0].frequency, e + j, atol=1e-12)
+ assert_allclose(high[0].weight, expected_high, atol=1e-12)
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_spectra_n3.py b/tracks/mps/solutions/Ranger-123/tests/test_spectra_n3.py
new file mode 100644
index 000000000..4f57a89e4
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_spectra_n3.py
@@ -0,0 +1,29 @@
+import numpy as np
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.config import ModelConfig
+from floquet_if_manybody.models import ising_hamiltonian
+from floquet_if_manybody.spectra import diagonalize
+from floquet_if_manybody.symmetry import n3_reflection_sectors, project
+
+
+def test_n3_odd_gap_is_single_spin_gap():
+ odd, _ = n3_reflection_sectors()
+ for j in [0, 0.5, 2.0]:
+ cfg = ModelConfig(n=3, j=j, omega=1)
+ energies = diagonalize(project(ising_hamiltonian(cfg), odd)).energies
+ assert_allclose(np.diff(energies), [1.0], atol=1e-12)
+
+
+def test_n3_cat_gap_asymptotic_coefficient():
+ _, even = n3_reflection_sectors()
+ ratios = []
+ for j in [4.0, 8.0, 16.0]:
+ cfg = ModelConfig(n=3, j=j, omega=1)
+ se = diagonalize(project(ising_hamiltonian(cfg), even))
+ # The cat partner has opposite global spin-flip parity inside the even
+ # reflection sector, so use the two lowest levels of this block.
+ gap = se.energies[1] - se.energies[0]
+ ratios.append(gap * 4 * j**2)
+ assert abs(ratios[-1] - 1) < abs(ratios[0] - 1)
+ np.testing.assert_allclose(ratios[-1], 1.0, rtol=0.02)
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n2.py b/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n2.py
new file mode 100644
index 000000000..65464d579
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n2.py
@@ -0,0 +1,14 @@
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.config import ModelConfig
+from floquet_if_manybody.models import coupling_operator, ising_hamiltonian
+from floquet_if_manybody.symmetry import n2_sectors, project, sector_residual
+
+
+def test_n2_singlet_is_dark_and_invariant():
+ singlet, triplet = n2_sectors()
+ cfg = ModelConfig(n=2)
+ assert (singlet.dimension, triplet.dimension) == (1, 3)
+ assert_allclose(project(coupling_operator(cfg), singlet), 0, atol=1e-14)
+ assert sector_residual(ising_hamiltonian(cfg), singlet) < 1e-13
+ assert sector_residual(ising_hamiltonian(cfg), triplet) < 1e-13
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n3.py b/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n3.py
new file mode 100644
index 000000000..5d91d288b
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n3.py
@@ -0,0 +1,15 @@
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.config import ModelConfig
+from floquet_if_manybody.models import ising_hamiltonian
+from floquet_if_manybody.symmetry import n3_reflection_sectors, project, sector_residual
+
+
+def test_n3_odd_sector_is_j_independent():
+ odd, even = n3_reflection_sectors()
+ h1 = project(ising_hamiltonian(ModelConfig(n=3, j=0.2)), odd)
+ h2 = project(ising_hamiltonian(ModelConfig(n=3, j=2.0)), odd)
+ assert_allclose(h1, h2)
+ assert (odd.dimension, even.dimension) == (2, 6)
+ assert sector_residual(ising_hamiltonian(ModelConfig(n=3)), odd) < 1e-13
+ assert sector_residual(ising_hamiltonian(ModelConfig(n=3)), even) < 1e-13
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n4.py b/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n4.py
new file mode 100644
index 000000000..937599ffb
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_symmetry_n4.py
@@ -0,0 +1,21 @@
+import numpy as np
+
+from floquet_if_manybody.config import ModelConfig
+from floquet_if_manybody.models import coupling_operator, ising_hamiltonian
+from floquet_if_manybody.symmetry import n4_reflection_sectors, sector_residual
+
+
+def test_n4_reflection_dimensions_and_invariance() -> None:
+ odd, even = n4_reflection_sectors()
+ assert odd.dimension == 6
+ assert even.dimension == 10
+ model = ModelConfig(n=4, j=0.5)
+ h0 = ising_hamiltonian(model)
+ coupling = coupling_operator(model)
+ for sector in (odd, even):
+ assert sector_residual(h0, sector) < 1e-13
+ assert sector_residual(coupling, sector) < 1e-13
+ assert np.allclose(
+ sector.isometry.conj().T @ sector.isometry,
+ np.eye(sector.dimension),
+ )
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_uniform_tempo_backend.py b/tracks/mps/solutions/Ranger-123/tests/test_uniform_tempo_backend.py
new file mode 100644
index 000000000..d5dd9ffb2
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_uniform_tempo_backend.py
@@ -0,0 +1,284 @@
+from __future__ import annotations
+
+import json
+import sys
+from pathlib import Path
+
+import numpy as np
+import pytest
+from numpy.testing import assert_allclose
+
+from floquet_if_manybody.backends.uniform_tempo import (
+ UniformTempoBackend,
+ UniformTempoControls,
+ _encode_complex,
+ _tensor_cache_key,
+)
+from floquet_if_manybody.config import BathConfig, ModelConfig
+
+
+def _write_fake_runner(path: Path, payload: dict[str, object], exit_code: int = 0) -> None:
+ script = f"""\
+import json
+import pathlib
+import sys
+
+if {exit_code}:
+ print("synthetic Julia failure", file=sys.stderr)
+ raise SystemExit({exit_code})
+input_path, output_path = sys.argv[1:3]
+request = json.loads(pathlib.Path(input_path).read_text())
+pathlib.Path({str(Path("captured-request.json"))!r}).write_text(json.dumps(request))
+payload = {payload!r}
+payload["request_echo"] = request
+pathlib.Path(output_path).write_text(json.dumps(payload))
+"""
+ script = script.replace(
+ repr(str(Path("captured-request.json"))),
+ repr(str(path.parent / "captured-request.json")),
+ )
+ path.write_text(script, encoding="utf-8")
+
+
+def _valid_payload() -> dict[str, object]:
+ return {
+ "method": "uniform_tempo_floquet_multitime",
+ "dt": np.pi / 2,
+ "period_steps": 4,
+ "bond_dimension": 3,
+ "floquet_state": {
+ "real": [0.6, 0.0, 0.0, 0.4],
+ "imag": [0.0, 0.1, -0.1, 0.0],
+ "shape": [2, 2],
+ },
+ "phase_states": {
+ "real": [0.6, 0.0, 0.0, 0.4, 0.4, 0.0, 0.0, 0.6],
+ "imag": [0.0] * 8,
+ "shape": [2, 2, 2],
+ },
+ "one_point": [0.2, -0.2],
+ "phase_offsets": [0, 2],
+ "delay": [0.0, np.pi / 2, np.pi, 3 * np.pi / 2, 2 * np.pi],
+ "correlation": {
+ "real": [1.0, 0.5, 0.25, 0.125, 0.0625],
+ "imag": [0.0, -0.1, -0.05, -0.025, -0.0125],
+ "shape": [5],
+ },
+ "diagnostics": {
+ "trace_error": 1e-8,
+ "hermiticity_error": 1e-8,
+ "minimum_density_eigenvalue": 0.3,
+ "fixed_point_residual": 1e-7,
+ "floquet_transfer_residual": 1e-7,
+ },
+ "julia_version": "1.12.6",
+ "uniform_tempo_revision": "b76a018c32e5415989761d902b1b0e95f1a337da",
+ "manifest_sha256": "a" * 64,
+ "process_tensor_cache_hit": False,
+ "transfer_eigenvalues": {
+ "real": [],
+ "imag": [],
+ "shape": [0],
+ },
+ "transfer_eigenpair_residuals": [],
+ "transfer_dimension": 12,
+ }
+
+
+def _backend(tmp_path: Path, payload: dict[str, object]) -> UniformTempoBackend:
+ runner = tmp_path / "fake_runner.py"
+ _write_fake_runner(runner, payload)
+ return UniformTempoBackend(command_prefix=(sys.executable, str(runner)))
+
+
+def _model() -> ModelConfig:
+ return ModelConfig(
+ n=3,
+ j=0.5,
+ drive_amplitude=0.2,
+ drive_frequency=1.0,
+ )
+
+
+def test_valid_payload_round_trips_complex_arrays(tmp_path: Path) -> None:
+ backend = _backend(tmp_path, _valid_payload())
+ result = backend.run_periodic(
+ np.array([[0.0, 0.5], [0.5, 0.0]], dtype=complex),
+ np.diag([1.0, -1.0]).astype(complex),
+ _model(),
+ BathConfig(alpha=0.01, cutoff=2.5),
+ UniformTempoControls(
+ steps_per_period=4,
+ tolerance=1e-4,
+ phase_samples=2,
+ delay_periods=1,
+ auto_nc=False,
+ memory_cutoff=6,
+ ),
+ )
+ assert result.method == "uniform_tempo_floquet_multitime"
+ assert result.phase_states.shape == (2, 2, 2)
+ assert_allclose(result.floquet_state, [[0.6, -0.1j], [0.1j, 0.4]])
+ assert_allclose(
+ result.correlation.total,
+ [
+ 1.0,
+ 0.5 - 0.1j,
+ 0.25 - 0.05j,
+ 0.125 - 0.025j,
+ 0.0625 - 0.0125j,
+ ],
+ )
+ assert_allclose(
+ result.correlation.total,
+ result.correlation.connected + result.correlation.coherent,
+ )
+ assert result.metadata["uniform_tempo_revision"].startswith("b76a018")
+ assert result.transfer_eigenvalues.size == 0
+
+
+def test_backend_round_trips_transfer_poles_and_independent_drive(
+ tmp_path: Path,
+) -> None:
+ payload = _valid_payload()
+ payload["transfer_eigenvalues"] = {
+ "real": [1.0, 0.8],
+ "imag": [0.0, 0.1],
+ "shape": [2],
+ }
+ payload["transfer_eigenpair_residuals"] = [1e-12, 2e-11]
+ backend = _backend(tmp_path, payload)
+ drive = 2 * np.diag([1.0, -1.0]).astype(complex)
+ result = backend.run_periodic(
+ np.array([[0.0, 0.5], [0.5, 0.0]], dtype=complex),
+ np.diag([1.0, -1.0]).astype(complex),
+ _model(),
+ BathConfig(alpha=0.01),
+ UniformTempoControls(4, 1e-4, 2, 1, pole_count=2),
+ drive_operator=drive,
+ )
+ assert_allclose(result.transfer_eigenvalues, [1.0, 0.8 + 0.1j])
+ assert_allclose(result.transfer_eigenpair_residuals, [1e-12, 2e-11])
+ request = json.loads((tmp_path / "captured-request.json").read_text())
+ assert request["drive"]["real"] == _encode_complex(drive)["real"]
+ assert request["controls"]["pole_count"] == 2
+
+
+@pytest.mark.parametrize(
+ ("field", "value", "message"),
+ [
+ ("transfer_eigenpair_residuals", [1e-12], "same length"),
+ ("transfer_eigenpair_residuals", [1e-12, -1.0], "nonnegative"),
+ (
+ "transfer_eigenvalues",
+ {"real": [1.0, "nan"], "imag": [0.0, 0.0], "shape": [2]},
+ "non-finite",
+ ),
+ ],
+)
+def test_invalid_transfer_pole_payload_is_rejected(
+ tmp_path: Path,
+ field: str,
+ value: object,
+ message: str,
+) -> None:
+ payload = _valid_payload()
+ payload["transfer_eigenvalues"] = {
+ "real": [1.0, 0.8],
+ "imag": [0.0, 0.1],
+ "shape": [2],
+ }
+ payload["transfer_eigenpair_residuals"] = [1e-12, 2e-11]
+ payload[field] = value
+ backend = _backend(tmp_path, payload)
+ with pytest.raises(ValueError, match=message):
+ backend.run_periodic(
+ np.eye(2, dtype=complex),
+ np.diag([1.0, -1.0]).astype(complex),
+ _model(),
+ BathConfig(alpha=0.01),
+ UniformTempoControls(4, 1e-4, 2, 1, pole_count=2),
+ )
+
+
+def test_nonzero_runner_exit_is_reported(tmp_path: Path) -> None:
+ runner = tmp_path / "failing.py"
+ _write_fake_runner(runner, {}, exit_code=7)
+ backend = UniformTempoBackend(command_prefix=(sys.executable, str(runner)))
+ with pytest.raises(RuntimeError, match="synthetic Julia failure"):
+ backend.run_periodic(
+ np.eye(2, dtype=complex),
+ np.diag([1.0, -1.0]).astype(complex),
+ _model(),
+ BathConfig(alpha=0.01),
+ UniformTempoControls(4, 1e-4, 2, 1),
+ )
+
+
+@pytest.mark.parametrize(
+ ("mutation", "message"),
+ [
+ (lambda payload: payload.pop("uniform_tempo_revision"), "provenance"),
+ (lambda payload: payload.update(method="wrong"), "method"),
+ (
+ lambda payload: payload["correlation"].update(real=[1.0, 0.5]),
+ "shape",
+ ),
+ ],
+)
+def test_malformed_payload_is_rejected(
+ tmp_path: Path, mutation, message: str
+) -> None:
+ payload = _valid_payload()
+ mutation(payload)
+ backend = _backend(tmp_path, payload)
+ with pytest.raises(ValueError, match=message):
+ backend.run_periodic(
+ np.eye(2, dtype=complex),
+ np.diag([1.0, -1.0]).astype(complex),
+ _model(),
+ BathConfig(alpha=0.01),
+ UniformTempoControls(4, 1e-4, 2, 1),
+ )
+
+
+def test_controls_require_commensurate_phase_sampling() -> None:
+ with pytest.raises(ValueError, match="phase_samples"):
+ UniformTempoControls(steps_per_period=6, tolerance=1e-5, phase_samples=4, delay_periods=1)
+
+
+def test_process_tensor_key_excludes_phase_and_delay_controls() -> None:
+ coupling = np.diag([1.0, -1.0]).astype(complex)
+ model = _model()
+ bath = BathConfig(alpha=0.01, cutoff=2.5)
+ coarse = UniformTempoControls(60, 3e-7, 3, 2)
+ denser_phase = UniformTempoControls(60, 3e-7, 15, 8)
+ assert _tensor_cache_key(coupling, model, bath, coarse) == _tensor_cache_key(
+ coupling,
+ model,
+ bath,
+ denser_phase,
+ )
+
+
+def test_backend_passes_content_addressed_tensor_cache(tmp_path: Path) -> None:
+ runner = tmp_path / "fake_runner.py"
+ _write_fake_runner(runner, _valid_payload())
+ backend = UniformTempoBackend(
+ command_prefix=(sys.executable, str(runner)),
+ tensor_cache_directory=tmp_path / "tensor-cache",
+ )
+ controls = UniformTempoControls(4, 1e-4, 2, 1)
+ backend.run_periodic(
+ np.array([[0.0, 0.5], [0.5, 0.0]], dtype=complex),
+ np.diag([1.0, -1.0]).astype(complex),
+ _model(),
+ BathConfig(alpha=0.01, cutoff=2.5),
+ controls,
+ )
+ request = json.loads((tmp_path / "captured-request.json").read_text())
+ cache_key = request["controls"]["process_tensor_cache_key"]
+ assert len(cache_key) == 64
+ assert request["controls"]["process_tensor_cache_path"].endswith(
+ f"{cache_key}.jls"
+ )
diff --git a/tracks/mps/solutions/Ranger-123/tests/test_uniform_tempo_environment.py b/tracks/mps/solutions/Ranger-123/tests/test_uniform_tempo_environment.py
new file mode 100644
index 000000000..c5054ad64
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/tests/test_uniform_tempo_environment.py
@@ -0,0 +1,37 @@
+import shutil
+import subprocess
+import tomllib
+from pathlib import Path
+
+import pytest
+
+PROJECT_ROOT = Path(__file__).resolve().parents[1]
+JULIA_PROJECT = PROJECT_ROOT / "julia" / "Project.toml"
+
+
+def test_julia_project_declares_required_dependencies() -> None:
+ project = tomllib.loads(JULIA_PROJECT.read_text(encoding="utf-8"))
+ assert {"UniformTEMPO", "OrdinaryDiffEq", "JSON3", "KrylovKit"} <= project[
+ "deps"
+ ].keys()
+ assert project["compat"]["julia"] == "1.12"
+
+
+def test_julia_runner_rejects_missing_input(tmp_path: Path) -> None:
+ julia = shutil.which("julia")
+ if julia is None:
+ pytest.skip("Julia is not installed")
+ completed = subprocess.run(
+ [
+ julia,
+ f"--project={PROJECT_ROOT / 'julia'}",
+ str(PROJECT_ROOT / "julia" / "run_uniform_tempo.jl"),
+ str(tmp_path / "missing.json"),
+ str(tmp_path / "out.json"),
+ ],
+ capture_output=True,
+ text=True,
+ check=False,
+ )
+ assert completed.returncode != 0
+ assert "input" in completed.stderr.lower()
diff --git a/tracks/mps/solutions/Ranger-123/uv.lock b/tracks/mps/solutions/Ranger-123/uv.lock
new file mode 100644
index 000000000..adfea015e
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/uv.lock
@@ -0,0 +1,1013 @@
+version = 1
+revision = 3
+requires-python = ">=3.11"
+resolution-markers = [
+ "python_full_version >= '3.15'",
+ "python_full_version >= '3.12' and python_full_version < '3.15'",
+ "python_full_version < '3.12'",
+]
+
+[[package]]
+name = "ast-serialize"
+version = "0.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/58/ad/0d70a3a2d6e01968d985415259e8ec7ad3f777903f9b1c1f3c8c44642c60/ast_serialize-0.6.0.tar.gz", hash = "sha256:aadd3ffcf4858c9726bf3515f7b199c7eadbe504f96028e4a87172c0da65a8fe", size = 61489, upload-time = "2026-06-30T20:02:55.555Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3f/12/3e5f575f156555547c250a8b0d1347517a3a20fc7f4492e9703a69d4f45e/ast_serialize-0.6.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:a7520b672827885bafeae7501f684d14d47d17e5f45256f9df547686cca52264", size = 1177640, upload-time = "2026-06-30T20:02:06.708Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/a4/921a9e27951627983b0f368859ea00f8330a551dc0bf4c2fdcb11855a98b/ast_serialize-0.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a14191beec7e0c078d2fc1f6edc0aee88bcd4db9f18e1bc9f8052b559c22dddc", size = 1168111, upload-time = "2026-06-30T20:02:08.366Z" },
+ { url = "https://files.pythonhosted.org/packages/00/69/950cf404de7b8782cf95e5c1237e25e2aa46177b287f39f9eeddf481fd6f/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32ef62ec34cf6be20ad77d4799556638fbdf187f3ae10698dfb20ef9f2c89516", size = 1227656, upload-time = "2026-06-30T20:02:09.843Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/a8/46f8f6a6479d9d2273980957bb091a506c55f5b95d3c029ee58518a78407/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13b7769970a39983b0adf2f38917b1cd3b8946f76df045756c3d741bc689f089", size = 1227706, upload-time = "2026-06-30T20:02:11.367Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/b9/9ac415bda0a40e49eab8fea3b2741c19c98bb84d57d62c4cfc6230eb67be/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f7a408601bb3edaefb3bc67a4c01f5235e3253653b6a5729a2ee2382b35341c", size = 1431705, upload-time = "2026-06-30T20:02:12.737Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/06/8807115d441444879f7561b5eede5ac18fc80392f11826d61ccf31f503b1/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8670bfa51208a2c0c8d138928e40e998fab158f9200d53bb80c088b5b8eda7b8", size = 1249533, upload-time = "2026-06-30T20:02:14.571Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/c0/c2ba82ef9618650357d9421a1fdb27ffec862a7f57e8e2de82a3ccd11e12/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4826809eb8597a8cd59fd924b6d7c285b8969a1e0007e2cb652cab62376270f", size = 1252619, upload-time = "2026-06-30T20:02:16.219Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/a7/fa31d52dd4102cede29fb9634e98d214129b2783b4f95528c6dc6a8f6587/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:577a6c189068686869f5f1ddc38363f3ae1808a4753b577266f9202071a7bb66", size = 1242983, upload-time = "2026-06-30T20:02:17.813Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/20/ddf742b5ad3c4bafd3466f2265037cfd99bc1b9a5ee46a5d58c90d523242/ast_serialize-0.6.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:085de7f62dc9cc247eb01e965a362707d1d90b1d89a82c5bf78301a60a3c417b", size = 1296148, upload-time = "2026-06-30T20:02:19.146Z" },
+ { url = "https://files.pythonhosted.org/packages/24/cb/9f6f217cce8b3b632c5568b478d195a35e79dce4dbe309438cb89ba6ea4f/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9f8a8b78b13173de6a9ec22111d9be674874cd5bdccda04f14ae5ebc2bef403a", size = 1403826, upload-time = "2026-06-30T20:02:20.696Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/f8/9d16d4f0107a183924425cc0e7618d8bf76f96b45afa9ff19f924ed1ad57/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f2ff3baffc3a29c1f15bc9098aa0c09763410262d5e6cef42116f7356c184554", size = 1502943, upload-time = "2026-06-30T20:02:22.034Z" },
+ { url = "https://files.pythonhosted.org/packages/80/dd/bbc1c38756350dddf7e24acae1c9482ef42051c267417e019aecc1ed4075/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0067b25fce104eaae5b88383de9ab803faeb671831e14ca698b771b356e2600f", size = 1497632, upload-time = "2026-06-30T20:02:23.517Z" },
+ { url = "https://files.pythonhosted.org/packages/42/7e/9daffefcf5b97e6bb4c3e0b3c024c1aee9722f23d3cf7cd2ff80d6fb4a40/ast_serialize-0.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c617417f9cbb0cb144f6283c3cbe0d2e0f01beaf9f608f662b21191058a626ec", size = 1448858, upload-time = "2026-06-30T20:02:24.889Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/1f/f9baaab81a677ea0af7d2458cac2f94ebcc85958f8a3c15ba9d9e5dab653/ast_serialize-0.6.0-cp314-cp314t-win32.whl", hash = "sha256:5337cb256dcea3df9288205213d1601581536526b8f4da44b6974f1180f3252a", size = 1052600, upload-time = "2026-06-30T20:02:26.263Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/1f/41b535866519512d8cf6669cb2cff7823b7672bb6279c0333b4ff89d7d9f/ast_serialize-0.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2d947e45cafc4b09bd7528917fa84c517654a43de173c79785574b7b3068ac24", size = 1095570, upload-time = "2026-06-30T20:02:27.639Z" },
+ { url = "https://files.pythonhosted.org/packages/50/64/e472fe3e3a2d33d874b987e8518aedf24562919e3b6161a4fa1797e89c0f/ast_serialize-0.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6e15ec740436e1a0d62de848641abe5f3a2f89a7f94907d534795ac91bbacf14", size = 1067267, upload-time = "2026-06-30T20:02:28.949Z" },
+ { url = "https://files.pythonhosted.org/packages/52/19/ac8348ae8711c9b5ae834634f635780cab62a0f5e6f988882e048b89c2ae/ast_serialize-0.6.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:093cb8bb91b720d8523580498d031791bb1bbaa048599c3d21085d380e11a596", size = 1185367, upload-time = "2026-06-30T20:02:30.427Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/f6/ec7ec652c51db77c2f61d8573338e13e4704303265ccc658cb4031d9f354/ast_serialize-0.6.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e61580a69faf47e3689795367ed211f2a10fd741478cc0f36a0f128793360aad", size = 1178657, upload-time = "2026-06-30T20:02:31.964Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/02/613a7534a41d0122f37d1e0c64aa8ac78bfb831f8c92f6db057a311abb3c/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305802f2ce2a7c4e87835078ea85c58b586ddda8095b92fe2ead9364ae19c80a", size = 1238620, upload-time = "2026-06-30T20:02:33.664Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/21/087957bba486242afc52f49b2d9e21c9dad00289356cf9efe67084015a9d/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c7b8b8f0c42f752ea00b2b7d7c090b3f80d9c1c5c75cadf16423790a0cc74081", size = 1236075, upload-time = "2026-06-30T20:02:34.936Z" },
+ { url = "https://files.pythonhosted.org/packages/82/04/78128bbb170071c2c72a210a181f1c00e11cc1cec60a8beef747b07f9201/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd5b91b9e6f2356ace3a556963b0cd783b395fbbb0bb17b4defc283415466e77", size = 1441348, upload-time = "2026-06-30T20:02:36.245Z" },
+ { url = "https://files.pythonhosted.org/packages/64/64/62fb99d6faf199b4c3e5b08a07136e9a0d7664bb249c6de3670e5b63e9b6/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d6ef91590258ada18909b9caea344dac4de2013906b035473cd674a43f4b790", size = 1258580, upload-time = "2026-06-30T20:02:37.53Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/87/b4d6c38e0ccd5e85dc54cecdf933a152c60b28fe5d993a6d8a72fa6d5896/ast_serialize-0.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcbed41e9386059fc0261d602445ede0976c2ecec2939688bcbcb9ed0b6f28b7", size = 1261693, upload-time = "2026-06-30T20:02:39.123Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/4b/3676ca2191f39bafb75f93f99b2f429ec464586158fece2165f3572805dc/ast_serialize-0.6.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:cdc4e6f930b9090c2f92c9036ad12ffb8e6e44d4a5ba06f1458a05d60f203f7b", size = 1252517, upload-time = "2026-06-30T20:02:40.511Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/58/494ef8c4b4acb2f4a265ac934caf45f792a08fe27d6b853de35ad991941a/ast_serialize-0.6.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:897ac47b5637be41c0c07061c8a912fafa967ef1dc73fa115e4bfa70882a093b", size = 1304843, upload-time = "2026-06-30T20:02:41.961Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/f2/13736d920ab3d49bbee80ef1a277dd7b7aaf3b3545efd9d2a8114fe05525/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c4af9a1386166e40ed01464991806f89038a2d89782576c7774876fa77034e32", size = 1413698, upload-time = "2026-06-30T20:02:44.179Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/5a/e046f3899e2acba4677d7427b76431443a1aa1a0e583dfb05b55b69d55cf/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:c901adbd750029b9ac4ad3d6aa56853e0ad4875119fbf52b7b8298afc223828b", size = 1512209, upload-time = "2026-06-30T20:02:45.584Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/c7/e42aaca7bb2d22a7c06d5a8c7930086c5a334e93d716e6fa5e6647a4515f/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae22a366b752ab4496191525b78b097b5b72d531752e3c1dd7e383a8f2c8a1a", size = 1508464, upload-time = "2026-06-30T20:02:46.942Z" },
+ { url = "https://files.pythonhosted.org/packages/95/93/5524a3dc6c3f593de3228ed9cbef73afa047625b7000ec21b7f58e6eb4d4/ast_serialize-0.6.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4ed29121da8b3fdc291002801a1de0f76248fa07dce89157a5f277842cf6126e", size = 1457164, upload-time = "2026-06-30T20:02:48.294Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/c0/36a6ffb4d653cf621427b4c4928671f53ad800c453474de2b82564a44ad9/ast_serialize-0.6.0-cp39-abi3-pyemscripten_2026_0_wasm32.whl", hash = "sha256:b1dac4e09d341c1300ba69cdcbe62867b32a8c75d90db9bf4d083bec3b039f0b", size = 863014, upload-time = "2026-06-30T20:02:49.742Z" },
+ { url = "https://files.pythonhosted.org/packages/09/c7/7d5ad8b49e1278e1c2a1e0274bd7850560b3f09313aa00c13bc8d5544792/ast_serialize-0.6.0-cp39-abi3-win32.whl", hash = "sha256:82c312a7844d2fdeb4d5c48bd3d215bf940dafd4704e1a9bcf252a99010a99b1", size = 1063165, upload-time = "2026-06-30T20:02:50.98Z" },
+ { url = "https://files.pythonhosted.org/packages/47/ae/6710c14ecb276031cf10249f6adf5a59e2d3fdb3b5183bd59f70524067ee/ast_serialize-0.6.0-cp39-abi3-win_amd64.whl", hash = "sha256:113b58346f9ceb664352032770caca817d4a3c86f611c6088e6ef65ddaa70f0e", size = 1101444, upload-time = "2026-06-30T20:02:52.554Z" },
+ { url = "https://files.pythonhosted.org/packages/66/40/c53deb2cd0c9b0fb636d24d9f40924cf2e65028e6b20b10cd5c1eeb2c730/ast_serialize-0.6.0-cp39-abi3-win_arm64.whl", hash = "sha256:ccd132fe8db56f61fe743b1f644d01b8d65b83248a8da506f3132bda86d6ed5e", size = 1072965, upload-time = "2026-06-30T20:02:54.097Z" },
+]
+
+[[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 = "contourpy"
+version = "1.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" },
+ { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" },
+ { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" },
+ { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" },
+ { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" },
+ { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" },
+ { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" },
+ { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" },
+ { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" },
+ { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" },
+ { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" },
+ { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" },
+ { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" },
+ { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" },
+ { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" },
+ { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" },
+ { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" },
+ { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" },
+ { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" },
+ { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" },
+ { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" },
+ { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" },
+ { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" },
+ { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" },
+ { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" },
+ { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" },
+ { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" },
+ { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" },
+ { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" },
+ { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" },
+ { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" },
+ { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" },
+ { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" },
+]
+
+[[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 = "floquet-if-manybody"
+version = "0.1.0"
+source = { editable = "." }
+dependencies = [
+ { name = "matplotlib" },
+ { name = "numpy" },
+ { name = "pyyaml" },
+ { name = "scipy" },
+]
+
+[package.optional-dependencies]
+dev = [
+ { name = "mypy" },
+ { name = "pytest" },
+ { name = "ruff" },
+]
+nonmarkov = [
+ { name = "oqupy" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "matplotlib", specifier = ">=3.9" },
+ { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.14" },
+ { name = "numpy", specifier = ">=1.26,<2.0" },
+ { name = "oqupy", marker = "extra == 'nonmarkov'", specifier = "==0.5.0" },
+ { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3" },
+ { name = "pyyaml", specifier = ">=6.0" },
+ { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9" },
+ { name = "scipy", specifier = ">=1.14" },
+]
+provides-extras = ["dev", "nonmarkov"]
+
+[[package]]
+name = "fonttools"
+version = "4.63.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/75/2b/a7f1545bdf5da69c4bda0cea2a5781f0ad2a6623e0277267672db43c5fe6/fonttools-4.63.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b8ae05d9eacf6081414d759c0a352769ac28ce31280d6bb8e77b03f9e3c449f", size = 2881793, upload-time = "2026-05-14T12:02:56.645Z" },
+ { url = "https://files.pythonhosted.org/packages/49/50/965308c703f085f225db2886813b27e015b8b3438c350b22dd65b52c2a2c/fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79cdc9f567aec74a72918fd060283911406750cbc9fd28c1316023deb6ce31a9", size = 2428130, upload-time = "2026-05-14T12:02:58.891Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/38/6937fbd7f2dc3a6b48725851bc2c15ec949b9af14d9bbcb5fe83cdf9bdf9/fonttools-4.63.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c14b4fd138c4bafcca294765c547914e1aa431ae1ca94ab99d8db08c958bd3b", size = 5111952, upload-time = "2026-05-14T12:03:01.263Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/43/a81f20050a3115b57d62c8e781446949512eac36690dc384ccea65ff4cc1/fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76ac49f929aecaf82d83250b8347e099d7aecba0f4726c1d9b6df3b8bb5fe18", size = 5082308, upload-time = "2026-05-14T12:03:03.211Z" },
+ { url = "https://files.pythonhosted.org/packages/67/00/cdd9d4944ca6ae280d01e69cc37bde3bf663630b837a6fc6d2cd65d80e0e/fonttools-4.63.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dcf076a4474fe0d7367e5bbf5b052c7284fa1feca729c04176ce513521afd8a0", size = 5087932, upload-time = "2026-05-14T12:03:05.147Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/f1/0aa0dbea778c75adbef223c42019fd47d22262b905974d62d829545d485f/fonttools-4.63.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7dd683fef0663e9f0f45cf541d788d24caa3ec9db50796b588e1757d8b3bc007", size = 5213271, upload-time = "2026-05-14T12:03:07.238Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/99/253e4056e1f0e67b9390125a154b73b5eb73ad521bece95c004858fdeec2/fonttools-4.63.0-cp311-cp311-win32.whl", hash = "sha256:afefc1ed0a59785a7fb06ea7e1678e849c193e1e387db783579bc7b3056fcfcb", size = 2304473, upload-time = "2026-05-14T12:03:09.271Z" },
+ { url = "https://files.pythonhosted.org/packages/08/60/defa5e69641db890a63be281f41345f4c33b157824eaf0b9fad3e08b0dcb/fonttools-4.63.0-cp311-cp311-win_amd64.whl", hash = "sha256:063e08bd17bd5a90127a14123de0d6a952dbc847695fd98b63c043d58057f90c", size = 2356389, upload-time = "2026-05-14T12:03:11.53Z" },
+ { url = "https://files.pythonhosted.org/packages/08/ef/b3c6b9b5be2f82416d73fe2ed2e96e2793cd80e7510bd6a17ca79cdd88ec/fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02", size = 2881131, upload-time = "2026-05-14T12:03:13.386Z" },
+ { url = "https://files.pythonhosted.org/packages/44/a0/c815bea63117fa63e4e1c01f8a1110d2112fa003f838e6467094ec2432ce/fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0", size = 2426704, upload-time = "2026-05-14T12:03:15.801Z" },
+ { url = "https://files.pythonhosted.org/packages/44/04/0b91d8e916e92ad1fac9e4624760baf0fd5ff2ead614c2f68fb21373f03f/fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af", size = 5044298, upload-time = "2026-05-14T12:03:18.085Z" },
+ { url = "https://files.pythonhosted.org/packages/77/c7/2342da9830e3e9d4870305ca5d2091d2a83284f2953079b7bdd3b5e029d8/fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8", size = 4999800, upload-time = "2026-05-14T12:03:20.161Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/6d/67fe16c48d7ce050979b33f47e0d28a318f02da030602e944c34f7a16ef3/fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b", size = 4982666, upload-time = "2026-05-14T12:03:22.87Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/00/3bbab338c07c71fa56269953845e92c951a61457bbbb0f1022551ea266d9/fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78", size = 5133598, upload-time = "2026-05-14T12:03:25.168Z" },
+ { url = "https://files.pythonhosted.org/packages/62/f2/aa27c7f98db5b064883dadcc5283947e81e034de42e22a33675878d98b54/fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263", size = 2292575, upload-time = "2026-05-14T12:03:27.496Z" },
+ { url = "https://files.pythonhosted.org/packages/87/36/cccb9bc2a6ab63d1b2980374f0dca72ce95ae267c9b4cfe77455bb70d0d4/fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272", size = 2343211, upload-time = "2026-05-14T12:03:30.057Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/8d/d8fec3dcde2963f8c908fb315e5ff2cd0ac34f82394bbbf73a2aa5145ce3/fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd", size = 2876062, upload-time = "2026-05-14T12:03:32.554Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/71/d935dc54e4ff121bfdd11e08702db63a7e6f25af21d8a3d7b7212df53641/fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59", size = 2424594, upload-time = "2026-05-14T12:03:34.86Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/40/e76320afa1df918e146155ef239b1719ee266092e96f5423bfd075affba1/fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d", size = 5024840, upload-time = "2026-05-14T12:03:36.745Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/36/0b805d8c485f872f65a509cbe3b58a5d0d17bee855333b54a150c79d3061/fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68", size = 4975801, upload-time = "2026-05-14T12:03:38.833Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/26/2cee03d0aa083ab022da5c07aff9ed3f689da1defb81ad6917c9627896da/fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be", size = 4965009, upload-time = "2026-05-14T12:03:41.494Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/48/cc4b66d9058c0d0982c833fad10127c4b0e9324606aafa41382295ca4102/fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27", size = 5105892, upload-time = "2026-05-14T12:03:43.525Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/1f/a98a30a814b9ddef3a2e706025f90b9e0bc94890e6cb15254bc86547d11a/fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380", size = 2291313, upload-time = "2026-05-14T12:03:45.594Z" },
+ { url = "https://files.pythonhosted.org/packages/92/46/5177b01f3b4abfdd4409f31cca4ab279c9343a26efbe9ec78c97fc612e02/fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b", size = 2342299, upload-time = "2026-05-14T12:03:47.414Z" },
+ { url = "https://files.pythonhosted.org/packages/27/d2/23d25e3f247b328be58d04a4c9f894178a0d1eda7d42867cfb388adaf416/fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fd1e3094f42d806d3d7c79162fc59e5910fcbe3a7360c385b8da969bc4493745", size = 2875338, upload-time = "2026-05-14T12:03:50.052Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/58/7dfa0c761cb3b2964e2a84c4dc986c926a87de0cb9fb60d5b28ded3f2914/fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6e528da43bc3791085f8cb6141b1d13e459226790240340fcbb4625649238b03", size = 2422661, upload-time = "2026-05-14T12:03:52.154Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/87/64cfa18a7a1621d17b7f4502b2b0ed8a135a90c3db51ea590ee99043e76b/fonttools-4.63.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b2248c5decb223562f7902ff6325077a073f608ee8e33e88ad88db734eb9f49", size = 5010526, upload-time = "2026-05-14T12:03:54.647Z" },
+ { url = "https://files.pythonhosted.org/packages/36/e1/a8933a72c45a87177fbde2696e0d0755c8c9062f8c077a961c6215fa27b1/fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:308f957cdeaf8abe4e5f2f124902ef405448af92c90f80e302a3b771c2e6116b", size = 4923946, upload-time = "2026-05-14T12:03:56.984Z" },
+ { url = "https://files.pythonhosted.org/packages/27/60/872e6e233b8c5e8b41413796ff18b7fe479661bd40147e071b450dfad7a1/fonttools-4.63.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bf00f21eb5fb721dbaf73d1e9da6d02a1af7768f2ebcf9798be98beab8ba90f6", size = 4962489, upload-time = "2026-05-14T12:03:59.443Z" },
+ { url = "https://files.pythonhosted.org/packages/30/c4/83c24f2ec38b90cfda84bf4b1a1f49df80e84a1db4e7ac6e0d41bf23bc39/fonttools-4.63.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1aaa4b9c75798400ac043ce04d74e7830376c85095a5a6ed7cba2f17a266bf4", size = 5071870, upload-time = "2026-05-14T12:04:02.122Z" },
+ { url = "https://files.pythonhosted.org/packages/de/40/3ae22b60ff1d41ce0bd044b31238cdc72cef99f28b976f1e128ebd618c9b/fonttools-4.63.0-cp314-cp314-win32.whl", hash = "sha256:22693918177bd9ceabec4736d338045f357769416fc6b0b2508eefef75b08616", size = 2295026, upload-time = "2026-05-14T12:04:04.47Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/d4/98078064ccc76b45cb0f6c002452011e93c4bd26f6850344f0951cc1fe89/fonttools-4.63.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d782fac32985914c351556f68ac0855391572bcd87de50e05970d3cd4c96fc5", size = 2347454, upload-time = "2026-05-14T12:04:06.752Z" },
+ { url = "https://files.pythonhosted.org/packages/49/4e/652d1580c5f4e39f7d103b0c793e4773129ad633dce4addd0cf4dfebde02/fonttools-4.63.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6db5140a60a5d731d21ec076745b40a310607731b0a565b50776393188649001", size = 2958152, upload-time = "2026-05-14T12:04:08.706Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/55/ad864c9a9b219f552eb46b32cd7906c466e5a578ba0c3abfcc0fe7413eb6/fonttools-4.63.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d76edbff9014094dbf03bd2d074709dfa6ec7aba13d838c937a2b33d2d6a86e", size = 2460809, upload-time = "2026-05-14T12:04:10.783Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/2b/0aa8db70f18cf52e49b4ed5ecec68547f981160bf5ded3b5aed6faa0a6f9/fonttools-4.63.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eac00b9118c3c2f87d272e45341871c5b3066baa3c86897fa634a7c3fb59096", size = 5148649, upload-time = "2026-05-14T12:04:12.747Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/63/18e4369c25043096f1048e0c9915951adc4f842bd81c6b18155824d6fa99/fonttools-4.63.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51394295f1a51de8b5f30bdb1e1b9a4231536c7064ef5c6e211eec19fa36036f", size = 4932147, upload-time = "2026-05-14T12:04:14.806Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/3f/67f3eac2ffd8a98446c5022f8ed3864eac878a5ff7af8df4c8286dba16cc/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9e12f105d2b6342c559c298afb674006bb2893afc7102dcf8a1b55b0486b4e40", size = 5027237, upload-time = "2026-05-14T12:04:17.675Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/ba/4e6214cb38a7b04779e97bb7636de9a5c7f20af7018d03dee0b64c08510a/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:796f27556dbe094c4824f75ca85267e4df776c79036c8441469a4df37038c196", size = 5053933, upload-time = "2026-05-14T12:04:20.818Z" },
+ { url = "https://files.pythonhosted.org/packages/34/3b/214dcc19ee31d3d38fb5ad2755c11ef0514e5dc300bbaf41c0b69f393799/fonttools-4.63.0-cp314-cp314t-win32.whl", hash = "sha256:948428a275741f0b64b113c955425a953314f4b9ab9997f73a72c83e68e569c8", size = 2359326, upload-time = "2026-05-14T12:04:24.22Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/1e/3ff1a9b523058c2eeb6a9d50f5574e2a738200d0d94107d5bc4105e8da3f/fonttools-4.63.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6d4741eb179121cab9eea4cb2393d24492373a260d7945006358c08cfbf45419", size = 2425829, upload-time = "2026-05-14T12:04:26.829Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" },
+]
+
+[[package]]
+name = "graphviz"
+version = "0.21"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f8/b3/3ac91e9be6b761a4b30d66ff165e54439dcd48b83f4e20d644867215f6ca/graphviz-0.21.tar.gz", hash = "sha256:20743e7183be82aaaa8ad6c93f8893c923bd6658a04c32ee115edb3c8a835f78", size = 200434, upload-time = "2025-06-15T09:35:05.824Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" },
+]
+
+[[package]]
+name = "h5py"
+version = "3.16.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/db/33/acd0ce6863b6c0d7735007df01815403f5589a21ff8c2e1ee2587a38f548/h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738", size = 446526, upload-time = "2026-03-06T13:49:08.07Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ba/95/a825894f3e45cbac7554c4e97314ce886b233a20033787eda755ca8fecc7/h5py-3.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:719439d14b83f74eeb080e9650a6c7aa6d0d9ea0ca7f804347b05fac6fbf18af", size = 3721663, upload-time = "2026-03-06T13:47:49.599Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/3b/38ff88b347c3e346cda1d3fc1b65a7aa75d40632228d8b8a5d7b58508c24/h5py-3.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3f0a0e136f2e95dd0b67146abb6668af4f1a69c81ef8651a2d316e8e01de447", size = 3087630, upload-time = "2026-03-06T13:47:51.249Z" },
+ { url = "https://files.pythonhosted.org/packages/98/a8/2594cef906aee761601eff842c7dc598bea2b394a3e1c00966832b8eeb7c/h5py-3.16.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a6fbc5367d4046801f9b7db9191b31895f22f1c6df1f9987d667854cac493538", size = 4823472, upload-time = "2026-03-06T13:47:53.085Z" },
+ { url = "https://files.pythonhosted.org/packages/52/a0/c1f604538ff6db22a0690be2dc44ab59178e115f63c917794e529356ab23/h5py-3.16.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fb1720028d99040792bb2fb31facb8da44a6f29df7697e0b84f0d79aff2e9bd3", size = 5027150, upload-time = "2026-03-06T13:47:55.043Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/fd/301739083c2fc4fd89950f9bcfce75d6e14b40b0ca3d40e48a8993d1722c/h5py-3.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:314b6054fe0b1051c2b0cb2df5cbdab15622fb05e80f202e3b6a5eee0d6fe365", size = 4814544, upload-time = "2026-03-06T13:47:56.893Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/42/2193ed41ccee78baba8fcc0cff2c925b8b9ee3793305b23e1f22c20bf4c7/h5py-3.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ffbab2fedd6581f6aa31cf1639ca2cb86e02779de525667892ebf4cc9fd26434", size = 5034013, upload-time = "2026-03-06T13:47:59.01Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/20/e6c0ff62ca2ad1a396a34f4380bafccaaf8791ff8fccf3d995a1fc12d417/h5py-3.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d1f1630f92ad74494a9a7392ab25982ce2b469fc62da6074c0ce48366a2999", size = 3191673, upload-time = "2026-03-06T13:48:00.626Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/48/239cbe352ac4f2b8243a8e620fa1a2034635f633731493a7ff1ed71e8658/h5py-3.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:85b9c49dd58dc44cf70af944784e2c2038b6f799665d0dcbbc812a26e0faa859", size = 2673834, upload-time = "2026-03-06T13:48:02.579Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/c0/5d4119dba94093bbafede500d3defd2f5eab7897732998c04b54021e530b/h5py-3.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c5313566f4643121a78503a473f0fb1e6dcc541d5115c44f05e037609c565c4d", size = 3685604, upload-time = "2026-03-06T13:48:04.198Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/42/c84efcc1d4caebafb1ecd8be4643f39c85c47a80fe254d92b8b43b1eadaf/h5py-3.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42b012933a83e1a558c673176676a10ce2fd3759976a0fedee1e672d1e04fc9d", size = 3061940, upload-time = "2026-03-06T13:48:05.783Z" },
+ { url = "https://files.pythonhosted.org/packages/89/84/06281c82d4d1686fde1ac6b0f307c50918f1c0151062445ab3b6fa5a921d/h5py-3.16.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ff24039e2573297787c3063df64b60aab0591980ac898329a08b0320e0cf2527", size = 5198852, upload-time = "2026-03-06T13:48:07.482Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/e9/1a19e42cd43cc1365e127db6aae85e1c671da1d9a5d746f4d34a50edb577/h5py-3.16.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:dfc21898ff025f1e8e67e194965a95a8d4754f452f83454538f98f8a3fcb207e", size = 5405250, upload-time = "2026-03-06T13:48:09.628Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/8e/9790c1655eabeb85b92b1ecab7d7e62a2069e53baefd58c98f0909c7a948/h5py-3.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:698dd69291272642ffda44a0ecd6cd3bda5faf9621452d255f57ce91487b9794", size = 5190108, upload-time = "2026-03-06T13:48:11.26Z" },
+ { url = "https://files.pythonhosted.org/packages/51/d7/ab693274f1bd7e8c5f9fdd6c7003a88d59bedeaf8752716a55f532924fbb/h5py-3.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b2c02b0a160faed5fb33f1ba8a264a37ee240b22e049ecc827345d0d9043074", size = 5419216, upload-time = "2026-03-06T13:48:13.322Z" },
+ { url = "https://files.pythonhosted.org/packages/03/c1/0976b235cf29ead553e22f2fb6385a8252b533715e00d0ae52ed7b900582/h5py-3.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:96b422019a1c8975c2d5dadcf61d4ba6f01c31f92bbde6e4649607885fe502d6", size = 3182868, upload-time = "2026-03-06T13:48:15.759Z" },
+ { url = "https://files.pythonhosted.org/packages/14/d9/866b7e570b39070f92d47b0ff1800f0f8239b6f9e45f02363d7112336c1f/h5py-3.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:39c2838fb1e8d97bcf1755e60ad1f3dd76a7b2a475928dc321672752678b96db", size = 2653286, upload-time = "2026-03-06T13:48:17.279Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/9e/6142ebfda0cb6e9349c091eae73c2e01a770b7659255248d637bec54a88b/h5py-3.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:370a845f432c2c9619db8eed334d1e610c6015796122b0e57aa46312c22617d9", size = 3671808, upload-time = "2026-03-06T13:48:19.737Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/65/5e088a45d0f43cd814bc5bec521c051d42005a472e804b1a36c48dada09b/h5py-3.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42108e93326c50c2810025aade9eac9d6827524cdccc7d4b75a546e5ab308edb", size = 3045837, upload-time = "2026-03-06T13:48:21.854Z" },
+ { url = "https://files.pythonhosted.org/packages/da/1e/6172269e18cc5a484e2913ced33339aad588e02ba407fafd00d369e22ef3/h5py-3.16.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:099f2525c9dcf28de366970a5fb34879aab20491589fa89ce2863a84218bb524", size = 5193860, upload-time = "2026-03-06T13:48:24.071Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/98/ef2b6fe2903e377cbe870c3b2800d62552f1e3dbe81ce49e1923c53d1c5c/h5py-3.16.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:9300ad32dea9dfc5171f94d5f6948e159ed93e4701280b0f508773b3f582f402", size = 5400417, upload-time = "2026-03-06T13:48:25.728Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/81/5b62d760039eed64348c98129d17061fdfc7839fc9c04eaaad6dee1004e4/h5py-3.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:171038f23bccddfc23f344cadabdfc9917ff554db6a0d417180d2747fe4c75a7", size = 5185214, upload-time = "2026-03-06T13:48:27.436Z" },
+ { url = "https://files.pythonhosted.org/packages/28/c4/532123bcd9080e250696779c927f2cb906c8bf3447df98f5ceb8dcded539/h5py-3.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7e420b539fb6023a259a1b14d4c9f6df8cf50d7268f48e161169987a57b737ff", size = 5414598, upload-time = "2026-03-06T13:48:29.49Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/d9/a27997f84341fc0dfcdd1fe4179b6ba6c32a7aa880fdb8c514d4dad6fba3/h5py-3.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:18f2bbcd545e6991412253b98727374c356d67caa920e68dc79eab36bf5fedad", size = 3175509, upload-time = "2026-03-06T13:48:31.131Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/23/bb8647521d4fd770c30a76cfc6cb6a2f5495868904054e92f2394c5a78ff/h5py-3.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:656f00e4d903199a1d58df06b711cf3ca632b874b4207b7dbec86185b5c8c7d4", size = 2647362, upload-time = "2026-03-06T13:48:33.411Z" },
+ { url = "https://files.pythonhosted.org/packages/48/3c/7fcd9b4c9eed82e91fb15568992561019ae7a829d1f696b2c844355d95dd/h5py-3.16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9c9d307c0ef862d1cd5714f72ecfafe0a5d7529c44845afa8de9f46e5ba8bd65", size = 3678608, upload-time = "2026-03-06T13:48:35.183Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/b7/9366ed44ced9b7ef357ab48c94205280276db9d7f064aa3012a97227e966/h5py-3.16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8c1eff849cdd53cbc73c214c30ebdb6f1bb8b64790b4b4fc36acdb5e43570210", size = 3054773, upload-time = "2026-03-06T13:48:37.139Z" },
+ { url = "https://files.pythonhosted.org/packages/58/a5/4964bc0e91e86340c2bbda83420225b2f770dcf1eb8a39464871ad769436/h5py-3.16.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:e2c04d129f180019e216ee5f9c40b78a418634091c8782e1f723a6ca3658b965", size = 5198886, upload-time = "2026-03-06T13:48:38.879Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/16/d905e7f53e661ce2c24686c38048d8e2b750ffc4350009d41c4e6c6c9826/h5py-3.16.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e4360f15875a532bc7b98196c7592ed4fc92672a57c0a621355961cafb17a6dd", size = 5404883, upload-time = "2026-03-06T13:48:41.324Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/f2/58f34cb74af46d39f4cd18ea20909a8514960c5a3e5b92fd06a28161e0a8/h5py-3.16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3fae9197390c325e62e0a1aa977f2f62d994aa87aab182abbea85479b791197c", size = 5192039, upload-time = "2026-03-06T13:48:43.117Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/ca/934a39c24ce2e2db017268c08da0537c20fa0be7e1549be3e977313fc8f5/h5py-3.16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:43259303989ac8adacc9986695b31e35dba6fd1e297ff9c6a04b7da5542139cc", size = 5421526, upload-time = "2026-03-06T13:48:44.838Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/14/615a450205e1b56d16c6783f5ccd116cde05550faad70ae077c955654a75/h5py-3.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:fa48993a0b799737ba7fd21e2350fa0a60701e58180fae9f2de834bc39a147ab", size = 3183263, upload-time = "2026-03-06T13:48:47.117Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/48/a6faef5ed632cae0c65ac6b214a6614a0b510c3183532c521bdb0055e117/h5py-3.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:1897a771a7f40d05c262fc8f37376ec37873218544b70216872876c627640f63", size = 2663450, upload-time = "2026-03-06T13:48:48.707Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/32/0c8bb8aedb62c772cf7c1d427c7d1951477e8c2835f872bc0a13d1f85f86/h5py-3.16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:15922e485844f77c0b9d275396d435db3baa58292a9c2176a386e072e0cf2491", size = 3760693, upload-time = "2026-03-06T13:48:50.453Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/1f/fcc5977d32d6387c5c9a694afee716a5e20658ac08b3ff24fdec79fb05f2/h5py-3.16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:df02dd29bd247f98674634dfe41f89fd7c16ba3d7de8695ec958f58404a4e618", size = 3181305, upload-time = "2026-03-06T13:48:52.221Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/a1/af87f64b9f986889884243643621ebbd4ac72472ba8ec8cec891ac8e2ca1/h5py-3.16.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0f456f556e4e2cebeebd9d66adf8dc321770a42593494a0b6f0af54a7567b242", size = 5074061, upload-time = "2026-03-06T13:48:54.089Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/d0/146f5eaff3dc246a9c7f6e5e4f42bd45cc613bce16693bcd4d1f7c958bf5/h5py-3.16.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:3e6cb3387c756de6a9492d601553dffea3fe11b5f22b443aac708c69f3f55e16", size = 5279216, upload-time = "2026-03-06T13:48:56.75Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/9d/12a13424f1e604fc7df9497b73c0356fb78c2fb206abd7465ce47226e8fd/h5py-3.16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8389e13a1fd745ad2856873e8187fd10268b2d9677877bb667b41aebd771d8b7", size = 5070068, upload-time = "2026-03-06T13:48:59.169Z" },
+ { url = "https://files.pythonhosted.org/packages/41/8c/bbe98f813722b4873818a8db3e15aa3e625b59278566905ac439725e8070/h5py-3.16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:346df559a0f7dcb31cf8e44805319e2ab24b8957c45e7708ce503b2ec79ba725", size = 5300253, upload-time = "2026-03-06T13:49:02.033Z" },
+ { url = "https://files.pythonhosted.org/packages/32/9e/87e6705b4d6890e7cecdf876e2a7d3e40654a2ae37482d79a6f1b87f7b92/h5py-3.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4c6ab014ab704b4feaa719ae783b86522ed0bf1f82184704ed3c9e4e3228796e", size = 3381671, upload-time = "2026-03-06T13:49:04.351Z" },
+ { url = "https://files.pythonhosted.org/packages/96/91/9fad90cfc5f9b2489c7c26ad897157bce82f0e9534a986a221b99760b23b/h5py-3.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:faca8fb4e4319c09d83337adc80b2ca7d5c5a343c2d6f1b6388f32cfecca13c1", size = 2740706, upload-time = "2026-03-06T13:49:06.347Z" },
+]
+
+[[package]]
+name = "iniconfig"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
+]
+
+[[package]]
+name = "kiwisolver"
+version = "1.5.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/12/dd/a495a9c104be1c476f0386e714252caf2b7eca883915422a64c50b88c6f5/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c", size = 122798, upload-time = "2026-03-09T13:12:58.963Z" },
+ { url = "https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb", size = 66216, upload-time = "2026-03-09T13:13:00.155Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/aa/510dc933d87767584abfe03efa445889996c70c2990f6f87c3ebaa0a18c5/kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac", size = 63911, upload-time = "2026-03-09T13:13:01.671Z" },
+ { url = "https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27", size = 1438209, upload-time = "2026-03-09T13:13:03.385Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/d6/76621246f5165e5372f02f5e6f3f48ea336a8f9e96e43997d45b240ed8cd/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398", size = 1248888, upload-time = "2026-03-09T13:13:05.231Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/c1/31559ec6fb39a5b48035ce29bb63ade628f321785f38c384dee3e2c08bc1/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db", size = 1266304, upload-time = "2026-03-09T13:13:06.743Z" },
+ { url = "https://files.pythonhosted.org/packages/5e/ef/1cb8276f2d29cc6a41e0a042f27946ca347d3a4a75acf85d0a16aa6dcc82/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc", size = 1319650, upload-time = "2026-03-09T13:13:08.607Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/e4/5ba3cecd7ce6236ae4a80f67e5d5531287337d0e1f076ca87a5abe4cd5d0/kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679", size = 970949, upload-time = "2026-03-09T13:13:10.299Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/69/dc61f7ae9a2f071f26004ced87f078235b5507ab6e5acd78f40365655034/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309", size = 2199125, upload-time = "2026-03-09T13:13:11.841Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/7b/abbe0f1b5afa85f8d084b73e90e5f801c0939eba16ac2e49af7c61a6c28d/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2", size = 2293783, upload-time = "2026-03-09T13:13:14.399Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/80/5908ae149d96d81580d604c7f8aefd0e98f4fd728cf172f477e9f2a81744/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c", size = 1960726, upload-time = "2026-03-09T13:13:16.047Z" },
+ { url = "https://files.pythonhosted.org/packages/84/08/a78cb776f8c085b7143142ce479859cfec086bd09ee638a317040b6ef420/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08", size = 2464738, upload-time = "2026-03-09T13:13:17.897Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/e1/65584da5356ed6cb12c63791a10b208860ac40a83de165cb6a6751a686e3/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4", size = 2270718, upload-time = "2026-03-09T13:13:19.421Z" },
+ { url = "https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b", size = 73480, upload-time = "2026-03-09T13:13:20.818Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/0e/2ee5debc4f77a625778fec5501ff3e8036fe361b7ee28ae402a485bb9694/kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac", size = 64930, upload-time = "2026-03-09T13:13:21.997Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" },
+ { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" },
+ { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" },
+ { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" },
+ { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" },
+ { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" },
+ { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" },
+ { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" },
+ { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" },
+ { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" },
+ { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" },
+ { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" },
+ { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" },
+ { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" },
+ { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" },
+ { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/d7/060f45052f2a01ad5762c8fdecd6d7a752b43400dc29ff75cd47225a40fd/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615", size = 123231, upload-time = "2026-03-09T13:14:41.323Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02", size = 66489, upload-time = "2026-03-09T13:14:42.534Z" },
+ { url = "https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e", size = 64063, upload-time = "2026-03-09T13:14:44.759Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac", size = 1475913, upload-time = "2026-03-09T13:14:46.247Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/f0/f768ae564a710135630672981231320bc403cf9152b5596ec5289de0f106/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05", size = 1282782, upload-time = "2026-03-09T13:14:48.458Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/9f/1de7aad00697325f05238a5f2eafbd487fb637cc27a558b5367a5f37fb7f/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd", size = 1300815, upload-time = "2026-03-09T13:14:50.721Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/c2/297f25141d2e468e0ce7f7a7b92e0cf8918143a0cbd3422c1ad627e85a06/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a", size = 1347925, upload-time = "2026-03-09T13:14:52.304Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/d3/f4c73a02eb41520c47610207b21afa8cdd18fdbf64ffd94674ae21c4812d/kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554", size = 991322, upload-time = "2026-03-09T13:14:54.637Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/46/d3f2efef7732fcda98d22bf4ad5d3d71d545167a852ca710a494f4c15343/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581", size = 2232857, upload-time = "2026-03-09T13:14:56.471Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/ec/2d9756bf2b6d26ae4349b8d3662fb3993f16d80c1f971c179ce862b9dbae/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303", size = 2329376, upload-time = "2026-03-09T13:14:58.072Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/9f/876a0a0f2260f1bde92e002b3019a5fabc35e0939c7d945e0fa66185eb20/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9", size = 1982549, upload-time = "2026-03-09T13:14:59.668Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/4f/ba3624dfac23a64d54ac4179832860cb537c1b0af06024936e82ca4154a0/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79", size = 2494680, upload-time = "2026-03-09T13:15:01.364Z" },
+ { url = "https://files.pythonhosted.org/packages/39/b7/97716b190ab98911b20d10bf92eca469121ec483b8ce0edd314f51bc85af/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796", size = 2297905, upload-time = "2026-03-09T13:15:03.925Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e", size = 75086, upload-time = "2026-03-09T13:15:07.775Z" },
+ { url = "https://files.pythonhosted.org/packages/70/15/9b90f7df0e31a003c71649cf66ef61c3c1b862f48c81007fa2383c8bd8d7/kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df", size = 66577, upload-time = "2026-03-09T13:15:09.139Z" },
+ { url = "https://files.pythonhosted.org/packages/17/01/7dc8c5443ff42b38e72731643ed7cf1ed9bf01691ae5cdca98501999ed83/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e", size = 125794, upload-time = "2026-03-09T13:15:10.525Z" },
+ { url = "https://files.pythonhosted.org/packages/46/8a/b4ebe46ebaac6a303417fab10c2e165c557ddaff558f9699d302b256bc53/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4", size = 67646, upload-time = "2026-03-09T13:15:12.016Z" },
+ { url = "https://files.pythonhosted.org/packages/60/35/10a844afc5f19d6f567359bf4789e26661755a2f36200d5d1ed8ad0126e5/kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028", size = 65511, upload-time = "2026-03-09T13:15:13.311Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/8a/685b297052dd041dcebce8e8787b58923b6e78acc6115a0dc9189011c44b/kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657", size = 1584858, upload-time = "2026-03-09T13:15:15.103Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/80/04865e3d4638ac5bddec28908916df4a3075b8c6cc101786a96803188b96/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920", size = 1392539, upload-time = "2026-03-09T13:15:16.661Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/01/77a19cacc0893fa13fafa46d1bba06fb4dc2360b3292baf4b56d8e067b24/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9", size = 1405310, upload-time = "2026-03-09T13:15:18.229Z" },
+ { url = "https://files.pythonhosted.org/packages/53/39/bcaf5d0cca50e604cfa9b4e3ae1d64b50ca1ae5b754122396084599ef903/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d", size = 1456244, upload-time = "2026-03-09T13:15:20.444Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/7a/72c187abc6975f6978c3e39b7cf67aeb8b3c0a8f9790aa7fd412855e9e1f/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65", size = 1073154, upload-time = "2026-03-09T13:15:22.039Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/ca/cf5b25783ebbd59143b4371ed0c8428a278abe68d6d0104b01865b1bbd0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa", size = 2334377, upload-time = "2026-03-09T13:15:23.741Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/e5/b1f492adc516796e88751282276745340e2a72dcd0d36cf7173e0daf3210/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0", size = 2425288, upload-time = "2026-03-09T13:15:25.789Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/e5/9b21fbe91a61b8f409d74a26498706e97a48008bfcd1864373d32a6ba31c/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9", size = 2063158, upload-time = "2026-03-09T13:15:27.63Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/02/83f47986138310f95ea95531f851b2a62227c11cbc3e690ae1374fe49f0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f", size = 2597260, upload-time = "2026-03-09T13:15:29.421Z" },
+ { url = "https://files.pythonhosted.org/packages/07/18/43a5f24608d8c313dd189cf838c8e68d75b115567c6279de7796197cfb6a/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646", size = 2394403, upload-time = "2026-03-09T13:15:31.517Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/b5/98222136d839b8afabcaa943b09bd05888c2d36355b7e448550211d1fca4/kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681", size = 79687, upload-time = "2026-03-09T13:15:33.204Z" },
+ { url = "https://files.pythonhosted.org/packages/99/a2/ca7dc962848040befed12732dff6acae7fb3c4f6fc4272b3f6c9a30b8713/kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57", size = 70032, upload-time = "2026-03-09T13:15:34.411Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/eb/5fcbbbf9a0e2c3a35effb88831a483345326bbc3a030a3b5b69aee647f84/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232", size = 59532, upload-time = "2026-03-09T13:15:47.047Z" },
+ { url = "https://files.pythonhosted.org/packages/c3/9b/e17104555bb4db148fd52327feea1e96be4b88e8e008b029002c281a21ab/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a", size = 57420, upload-time = "2026-03-09T13:15:48.199Z" },
+ { url = "https://files.pythonhosted.org/packages/48/44/2b5b95b7aa39fb2d8d9d956e0f3d5d45aef2ae1d942d4c3ffac2f9cfed1a/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737", size = 79892, upload-time = "2026-03-09T13:15:49.694Z" },
+ { url = "https://files.pythonhosted.org/packages/52/7d/7157f9bba6b455cfb4632ed411e199fc8b8977642c2b12082e1bd9e6d173/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16", size = 77603, upload-time = "2026-03-09T13:15:50.945Z" },
+ { url = "https://files.pythonhosted.org/packages/0a/dd/8050c947d435c8d4bc94e3252f4d8bb8a76cfb424f043a8680be637a57f1/kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1", size = 73558, upload-time = "2026-03-09T13:15:52.112Z" },
+]
+
+[[package]]
+name = "librt"
+version = "0.13.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/dc/2f/3908645ddddab7120b46295e541ead308109fa48dbec7d67d7a778870d60/librt-0.13.0.tar.gz", hash = "sha256:1d2a610c14ac0d0750ee0a3ab8548e83155258387891caaca04def4bf7289781", size = 211402, upload-time = "2026-07-08T12:26:29.834Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/89/25/a6498964cfeec270c468cffdc118f69c29b412593610d55fa1327ca51ff4/librt-0.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1b5a7bbff495baedbd9b916c367d66854008f8f3b575908ded477c499dc60082", size = 148029, upload-time = "2026-07-08T12:24:45.961Z" },
+ { url = "https://files.pythonhosted.org/packages/78/59/dc86d1bffd8e0c2818bace29d9f7783cfbb8e0673bf3673b5bbd5bbe0420/librt-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34bc7938b9fdf14fe32a406c19c71faf894c5cee7e7474bd0be2f17200b82d14", size = 153036, upload-time = "2026-07-08T12:24:47.257Z" },
+ { url = "https://files.pythonhosted.org/packages/29/3f/b923826660f02f286186cd9303d52bb05ced0a13708edc104dc8480920e3/librt-0.13.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f40e56b61b41be5f7dec938cfeffd660668cf4b5e72c78e7bd671d66b7bc2c79", size = 493062, upload-time = "2026-07-08T12:24:48.483Z" },
+ { url = "https://files.pythonhosted.org/packages/88/87/6c0980a9c9b1302cb68d108906697b89eceb55889bb1dcf77c109aa56ca5/librt-0.13.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:9c5d02b89de5acd0379a51ec44a89476fb03df6145442e1c8ecd6bee2f91b176", size = 485510, upload-time = "2026-07-08T12:24:49.727Z" },
+ { url = "https://files.pythonhosted.org/packages/32/81/795ae3b9df5dd94079fb807e38191855e023e8c6249014ae6bc3f0d9a490/librt-0.13.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7db9a3ff32ef5f7d1703d93831a3316cdf0b537de6a1cc03cc8fdd09b9194e89", size = 515909, upload-time = "2026-07-08T12:24:51.135Z" },
+ { url = "https://files.pythonhosted.org/packages/20/e5/182de15abce8907108a6fdb41487de65beb5099b74dc5841b19b099168db/librt-0.13.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3dbb2a31882456cadc7053378e81ad7ed7693db4ac9f98ab5f81ef034aa8ec9f", size = 508620, upload-time = "2026-07-08T12:24:52.358Z" },
+ { url = "https://files.pythonhosted.org/packages/32/03/33978d32db76e1f66377e8f78e42a2ca3c162143331677d1f50bbad36cfb/librt-0.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c6014e3c80f9c1fe268ef8b0e0ef113bac672cc032f2f93866e7ddad4f3e663d", size = 530363, upload-time = "2026-07-08T12:24:53.503Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/f5/b291fbd2d00f7d8287bcbf67b5aa0c6afed4bc26cef23e079629c47a2c04/librt-0.13.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:091b60a4d2174fc1ec5c34cdc0b72efb6224753d76b7da61ebeab7a191aec8bd", size = 534209, upload-time = "2026-07-08T12:24:55.138Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/03/6f41f17939d191bc21609f220da8509316bc62797f078545fe83be522e78/librt-0.13.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:66cb1138f384a191a6d75f986064841fcfdc0cea98f7bd9c9ab9b38049917588", size = 514254, upload-time = "2026-07-08T12:24:56.276Z" },
+ { url = "https://files.pythonhosted.org/packages/af/c2/2e4befa5410a7443019c14abccc94ff619797171f6b72013635fb87f31d7/librt-0.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:17221a7569f8f292aa0014226e48aa25b8c2b08da18088cd230953d0ea0f9cd1", size = 557611, upload-time = "2026-07-08T12:24:57.561Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/54/8b69f81448417adbc040a2185f4e2eece1e1994b7dcfaeed4662b30f98a5/librt-0.13.0-cp311-cp311-win32.whl", hash = "sha256:fc67741da44c6eaa90e01eafb586bbba9b51eb5b6ed381ee6f5ae72eb3316d21", size = 104906, upload-time = "2026-07-08T12:24:58.806Z" },
+ { url = "https://files.pythonhosted.org/packages/76/5a/f4aaf37b50f2fde12c8c663b83fdd499cdc24f957f19543d7414bfcc9e25/librt-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:cc99dfb62b23c9207c33d0be8a2e2af7a42e21e6ea388b380a0c948c7b88953b", size = 125852, upload-time = "2026-07-08T12:25:00.065Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/99/bf1820e6feeabc2f218c24450ec0c995d6a91e8ba0fd3caf042c9e8adb2a/librt-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:40ccd13c252d3fe473ffc8a57be7565abc8b64cf1b108344c859d5164f7f3e0c", size = 111832, upload-time = "2026-07-08T12:25:01.148Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/f4/b2933ddae222dac338476abb872641169a5cfed2c2bb5444a5b07b32b0c3/librt-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30536798f4504c0fad0885b1d371b0539abb081e4570c9d7c641cb51141b49f0", size = 150990, upload-time = "2026-07-08T12:25:02.42Z" },
+ { url = "https://files.pythonhosted.org/packages/90/ef/db98f744ca50e6efc9c95c70ee49b77aefac31f6a3fc7c83754a42d6a74f/librt-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93d24ebb82aa4420b1409c389e7857bc35bd0b668007ac8172427d5c73cc8cc5", size = 155238, upload-time = "2026-07-08T12:25:03.681Z" },
+ { url = "https://files.pythonhosted.org/packages/03/e7/a197e7bc72baf2c61ce7fdc6906a5054dc05bd8da0819aa894e4857bf87e/librt-0.13.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb8a1adce42d8b75485a5d56a9623a50bcab995b6079f1dac59fc44034dd93d9", size = 503073, upload-time = "2026-07-08T12:25:05.049Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/e7/7887712e27da7c1ab80fcabb1de6eb24243964f6557cae530d4b70706dbd/librt-0.13.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0763ca2ab66058174f9dee426dc64f5e0a89c24a7df8d3fe3f1836c04e25de4b", size = 496528, upload-time = "2026-07-08T12:25:06.26Z" },
+ { url = "https://files.pythonhosted.org/packages/94/f0/f2283385bb6b950b26a1410f4ce51ec27231e0b3a4b925c46366d218b198/librt-0.13.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b222493da6e7b6199db9bd79502436cf5a27da3c1f7fa83c7e285444fc93fd03", size = 531786, upload-time = "2026-07-08T12:25:07.658Z" },
+ { url = "https://files.pythonhosted.org/packages/36/11/69ac3b54766ffba5fd7e5acebfb048d66dbe1f9f2d14516c2b3edc59cf87/librt-0.13.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fadc63331f4388c3dc90090448f682a7e9feafc11481391c1e94f2f907a3976e", size = 524393, upload-time = "2026-07-08T12:25:09.121Z" },
+ { url = "https://files.pythonhosted.org/packages/61/5f/d72f95fd444a926a3c14b4e24979474116988dd57a45be242077c45d3c22/librt-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:70d9c62a4cffd9f23396cd5ef93fc5d11b31596b9b7d6306074abe3d5fcf09bd", size = 543026, upload-time = "2026-07-08T12:25:10.459Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/08/dcd9993ad192737a004ba263d549f8ea605b326b952e7d6205c7d4170b76/librt-0.13.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66c0e7e6b02a155576df2c77ec933a70b72da726e248c494abf690923e624348", size = 546829, upload-time = "2026-07-08T12:25:11.716Z" },
+ { url = "https://files.pythonhosted.org/packages/96/d5/6d9bb2f54e4109a956b7128836529653eb9d740f784bc47ed10a02c1000e/librt-0.13.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ac04bcd3328eb91d99dfedf6a60d9c1f15d3434e6f6daf922f0420f7d90b85c7", size = 535700, upload-time = "2026-07-08T12:25:13.144Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/f2/10946922503858a359492fa27f13e86228bde702116a740ac7b3cd185f24/librt-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db327e7271e653c32040b85ae6188059c924b57d7e1e29f935523fa017cd4e82", size = 573566, upload-time = "2026-07-08T12:25:14.336Z" },
+ { url = "https://files.pythonhosted.org/packages/48/a8/94f00e3c99479a18088af3685ea016c42f3c7d5d1964d8dbb40c08d7f1aa/librt-0.13.0-cp312-cp312-win32.whl", hash = "sha256:860bd1d8ba48456ce08feaf8d343a8aaeb2fa086f2bcaa2a923fa3f7a3ff9aa3", size = 106099, upload-time = "2026-07-08T12:25:16.159Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/7b/2da9c74c1ed25a89cc4e1c8e007ea2eb4a0f1fafa3e70d757fe3242c5c5c/librt-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:e54a315caf843c8d77e388cadc56ea9ded569935ee2d2347d7ea94992e5aa6fa", size = 126934, upload-time = "2026-07-08T12:25:17.275Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/65/aead61bbf3b5358593f9d4779d2a0e88eaf6ec191a6342dde36dd1df6371/librt-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:c718e99a0992127af84385378460db624103b559ab260435abcfe77a4e4ed1c1", size = 112236, upload-time = "2026-07-08T12:25:18.425Z" },
+ { url = "https://files.pythonhosted.org/packages/67/3b/18e7b63255297a2bdc9c25c8d6d4ca8eca9f63aceb1252c0f7427ac7099e/librt-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a468951af16155824e88bdd8326ebe5bdb371f3ec0ac04642994b98201d914f3", size = 151027, upload-time = "2026-07-08T12:25:19.638Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/68/e2248452c00d1a03b45fee1752cdc8f790a476efd2402b75181da88a9e61/librt-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ae01d8512cc17079e53425635327dbf3f7ff57a42c00dec348bf79791c56444c", size = 155152, upload-time = "2026-07-08T12:25:20.851Z" },
+ { url = "https://files.pythonhosted.org/packages/0e/16/52b1c99bf19057a062aac39c900cbb81499f6f75d6c537c14463d247ba78/librt-0.13.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32c26893cd085c1efe83219e78d866da23fb20a066101b8f68210004361d224c", size = 502499, upload-time = "2026-07-08T12:25:22.055Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/54/b811151805c795f55e0dedee6ec687b75f9982a8105d240ea3910737a77b/librt-0.13.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5929da1981a46bcf4b28b1b9499905f0ff58e2419da402a048234e9783acbc4b", size = 496108, upload-time = "2026-07-08T12:25:23.296Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/f8/094d6b2bd93f3fdaa54db54cc788c4a365333bddad65ab02e04da0b1d004/librt-0.13.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b85d664d777bab6c0d709416cb42938251fda9e221b79e3a2215d85df5f4f9", size = 531576, upload-time = "2026-07-08T12:25:24.648Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/40/541733d5755824f968f7ec39d78ffbd75d145964157ae5e69a09ec6d7326/librt-0.13.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:531b2df3e9fe96b1fcf73a6d165921e4656be5f58d631d384ebce344298368db", size = 524390, upload-time = "2026-07-08T12:25:25.898Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/b5/255673cfdbf5ba663339d36cd863c897289ab4337577e19f9405ce059f36/librt-0.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:109b84a9edf69ad89dc1f66358659e14a031baca95e3e5b0060bd903ede8efd6", size = 543053, upload-time = "2026-07-08T12:25:27.436Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/11/ab5005e9c9850710f21e354201bf090646349d3fabf5f951eaf70235729e/librt-0.13.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1304368a3e7ffc3e9db986796cc5326fdb5943a3567ecc137cff318e4240c0e7", size = 546387, upload-time = "2026-07-08T12:25:28.65Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/04/a5d7ce1d1df1afd15ca283dcdf7530ac073e12d69ae8c40879dda96f7868/librt-0.13.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e4f9b472e7d308d94b62c801982065661158c6ed02790d6c7ddb4337cea0f9c1", size = 535970, upload-time = "2026-07-08T12:25:30.171Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/76/927e267a6daa290174ac281b23c9804c8829b042ade9c6f24a065f540958/librt-0.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f836c37478f167a81200d8c8b2c920a22224564bed2c23d7aeec760965c367a", size = 573582, upload-time = "2026-07-08T12:25:31.507Z" },
+ { url = "https://files.pythonhosted.org/packages/10/24/b6c5213efe39c19f9e13605644d0cf063b4ddaa33ac2e45b088e23a70e2e/librt-0.13.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:4000d961ff9598ac6ea603c6c836a5ed49bc205ade5fc378b998dfe1e2c36628", size = 82189, upload-time = "2026-07-08T12:25:32.675Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/00/d29736be177a906ac0b84a5b04b4fbfa22c776dc2f366de4172b0f968c08/librt-0.13.0-cp313-cp313-win32.whl", hash = "sha256:79e44cff71750d299d61a678e49995b0d5935a9cda238c2574daeca3ba536927", size = 106193, upload-time = "2026-07-08T12:25:33.692Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/ac/aff6fb45393cb8912f39dfb156ef6b2d1cadb207ff465fc8f66141054be8/librt-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:54dab44a847d5ad1acd05c8a83fe518ae685516ecf4d3f7cc6e3df2a66767650", size = 126962, upload-time = "2026-07-08T12:25:34.769Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/3a/d68cb2b334d53fd30fac81d3a489ce4ba0d9506f4df43fcf676b68352b19/librt-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:d4cb6fbfdf874340ab5e51450753c0f817b6958a3621125ee695bbc3de866566", size = 112127, upload-time = "2026-07-08T12:25:35.981Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/66/f49ae0d592bd45b6941e9a8bafcb6a87cddcd501ee7874707e767f01b585/librt-0.13.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:25218d94b1d2cbc0ba1d8a3f9dc9af578d9646e5ed16443a70cde1dfdcce6d71", size = 149818, upload-time = "2026-07-08T12:25:37.203Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/50/51c76d74014d04fb95b6506d286808984b78a2f7a41039094e6b2194ac48/librt-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f26629539d4893c2957a16c41bb058e1e135c1f150f6a2e25ed047f64cf3f5c6", size = 154071, upload-time = "2026-07-08T12:25:39.399Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/fe/f19b0f5f82d5a1f2da736586bc840abd00ce07d6388136ae80b7333883fc/librt-0.13.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4517d47b2b8af26975a406fba7d314de9696d864252e0257c6ea90238cfe27f", size = 494168, upload-time = "2026-07-08T12:25:40.641Z" },
+ { url = "https://files.pythonhosted.org/packages/94/bc/b8550c75775127fd31a5f20e8775997f7b527ad661fc8ddccd7497c064f7/librt-0.13.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f19e181de5b3a1148bb3420b8c4b0b0ea0fce6950099724ad151d6cea5acc180", size = 491054, upload-time = "2026-07-08T12:25:41.905Z" },
+ { url = "https://files.pythonhosted.org/packages/30/14/4d0204867623df3f33f86efd3d3692ba5e01321443f4d6eab35a22697618/librt-0.13.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22034924f5b42d5a56371cf271771bfeaabf235a7a8b6264bef2d20013f786c6", size = 523006, upload-time = "2026-07-08T12:25:43.327Z" },
+ { url = "https://files.pythonhosted.org/packages/19/0a/c45fc9a260934696bace1ac5df1e148ac92bd71767aee3bf7cd7a4534f4c/librt-0.13.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7897db4e95e22468bdda33d8e012ceacd0182abf001e6389d763f0def6286b9", size = 515058, upload-time = "2026-07-08T12:25:44.541Z" },
+ { url = "https://files.pythonhosted.org/packages/13/0a/50c5ce45b326854ef8fa6ae4c36cf5142e5c55315eaf9e51d0ae73ac4da3/librt-0.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1ce61b3746545029d4f5c17d6bd74b676254ad98433086c846ffb5e8fa73f007", size = 534025, upload-time = "2026-07-08T12:25:45.825Z" },
+ { url = "https://files.pythonhosted.org/packages/89/2d/08c413c8f93fc13b8103624fce38e5caa86cd08cbbc8465870ab287af54b/librt-0.13.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:46c330e82565962c761dbce7941be2cff7db674ee807455a8d0cadc5f9b759b0", size = 540557, upload-time = "2026-07-08T12:25:47.059Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/c1/93af71fb4a364952210051811dd4e40174e79656b050c89cacac18af3330/librt-0.13.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:375f5af8f99cbaa99dd293af986e3d57caabc9ba81a5d3f021603764854197a1", size = 523201, upload-time = "2026-07-08T12:25:48.392Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/6e/9766f07b676a4889d9f8bc2864e9ba5fff165653143ef4dda7df6aa34d16/librt-0.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9320d34c3376ae204b2cd176e8d4883a013934e0aef822f1aed9c536490c275d", size = 565740, upload-time = "2026-07-08T12:25:49.678Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/1e/664e3472ce2b6e10e9b83f29d4a36eb982ff6b5a169ae7567bba3a4c4ff5/librt-0.13.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:9af313c66157a69dc69ea0059a66961692250e0dc95af9c385a48ffb770a0d16", size = 81611, upload-time = "2026-07-08T12:25:50.857Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/d4/8582a4d65e2234673685e07309d02c230b28a85724eb0acbf13f019b7f6e/librt-0.13.0-cp314-cp314-win32.whl", hash = "sha256:f2a7253458e34f33543551394ae4fe104b497ec2a65ac266074de64c1df82e37", size = 100106, upload-time = "2026-07-08T12:25:52.03Z" },
+ { url = "https://files.pythonhosted.org/packages/63/ce/0cb99efe6086b46cd985dc26672166fae312a239690e75871f7fafbd3fc5/librt-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:a3dfe4edf10e8ed7e55b026a8bfc2c2a8704218b659cd4bffdf604fab966dc39", size = 121209, upload-time = "2026-07-08T12:25:53.166Z" },
+ { url = "https://files.pythonhosted.org/packages/26/85/4f3ccb083a3c9b0d42e223acdb3c3f507953324a59cdcab4826e8e2e3b89/librt-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:68a5faee4bba381cb93b5961f684a514cf0053cb92308ff9c792c2fea0b174c6", size = 106404, upload-time = "2026-07-08T12:25:54.253Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/77/333191499538c8e8189de7a4cba8e6f49ee949fd6d6e6324b21fd1522466/librt-0.13.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a38fb81d8376dfa2f8963b265fec07637802b0d01e2a127c19c66cb070fb24f5", size = 159231, upload-time = "2026-07-08T12:25:55.432Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/9e/2aa83758f22c278b837a1d8025898434ce2b8bff36678d5330ecaef56dff/librt-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d4c8d9bd5abce34b2e75edb3bf37ab0f34e49b1f915a40ae8468eb7c85bc5b46", size = 161300, upload-time = "2026-07-08T12:25:56.585Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/c0/86791e936553ca763d6b3c2fb4d31d596cd00e14fa631c283a40ba01559a/librt-0.13.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:387e2f1d27e89bffe0d3f520f0da0662c973fd607ca16c1808f8a5085419485e", size = 582056, upload-time = "2026-07-08T12:25:58.144Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/d3/a9ec15984a185e000c4d2a16ba28bd623124ad4c38a10974c7ff78e3a893/librt-0.13.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:4f6db193d2e5e0ed60359b9a5a682cd67205d0d3b1e459a867dd4b5c4e7eaa7a", size = 562758, upload-time = "2026-07-08T12:25:59.544Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/af/dbe36b78b19c06a55097f99305e4ea9458e2273e6ae16a3cbecaad7ee978/librt-0.13.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d38604854e8d22faadf683ec6c02bb0f886e2ba56ef981a1c36ee275f21ea22", size = 602095, upload-time = "2026-07-08T12:26:00.991Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/a8/2966891b4dd2830f5203fbee92ac2c4947653a2390ba73dfa44244fad025/librt-0.13.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:371f7ce73026815dafd51c50ce38416e91428b28c4b2ec97cd39271164b0045c", size = 593452, upload-time = "2026-07-08T12:26:02.352Z" },
+ { url = "https://files.pythonhosted.org/packages/61/f5/4df8bfc8405ecf8c0d525b4d69636f694bdd8620b313ec8b76e54a5926cc/librt-0.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3aaedf52171bee90860704c560bc798fe83b76247df47568e0197e9b13c735a0", size = 623729, upload-time = "2026-07-08T12:26:04.294Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/13/9ac202dffc8db06f75d06c08c2f9f6ff054be67d21272dcc078fa1cc0c57/librt-0.13.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:96bad8725a4f196a798366c25ce075d1f7543a4ec045ffc13e6a7ec095cdab04", size = 617077, upload-time = "2026-07-08T12:26:05.845Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/f0/ebe38610716aee5cb28efd95089bb90192096179802779381e1c5dcf239c/librt-0.13.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:6bf6a559ffe4a93bbea6cf31ddf01a7fd9ba342ef51f27beb178e318b74acd61", size = 599561, upload-time = "2026-07-08T12:26:07.21Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/5c/c2e72e236fff7abc716d5b1753b8b8cd3ea85ac46fe17d2e7c51d4e1c723/librt-0.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:301067672387902c55f94b51d5022304b36c966ea9fe1f21caab99a9bef487c9", size = 645511, upload-time = "2026-07-08T12:26:08.562Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/99/6203ce619dee940d6bfbe099ec3fe4be00a68e9d60f70abf906cf124fe66/librt-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:5fdcf34f86de8fb66d7dc7589f96ba91c4aa46671200d400e6fd6f109a483f18", size = 104357, upload-time = "2026-07-08T12:26:09.828Z" },
+ { url = "https://files.pythonhosted.org/packages/52/dd/843b6314087c41657c7036d7914d8f294bdf9b580aa8513ea0588c8e9a3d/librt-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:260c33e92263fa629b4f6d3c51967a1c2158fe6c33237aaa3ebeac586b085259", size = 126998, upload-time = "2026-07-08T12:26:10.975Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/5d/3dcec2884ba1b0806d1408612555c38dd5d68e90156b59f75f6e36435c3a/librt-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2f281549a4c52ac7bb97997f14353f8bd0e53a34ca0dad1c905cfd0b4a58ae99", size = 110771, upload-time = "2026-07-08T12:26:12.303Z" },
+]
+
+[[package]]
+name = "matplotlib"
+version = "3.11.1"
+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/49/64/f9a391af28f518b11ad45a8a712353c94a0aefce09d3703200e5c54b610a/matplotlib-3.11.1.tar.gz", hash = "sha256:69647db5746941c793d6e445a4cd349323ffb87d9cc958c2ad84a659b4832d30", size = 32612045, upload-time = "2026-07-18T03:39:46.63Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6e/d0/791aa183dd88491555cf7d4be0b52b0bcf6c3c2a2c22c815a2e819bf53e2/matplotlib-3.11.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b7cf158e7add54a8d51ac9b5a84abd6d4e13ed4951b4f25f1c5139f41c2addb2", size = 9440302, upload-time = "2026-07-18T03:38:03.844Z" },
+ { url = "https://files.pythonhosted.org/packages/35/74/82bbdf683a301f4478384c8aaba6903631a2ca18294b2d7655c9a542bffb/matplotlib-3.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d2ace7273b9a5061a3b420918a16fae1f2dc5dfee1abcc13aba71b5d94b1820c", size = 9268549, upload-time = "2026-07-18T03:38:06.144Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/f0/9b4298911303f74e6d83e64a81d996c0616405ec95046fac7f17e4258b9e/matplotlib-3.11.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee55e9041211bf84302ab55ec3965df18dd90ae19f8b58332a7feaf208bfe83", size = 10024922, upload-time = "2026-07-18T03:38:08.236Z" },
+ { url = "https://files.pythonhosted.org/packages/84/6f/0bc3c3d05b021db44c14bc379a7c0df7d57302aa15380c16fd4e63fd6a9b/matplotlib-3.11.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f4bdeea33a8d15a071dbfe6d119451b1d719c733ac666d65357082901a9099", size = 10832170, upload-time = "2026-07-18T03:38:10.276Z" },
+ { url = "https://files.pythonhosted.org/packages/db/4d/e375f39acdb2af5a9342730618608e39790ec842e6f1b392863028781459/matplotlib-3.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b4c78ceb2f11bcac7389d305cda17aeb1f4586a857854ab5780bd3dd8dbfc407", size = 10916701, upload-time = "2026-07-18T03:38:12.512Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/be/fa26ed085b41298f64a8f9b7592c671bbf1acc8b0df124c1c5de96b859f8/matplotlib-3.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:7f33a781e12b1e53b278deb2f5373c2e55ec4f10727be3440c0cfb5cda9f944f", size = 9315331, upload-time = "2026-07-18T03:38:14.949Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/f3/eb5bdf3b6e191b200db298b08bbc1638b7f3c82cdc8680f9d88bf72559ae/matplotlib-3.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:67e4c3cd578c65ebd81bdc09a1b6592ceafee6dfafe116dc85dfcb647b5bbb18", size = 9003475, upload-time = "2026-07-18T03:38:17.205Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/6c/7ef7ebcb2bd9739b2b66b18b076e077f44bb46fdbe28ca0506edb3c62c79/matplotlib-3.11.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e15ef41507f3d525f46154ac9e3ae785dacde9f20e593a25de8986267892ef74", size = 9453849, upload-time = "2026-07-18T03:38:19.593Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/f8/6d0c312c8d9738e7d9677f09fe5c986b3239e651a7b73a2deb38b65e4a71/matplotlib-3.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:21a67b961a6d597bca54fae826cd20695ba4a6e4d05424a08da6e13e3176fd6b", size = 9283113, upload-time = "2026-07-18T03:38:21.95Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/cf/b4ad2cc81b6672ea29ea04e64e350a9f9b493b0908ccd884c67eeff8f7b2/matplotlib-3.11.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ba8f811b8ddfac493734d6af0b2dff96919d0c28ca0d641858dab4262777c6ea", size = 10035615, upload-time = "2026-07-18T03:38:24.315Z" },
+ { url = "https://files.pythonhosted.org/packages/88/90/4e10e033d9b66589d8ed98b84c95cdbb57033d57c1f41339d7393dbd2f2e/matplotlib-3.11.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c52f7ad20ef476806ed212380b1d54d20310c8b86bdc2c9a68b51f0024a44472", size = 10842559, upload-time = "2026-07-18T03:38:26.285Z" },
+ { url = "https://files.pythonhosted.org/packages/88/eb/799612d0f8cd3e816a10fec59329fca52cd2353264df80378dfc541ae855/matplotlib-3.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8b14eb22961fe865efb0e4ff167e333e428908b00115a8d800ccb65ee108e481", size = 10927532, upload-time = "2026-07-18T03:38:28.532Z" },
+ { url = "https://files.pythonhosted.org/packages/88/89/56649bbaa2fd12e20f3be03dbcc135b0c8676d88bac17977599e3eb442a0/matplotlib-3.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:88a2a27dd9691ae448dfae4b26f59036be90c3c28757edd3553a29559d00859f", size = 9333886, upload-time = "2026-07-18T03:38:30.477Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/11/4d124efbbad677b7b7552f6f85a3bd432d4232f95400cea98fcd2ae36ef3/matplotlib-3.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:480194afceca4df2f137c2721227d3cba67121fbf4397b69cee7f83714b0a58a", size = 9007545, upload-time = "2026-07-18T03:38:32.833Z" },
+ { url = "https://files.pythonhosted.org/packages/04/6c/4798363b7fb5644e309fe1fac30216e9146c9f70859d80d588c18caf5317/matplotlib-3.11.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6771b0cd7838c6a857a7209814158c0ad09bfef878db3033dd82d70ad101f191", size = 9454341, upload-time = "2026-07-18T03:38:35.001Z" },
+ { url = "https://files.pythonhosted.org/packages/59/98/6acadbe7f98df19d274bc107ac58bb439fa75df82c33dc110d71a4a8501f/matplotlib-3.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2abdee5ffa2fe11b2d19f7a5c63b785fb7c28cc46c7bc1814156341d9d1a33e1", size = 9283627, upload-time = "2026-07-18T03:38:37.061Z" },
+ { url = "https://files.pythonhosted.org/packages/24/ea/65cec46fe241390ccea1b1754207ee28eb71c5ab866bd5f22fe47e538fa4/matplotlib-3.11.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b0a19dcf73406d3746d25a5ed42d713604c9a3e024d129b102852b0d941cb9f3", size = 10035860, upload-time = "2026-07-18T03:38:39.663Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/10/63fdccccbabe002fb0960876baabc5e3f24d9c1bb4cfb25651457f74b3a0/matplotlib-3.11.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7389b77ed2ab0552f46d9a90b81b7b8e6dfcdc42adc36c37a0865799843e0e3e", size = 10843594, upload-time = "2026-07-18T03:38:42.144Z" },
+ { url = "https://files.pythonhosted.org/packages/98/51/a1155945bff7b91381875022ac1522c5dfdac0d006be8e7df389b3134eae/matplotlib-3.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c90be0b73568da4f662afac580956a76e308437e641b4a45aa08925eeb67d95f", size = 10927962, upload-time = "2026-07-18T03:38:44.302Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/3a/3d5e1f42dc761bf53401a62a83ff93389b37de9d2c093b2a3aa49ac34f1b/matplotlib-3.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:68408341f2312836fbbdf6b3c78047f65b2d8752f5fd221c3e72d348f5b34f8b", size = 9334074, upload-time = "2026-07-18T03:38:46.616Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/db/3f5ea5a5b64060ef5e1ff60a19170423e41ce21b8497a6fe15a36e0b43e3/matplotlib-3.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c1f44890d435c1b4ef52f701ad5828cb450ea97bcc83918fda6be74965d6cd2", size = 9007662, upload-time = "2026-07-18T03:38:49.112Z" },
+ { url = "https://files.pythonhosted.org/packages/98/6e/c7ae5e0531425b69c0826b00ebbc264c85cab853f1cd6e096c9983c2cdc1/matplotlib-3.11.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:5e510088c27a89d53580a752f959146893563e63c330e161d159b0fee652af6f", size = 9503790, upload-time = "2026-07-18T03:38:51.527Z" },
+ { url = "https://files.pythonhosted.org/packages/92/79/15be162e0a2ed546939674e2e97d0e33ec2447d86d4d4e611fa295bb178c/matplotlib-3.11.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:1524e2bdd48a93557aa47ddcfe9c225dfdd57d5a01a5c49128c20f0632980ee1", size = 9336148, upload-time = "2026-07-18T03:38:53.564Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/7f/36ffe144fc4aacfe0e3ed2318f72b6755d1e73b041d619b4d393e60f5a66/matplotlib-3.11.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:11664c551345553db92e61cae6cf1376f138f8c47cafdf13b64b18f3e3e9e464", size = 10049244, upload-time = "2026-07-18T03:38:55.911Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/5f/55812d68c0a840d3a463638f48c00ab1fe338518ec49a640cb6473b444af/matplotlib-3.11.1-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e1f8922ba31959cf6a9dfb51be64b7f7bc582801a3957dc0c2f3afcd3537adf", size = 10860798, upload-time = "2026-07-18T03:38:58.282Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/64/cca444b4eb5e6c768c44fc5e1f0b5211f20ca2b282778051996e996a2bdf/matplotlib-3.11.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83235693abde86e5e0129998f80ee39fc7f58e6d56a88fafb28a9278833e9d5f", size = 10943282, upload-time = "2026-07-18T03:39:00.465Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/0f/a49c329d394f2e9ef38506982107e8b04ecf94dd41a9d8423ff82cc737c7/matplotlib-3.11.1-cp313-cp313t-win_amd64.whl", hash = "sha256:9a076f4fc5cdc43fdf510f5981418d25c2db4973418d9f22d8bb3dc8045ada78", size = 9383532, upload-time = "2026-07-18T03:39:02.468Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/50/103e86afb806d8f64d04ede14e4cfc09dbfc25f512421ff85fdd6ebd59cf/matplotlib-3.11.1-cp313-cp313t-win_arm64.whl", hash = "sha256:216fbb93a74add02ddb4cb38ef5348f59ac00b3e84567eaf16598772d40e150a", size = 9059665, upload-time = "2026-07-18T03:39:04.607Z" },
+ { url = "https://files.pythonhosted.org/packages/35/04/3079499fa8cb661ea66d13d6439d5a3ae6710a7afd5c7f72e08914f275f8/matplotlib-3.11.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:30c492d4ba9448595b6fd8708c6725963f8148e25c0d8842948da5b05f0ee8d3", size = 9456022, upload-time = "2026-07-18T03:39:07.041Z" },
+ { url = "https://files.pythonhosted.org/packages/53/a2/69acfe84ec1f32930e801a5782a07fc5c79c8c6599a507b806d859d5da8e/matplotlib-3.11.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ac104be2768ffdd8655db9e71b768cbb45f2b9aa7b450cf1595e8f65d3822319", size = 9285475, upload-time = "2026-07-18T03:39:09.562Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/b3/31b15a2ca56d4ddd6aaa1c884c2f51cf9a61cfaf5ca6f6fbd6343d38e6df/matplotlib-3.11.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6be943cb68bc6660ead58c55b3aa6366cba2ef7feb06460fbcce32360376f19f", size = 10847102, upload-time = "2026-07-18T03:39:11.532Z" },
+ { url = "https://files.pythonhosted.org/packages/64/0d/a17e966e620545c1548125af0b29ac812dd17b197a18a7462ac12fa859ee/matplotlib-3.11.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5af0dcda57d471440a7b5b623e70e0a61003518443d9098f211a96ecfbbc25be", size = 11131087, upload-time = "2026-07-18T03:39:13.764Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c5/5e100efdd67abb7de20befaa333612ef9bfc63417fb71398f904f25d083c/matplotlib-3.11.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3d3fd84082b1afbd9398466c81309e20045be20d48fe0fb18c43504d164cbbb2", size = 10929036, upload-time = "2026-07-18T03:39:16.888Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/04/d719a0a36930ecc8dfc801ff340f9dcfc4223f8ca5d39d06b4020032fff8/matplotlib-3.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:9601a1e90be21e4884c53b4f3dc3ee0544654946f9975258d691f1c2e2f119c6", size = 9489571, upload-time = "2026-07-18T03:39:19.449Z" },
+ { url = "https://files.pythonhosted.org/packages/48/65/facabdc2f1f6caba7e856db64dfedddca25f7608df07d96a1c8fd114fd3b/matplotlib-3.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:ae30c6109848ac0f9fa36c5d6270938487614c47ba31860bd5361266dabc5685", size = 9164486, upload-time = "2026-07-18T03:39:21.424Z" },
+ { url = "https://files.pythonhosted.org/packages/88/dd/18da6cd01cf96354534f98c468a25380c68ce582a2c9dd0cae12b04af4f2/matplotlib-3.11.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:dadfe80797174e2984aae3be0b77594a3c72d2c0a40fbd4a0de48d2728caf3ae", size = 9504876, upload-time = "2026-07-18T03:39:23.633Z" },
+ { url = "https://files.pythonhosted.org/packages/79/b0/f0b63555a18b79d038c81fd6126f35fc4dfce0eaff48d96103348c7cf935/matplotlib-3.11.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:89b193b255f4f6f7948dbcee3691f4f341ab05d9a8874a67b45ddb4182922eda", size = 9336120, upload-time = "2026-07-18T03:39:25.797Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/dd/f210ec7c4a6f198d5567237048a93d0811fb5a1f1691f13320e592f95b41/matplotlib-3.11.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191163532cdefcb1571ca38a6d7e6474baccde64495783e6ba47aa07ec4b9bbb", size = 10858033, upload-time = "2026-07-18T03:39:27.999Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/d2/d6d5324507c5fbb316db48e258c09c2807f3de03d9af47017e120070926f/matplotlib-3.11.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9fdf1c818ab05d0e74002091ddaf414478a3a449ec9d51c8976d45be7e3a01e2", size = 11141827, upload-time = "2026-07-18T03:39:30.092Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/68/3c22e9320bdce2c4d2f1320643ef706db7a24cb7420eea28b97a2d67f5a8/matplotlib-3.11.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b937b9dba5f5f6c1e31c47abe2186c865c0914fd18f2ce0dfc39c9adcef5951d", size = 10943061, upload-time = "2026-07-18T03:39:32.356Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/4a/907ed190ee81a9df581e0ed5456134fc0f7cb55ffcfda2f9e54ca900761c/matplotlib-3.11.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f2912f647f3fbe1ccf085f91e213936f9101bead81a5e670565b1f1b3712f4fb", size = 9540074, upload-time = "2026-07-18T03:39:34.789Z" },
+ { url = "https://files.pythonhosted.org/packages/23/d4/97c19b77e0a6e3b48581185bb65088f431cd20186076cc0f650a1757ea46/matplotlib-3.11.1-cp314-cp314t-win_arm64.whl", hash = "sha256:54d47b8ae8b579633a3902ca5b4ad6c1e132a5626d64447b2e22a66394e79987", size = 9213472, upload-time = "2026-07-18T03:39:37.141Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/38/ceb1d637c4db6d06141f3739e93af3321e7caaabe69b57ae48ffe3ee95b1/matplotlib-3.11.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:427258425f9a3fc4ed79a91f9e9b9aaf5a82cb6571e85dc14063cc6fbb993741", size = 9438045, upload-time = "2026-07-18T03:39:39.491Z" },
+ { url = "https://files.pythonhosted.org/packages/89/25/72ad8b58602d3a6ef1dfc4b65ecd01634ab65a2bdf494c9fe0e966dbf081/matplotlib-3.11.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:1ac697e591c11b6ad04679a73c2d2f9980fe9d9f0311fb414a2e329706343dfb", size = 9266127, upload-time = "2026-07-18T03:39:41.597Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/6d/69552382fcc8e93d1f2763ef2665980a900a48b7f3a4c57ed290726d1cbc/matplotlib-3.11.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e4b9ac2f1f607ecda2af90a5232beee2af7582fce1cc30c4b6a1b012dc21ee99", size = 10019439, upload-time = "2026-07-18T03:39:43.78Z" },
+]
+
+[[package]]
+name = "mypy"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "ast-serialize" },
+ { name = "librt", marker = "platform_python_implementation != 'PyPy'" },
+ { name = "mypy-extensions" },
+ { name = "pathspec" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/12/af/4e516a05d3ca2eb9283e9ec45b2c02225c1514dd6da49fd3c9eaa6639370/mypy-2.3.0.tar.gz", hash = "sha256:465965d41cd9a2726694e983e8ce7113259327bec798115d1e1dfa2a52fb666e", size = 3988104, upload-time = "2026-07-13T11:34:53.387Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e6/b9/d75b3082b05f1b3028828aeb18e74ae5ab0a0936051bbf1f32f59f654747/mypy-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3419d00717afbc5265b50dd14b1278f29ea4884dd398ab67873489ac093fd329", size = 14838725, upload-time = "2026-07-13T11:32:44.655Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/50/79a65c6ea6e115bc73296038a4543b2d5c91f07912b918a2c616a2514bba/mypy-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cfca8ee88544090f86b6dcce05ec55d66eb48a762412ac2507810ba4bd793b6f", size = 13911128, upload-time = "2026-07-13T11:32:02.021Z" },
+ { url = "https://files.pythonhosted.org/packages/90/48/e11ed7716c26953ca321f726e452e374dbf81a6f2b8b212ec02af29b6b8f/mypy-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75cbb4b9ef04a0c84a957f07abc4504fbf64b8dcc145675101f2d3a78a4b1d6a", size = 14146742, upload-time = "2026-07-13T11:33:03.313Z" },
+ { url = "https://files.pythonhosted.org/packages/06/72/6807565b1c4861ef66f7fdd98b51c61556356eab80235717b46c53bb8627/mypy-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:982e3d53dd23d0a4cef67dd66791fdbede0cf38f9eb617bf47663554c51e1e36", size = 15081418, upload-time = "2026-07-13T11:31:13.899Z" },
+ { url = "https://files.pythonhosted.org/packages/00/80/1ea14c5d80e589e415973db3e47c78c2219a305b808b2b506395342c1d79/mypy-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85c5385b93012ffa3b31479ab579aef5415f4f3a32c6cf1ae07a984d2a0ff461", size = 15328164, upload-time = "2026-07-13T11:31:35.723Z" },
+ { url = "https://files.pythonhosted.org/packages/37/28/8223157404a3d51920078459c37f80fbdc590e1d8ea049dc5ce48643022a/mypy-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:13b1b16e2fa39f3b2e33fb1c468abc7a69369fa2e886b4b87b5afc81472325cd", size = 11136472, upload-time = "2026-07-13T11:27:37.018Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/cc/ea27e5959c5f258585a756b252031f3b313583d81b5064b2bebc41d3706b/mypy-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:b5cd2f027a972a4a5f2278a11fac9747f5f81a53a30b714d74950b6807e55568", size = 10135800, upload-time = "2026-07-13T11:30:08.92Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/94/0e7e592619e2133596a47cdd642534b0456545c218430bd3b9d8fefdd1b1/mypy-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d53fc67b9d28a43c6199077f49fea0f05839e36cf6158500331c9549225e5a5", size = 15026523, upload-time = "2026-07-13T11:34:49.206Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/d2/1e1731df090a857df2807177a4626863e5ac0f0256513c35780efe53986f/mypy-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fbc00cee7bdbb9291979ddc9d08034a29dfcda4932628c9bbc28c1edd589df0c", size = 14032189, upload-time = "2026-07-13T11:33:57.168Z" },
+ { url = "https://files.pythonhosted.org/packages/44/95/cab921f4a806e171f34113e6181dd23c55358ccf6a80741269ef594a410e/mypy-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04e617030eca5221909c8b7d8d7fd1c637948199aa2100b2ad9813feb07e1491", size = 14198696, upload-time = "2026-07-13T11:32:12.767Z" },
+ { url = "https://files.pythonhosted.org/packages/66/80/e6d008bb19fe446e3662d85e0e2717bf9f2d611a2164fb29d6e067dbf46c/mypy-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56c184d2c20ca6b6378d58d1960270a767f41f5e44acbbd27f05effef4f4e1d7", size = 15286904, upload-time = "2026-07-13T11:34:27.594Z" },
+ { url = "https://files.pythonhosted.org/packages/db/83/94397c9293608a364aa03e8084fb34ede4ae976a260384b9b52929308135/mypy-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3961a4a34b05f7c74b0f05aa51fbfe99a2d1e126038df40318d15c8f558b7ef3", size = 15528342, upload-time = "2026-07-13T11:34:07.819Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/96/d8b37d819adec6cfccfb1fd3afc1735d94717ddeafb45536db9c6943e09b/mypy-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b1942b9314d4c784b8ea1dbab4972603290e5dd5630f06675f13aec97526bc4c", size = 11218346, upload-time = "2026-07-13T11:28:27.745Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/cd/cd9f725b19b19e5b530a154cf9bcf9e94279c5d55b3c34fb42b3aa48ea1b/mypy-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:be51653d7669d7d7955d613b8d0bb57d5b652eaf71a873ddf65ac87254dd2595", size = 10204525, upload-time = "2026-07-13T11:31:02.552Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/ae/f7d056eb0294586a572d0d0d89580ec633c064db520f11d37d5a2fb833bd/mypy-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:91ad22a52ae2c7e621c2f67c94d5a17f66b3209a4cff5cf8a573579835c69e97", size = 14947298, upload-time = "2026-07-13T11:27:47.734Z" },
+ { url = "https://files.pythonhosted.org/packages/32/d5/db3e7af01e7844d21662c6ddc1f7825ec7cb4053f0391ac02faf3638396f/mypy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:99ac767cc5d3b64c8d0ae226ead10c96694f94e4e7da1668642225dcd4e75aac", size = 13950768, upload-time = "2026-07-13T11:27:57.726Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/fb/43c031f0190513d1ec248ed037eceb742ddd2a4d74bbf406658a28173837/mypy-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de6d2c484742a4d7b0ed6d07b143375624d3b899c5749c7b3c947f56261f48a6", size = 14151586, upload-time = "2026-07-13T11:29:18.615Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/c3/f8b2ffc60883084da91be51af58e88a7ffd4ff9795acb7d902ff88d31eb1/mypy-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7da939dd335cfd2ad788bdfd081c9f4e47634ab995e5a45eb15fd1e5bc052f8b", size = 15227411, upload-time = "2026-07-13T11:30:29.904Z" },
+ { url = "https://files.pythonhosted.org/packages/83/2e/16b917fc7adcf03f1aadddfc93aab804ffb234b1ab09c0ffd6d92a5d34a2/mypy-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7247eb2824f996722a949530183394921ca71deb9680052a338cf53cff7925c2", size = 15478790, upload-time = "2026-07-13T11:33:14.686Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/88/aaa65a93c73d0cdae7e42f8adb302bf6885bb281302084f99d0290a35347/mypy-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:75b0984bb3cbd76bb5c9291a8671f7ae66ca3b51c7584c358fc2e923259f0757", size = 11234919, upload-time = "2026-07-13T11:33:39.28Z" },
+ { url = "https://files.pythonhosted.org/packages/35/19/b40de63f1a80e63bc2d40f0679a6a8dbd34e95176c8122119bdf406aa552/mypy-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:d78fcf900b59cb7e82cb7e3a235e31b462d9333d92285bd1e4952d355b8ffba1", size = 10201510, upload-time = "2026-07-13T11:31:52.619Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/58/fa0ae047da911f540284009b4f44b96fe09d83c076d7c103e9d645f46303/mypy-2.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ea317b060ce83e26050f8f9e4d7d6bf44ed7597c8ff9990bccffbb9d1d8522db", size = 14941909, upload-time = "2026-07-13T11:32:34.332Z" },
+ { url = "https://files.pythonhosted.org/packages/15/14/2ba1d61452d7c2a7fe12741e8d374e52b183476b07aa7f9e2a0d02b0720a/mypy-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:094af99f92638aa92852326188b85a89e50f4a472f44827c03362228482f0762", size = 13967581, upload-time = "2026-07-13T11:30:00.587Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/5a/483fb9e5ffbbb1a28dccc7b0a13d141b17ac769b6c9f488c0a0c63698962/mypy-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de121747278144fc9ae7caa2e978cf5df12aebc82933182f5b3b86081a30baef", size = 14168807, upload-time = "2026-07-13T11:28:48.6Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/77/70d7a10732063beb74ad713682cf871e88f5c5fa39bfc8beff8a524bf9cb/mypy-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37fa4de896a84e2dc9200d91e614c22563b43d1a266789d4bbac7b22ebe6192b", size = 15200144, upload-time = "2026-07-13T11:31:25.283Z" },
+ { url = "https://files.pythonhosted.org/packages/56/72/766218ac783be4fdfcd699b90037b63017348a3e86fb2c1fbfb18302637d/mypy-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f1b3a98dfd21058bc759bb3337d5d1f61d0fdf9f3cf9c00f4291790fb5427bff", size = 15460389, upload-time = "2026-07-13T11:29:29.077Z" },
+ { url = "https://files.pythonhosted.org/packages/38/4e/8a9db7411ecb8ec0cb1fd05dba432f28bafffcd38b4e887714a4a0506689/mypy-2.3.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:944c665d984157cb96a679dfb7a4a81dd1d36b24b9c284b699514e6e626b82d4", size = 7753664, upload-time = "2026-07-13T11:29:08.147Z" },
+ { url = "https://files.pythonhosted.org/packages/65/4c/c3f8bfd6ed0e5e38b5a244403b27f821d433443df5a15a278417c10a3a3c/mypy-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:4359424140d985192c778c1ce2c114a10c1ca58a381ed79cfa70d37df94b299f", size = 11417237, upload-time = "2026-07-13T11:33:47.467Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/00/89a32eaf5ccf174bc4f90db0eaea5d70636c01b8d49f384bdab2e8834390/mypy-2.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:3dd0bed92c4bdec57c42505b96416fb9e6a5aa7be84d2809bcd5f2ecec2860d7", size = 10389252, upload-time = "2026-07-13T11:31:43.81Z" },
+ { url = "https://files.pythonhosted.org/packages/31/56/104f93d69aa9f339b6b9d3b0a7faa699b8b466c942cf3ae86cc2a2ec0915/mypy-2.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:691fdc37132b1ae628d834f672e74de83462d9fb4aff621835767fb43a8dd373", size = 16385495, upload-time = "2026-07-13T11:29:49.818Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/03/f1d2123313f55efafdd27706960f43a771c62f1b68426c76043f3ab9ebf3/mypy-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:aec15d465d477558fd842757b487849007311cf3897849cdda0e3162ac0ac556", size = 15098155, upload-time = "2026-07-13T11:30:40.301Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/5d/d5f9200399b445e81726c4f23becee33f233aee81c72680b1ef3a258b641/mypy-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b352b7e49f5e6576009e8df730e1ff4f915cb565b851b396d2ffe2f5a6f5da88", size = 15514155, upload-time = "2026-07-13T11:34:38.569Z" },
+ { url = "https://files.pythonhosted.org/packages/cd/ce/69977c555f08faa3190cfde44189b89dbd56861b1ab97aa18fc5f3a2e4a3/mypy-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c6c6bf687b17f90dbfcad95b960d32eaa0154c00da45f03ab50bf8952e047fe", size = 16766351, upload-time = "2026-07-13T11:33:29.195Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/92/6648b6caa3ab9e00f9ac0c2a78307805f873dd48139b24a6f6f7c3667bbf/mypy-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f4ed18f111bfe2d599bca7468e7f9251042c1c2118f762c8de2766a56d773c60", size = 17043490, upload-time = "2026-07-13T11:30:53.927Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/ab/0dc91d80f3f016634c68d451f294a97320fe903a9b6f90b9e57b3f7f1717/mypy-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0b025a93cffb9781d231f232be07a17912f35f10a313c24f301c81e842870654", size = 12146869, upload-time = "2026-07-13T11:29:38.874Z" },
+ { url = "https://files.pythonhosted.org/packages/85/b5/4c964d02634ba81f4d1c84838e5c5b18ab06d13ed568960f5d6318495ccc/mypy-2.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:adebc76aab4f3495a88b41d48aa4aff0c03f2822501da76625afcca5975f19e5", size = 10965113, upload-time = "2026-07-13T11:28:07.056Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/fa/fdc54fe583ba3cafbcedfb70eeeaf03849f75b1827a07096c7bd996f582d/mypy-2.3.0-py3-none-any.whl", hash = "sha256:6b1cdb579446b60432432b2b2403a6201b4b475a004d7f488511c9ba177c9e88", size = 2753292, upload-time = "2026-07-13T11:33:18.48Z" },
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
+]
+
+[[package]]
+name = "numdifftools"
+version = "0.9.42"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+ { name = "scipy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/17/94/7c83677dddc78f93230f4c8a6a5faa06c92699a76eb019386a3aed8a9762/numdifftools-0.9.42.tar.gz", hash = "sha256:866675171f293c4bf2f1e1c5bf9b88a07d5396903e3b3e7fcc3879e2a01cfbc1", size = 79612, upload-time = "2025-12-11T12:06:10.54Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/60/60/c7504633e9fe53dc823db5d83dc15651c595cf35d668781832b4d2748272/numdifftools-0.9.42-py3-none-any.whl", hash = "sha256:22f926b8de24aa44f740bc26744a74555c1c80413068b1dee2edb3c3d10566f6", size = 94252, upload-time = "2025-12-11T12:06:09.322Z" },
+]
+
+[[package]]
+name = "numpy"
+version = "1.26.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/11/57/baae43d14fe163fa0e4c47f307b6b2511ab8d7d30177c491960504252053/numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", size = 20630554, upload-time = "2024-02-05T23:51:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/2e/151484f49fd03944c4a3ad9c418ed193cfd02724e138ac8a9505d056c582/numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", size = 13997127, upload-time = "2024-02-05T23:52:15.314Z" },
+ { url = "https://files.pythonhosted.org/packages/79/ae/7e5b85136806f9dadf4878bf73cf223fe5c2636818ba3ab1c585d0403164/numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", size = 14222994, upload-time = "2024-02-05T23:52:47.569Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/d0/edc009c27b406c4f9cbc79274d6e46d634d139075492ad055e3d68445925/numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", size = 18252005, upload-time = "2024-02-05T23:53:15.637Z" },
+ { url = "https://files.pythonhosted.org/packages/09/bf/2b1aaf8f525f2923ff6cfcf134ae5e750e279ac65ebf386c75a0cf6da06a/numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", size = 13885297, upload-time = "2024-02-05T23:53:42.16Z" },
+ { url = "https://files.pythonhosted.org/packages/df/a0/4e0f14d847cfc2a633a1c8621d00724f3206cfeddeb66d35698c4e2cf3d2/numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", size = 18093567, upload-time = "2024-02-05T23:54:11.696Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/b7/a734c733286e10a7f1a8ad1ae8c90f2d33bf604a96548e0a4a3a6739b468/numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", size = 5968812, upload-time = "2024-02-05T23:54:26.453Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/6b/5610004206cf7f8e7ad91c5a85a8c71b2f2f8051a0c0c4d5916b76d6cbb2/numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", size = 15811913, upload-time = "2024-02-05T23:54:53.933Z" },
+ { url = "https://files.pythonhosted.org/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", size = 20335901, upload-time = "2024-02-05T23:55:32.801Z" },
+ { url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", size = 13685868, upload-time = "2024-02-05T23:55:56.28Z" },
+ { url = "https://files.pythonhosted.org/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", size = 13925109, upload-time = "2024-02-05T23:56:20.368Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", size = 17950613, upload-time = "2024-02-05T23:56:56.054Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", size = 13572172, upload-time = "2024-02-05T23:57:21.56Z" },
+ { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", size = 17786643, upload-time = "2024-02-05T23:57:56.585Z" },
+ { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", size = 5677803, upload-time = "2024-02-05T23:58:08.963Z" },
+ { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", size = 15517754, upload-time = "2024-02-05T23:58:36.364Z" },
+]
+
+[[package]]
+name = "opt-einsum"
+version = "3.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8c/b9/2ac072041e899a52f20cf9510850ff58295003aa75525e58343591b0cbfb/opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac", size = 63004, upload-time = "2024-09-26T14:33:24.483Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932, upload-time = "2024-09-26T14:33:23.039Z" },
+]
+
+[[package]]
+name = "oqupy"
+version = "0.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "h5py" },
+ { name = "matplotlib" },
+ { name = "numdifftools" },
+ { name = "numpy" },
+ { name = "scipy" },
+ { name = "tensornetwork" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/04/50/e65a13a051697dacfaa4106c51b2473b7c1e23133b174406db31c50e8c91/oqupy-0.5.0.tar.gz", hash = "sha256:cda14c4cb07a79a6efccb20e7847f8002767c5c03c9a1146ad5435bebd6d1cab", size = 127010, upload-time = "2024-06-24T13:43:09.625Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/75/6d/52f562416eb5045e0aa6b76343594b204bdcb994d9aa55630b4490e3caea/oqupy-0.5.0-py3-none-any.whl", hash = "sha256:5cb04003578cabbb7df7d6dd4dda12505d358d46eddfdc2593234c3d2f3054dc", size = 104902, upload-time = "2024-06-24T13:43:08.411Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "26.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" },
+]
+
+[[package]]
+name = "pathspec"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
+]
+
+[[package]]
+name = "pillow"
+version = "12.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/c8/0a78b0e02d7ac54bc03e5321c9220da52f0c2ea83b21f7c40e7f3169c502/pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756", size = 5392415, upload-time = "2026-07-01T11:53:47.162Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/5b/a02d30018abd97ced9f5a6c63d28597694a00d066516b9c1c6de45859fc9/pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6", size = 4785266, upload-time = "2026-07-01T11:53:49.079Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/98/766667a4be768150a202836acd9fad19c06824ca86c4286d3cf6b274964e/pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd", size = 6263814, upload-time = "2026-07-01T11:53:51.32Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/2d/ede717bc1144f63886c21fd349bb95860b0d1a21149ff16f2bb362b612b6/pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd", size = 6934408, upload-time = "2026-07-01T11:53:53.487Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/48/9c58b685e69d49c31af6c8eb9012055fab7e665785165c84796e2c73ce72/pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c", size = 6337160, upload-time = "2026-07-01T11:53:55.457Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/fa/dc2a5c0ba6df93f67c31d34b808b7ce440b40cdbf96f0b81cde1d1e6fa93/pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5", size = 7045172, upload-time = "2026-07-01T11:53:57.736Z" },
+ { url = "https://files.pythonhosted.org/packages/86/a5/444817a4d4c4c2417df00513086ca196f388d8f9ef40c2e4ccd1ad1af54b/pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b", size = 6472232, upload-time = "2026-07-01T11:53:59.767Z" },
+ { url = "https://files.pythonhosted.org/packages/63/c6/4bad1b18d132a50b27e1365e1ab163616f7a5bb56d330f66f9d1d9d4f9d4/pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a", size = 7233653, upload-time = "2026-07-01T11:54:02.066Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/16/00f91ab7760dc842f5aad55217e80fc4a7067a0604535249bc8a2d6d9870/pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26", size = 2568195, upload-time = "2026-07-01T11:54:04.622Z" },
+ { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" },
+ { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" },
+ { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" },
+ { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" },
+ { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" },
+ { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/ac/31fb64e1e7efb5a4b50cd3d92049ba89ac6e4d8d3bb6a74e15048ca3353e/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89", size = 4161684, upload-time = "2026-07-01T11:54:25.934Z" },
+ { url = "https://files.pythonhosted.org/packages/87/b4/9805e23d2b4d77842b468513841fda254ee42f0289d25088340e4ff46e2d/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace", size = 4255487, upload-time = "2026-07-01T11:54:27.935Z" },
+ { url = "https://files.pythonhosted.org/packages/df/39/ecf519435a200c693fe053a6ee4d835b41cf963a4dfc2551c4e637cb2a71/pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec", size = 3696433, upload-time = "2026-07-01T11:54:29.813Z" },
+ { url = "https://files.pythonhosted.org/packages/42/92/2fc3ffad878ae8dd5469ec1bc8eb83b71f48e13efdf68f02709003982a32/pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66", size = 5345889, upload-time = "2026-07-01T11:54:31.97Z" },
+ { url = "https://files.pythonhosted.org/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35", size = 4780109, upload-time = "2026-07-01T11:54:34.026Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/01/e18aff37cb0b4aac47ac90f016d347a49aca667ef97f190b06ac2aabc928/pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65", size = 6263736, upload-time = "2026-07-01T11:54:36.131Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/62/de5bdd77d935331f4f802edc11e4d82950f642caad6cb2f949837b8560e2/pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3", size = 6937129, upload-time = "2026-07-01T11:54:38.216Z" },
+ { url = "https://files.pythonhosted.org/packages/70/4d/105627a13300c5e0df1d174230b32fd1273062c96f7745fd552b945d1e1d/pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a", size = 6339562, upload-time = "2026-07-01T11:54:40.354Z" },
+ { url = "https://files.pythonhosted.org/packages/6b/1d/f13de01a553988ab895ba1c722e06cf3144d4f57656fd5b81b6d881f1179/pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e", size = 7049439, upload-time = "2026-07-01T11:54:42.489Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/f9/066794cca041b969964f779ee5fa66a9498bbf34248ac39c5d7954e4198f/pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f", size = 6473287, upload-time = "2026-07-01T11:54:44.9Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/9b/7a58e61d62be561da3a356fe2384d4059a6345fc130e23ef1c36a5b81d24/pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8", size = 7239691, upload-time = "2026-07-01T11:54:47.141Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/b0/c4ed4f0ef8f8fa5ee8351537db6650bb8189f7e118842978dd6589065692/pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b", size = 2568185, upload-time = "2026-07-01T11:54:49.137Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/01/001f65b68192f0228cc1dbbc8d2530ab5d58b61037ba0587f946fea607cd/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330", size = 4161736, upload-time = "2026-07-01T11:54:51.156Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/d2/0219746d0fd16fc8a84498e79452375be3797d3ce4044596ce565164b84f/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217", size = 4255435, upload-time = "2026-07-01T11:54:53.414Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/02/8d0bc62ef0302318c46ff2a512822d2610e81c7aa46c9b3abe6cbaca5ad0/pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930", size = 3696262, upload-time = "2026-07-01T11:54:55.739Z" },
+ { url = "https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8", size = 5350344, upload-time = "2026-07-01T11:54:57.657Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0", size = 4780131, upload-time = "2026-07-01T11:54:59.713Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/9d/8b2c807dbef61a5197c047afe99823787eb66f63daf9fb2432f91d6f0462/pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321", size = 6263757, upload-time = "2026-07-01T11:55:01.778Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b", size = 6936962, upload-time = "2026-07-01T11:55:03.93Z" },
+ { url = "https://files.pythonhosted.org/packages/18/7e/e483414b35800b86b6f08dbbc7803fb5cd52c4d6f897f47d53ea2c7e6f65/pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198", size = 6339171, upload-time = "2026-07-01T11:55:05.989Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/f4/68c491844841ede6bed70189546b3ee9731cf9f2cbad396faff5e1ccba45/pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130", size = 7048116, upload-time = "2026-07-01T11:55:08.131Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/34/77f3f793fed8efc7d243f21b33c5a3f0d1c97ee70346d3db855587e155ff/pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a", size = 6467209, upload-time = "2026-07-01T11:55:10.408Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/e0/492879f69d94f91f60fc8cd05ba03650e9520afebb2fb7aa12777d7c7f38/pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d", size = 7237707, upload-time = "2026-07-01T11:55:12.745Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/ac/6b11f2875f1c2ac040d84e1bbf9cf22a88038f901ca1037898b280b38365/pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838", size = 2565995, upload-time = "2026-07-01T11:55:14.736Z" },
+ { url = "https://files.pythonhosted.org/packages/52/69/c2208e56af9bfc1913afb24020297a691eb1d4ef688474c8a04913f65e04/pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e", size = 5352503, upload-time = "2026-07-01T11:55:17.076Z" },
+ { url = "https://files.pythonhosted.org/packages/07/70/e5686d753e898a45d778ff1718dba8516ead6ab6b95d85fc8c4b70650cf2/pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17", size = 4782956, upload-time = "2026-07-01T11:55:19.448Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/37/25c6692f06927ee973ff18c8d9ee98ad0b4d84ee67a09610c2dd1447958e/pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385", size = 6322855, upload-time = "2026-07-01T11:55:21.613Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/91/420637fcb8f1bc11029e403b4538e6694744428d8246118e45719f944556/pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c", size = 6989642, upload-time = "2026-07-01T11:55:24.006Z" },
+ { url = "https://files.pythonhosted.org/packages/10/08/b94d7811281ccf0d143a1cf768d1c49e1e54af63e7b708ab2ee3eb87face/pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d", size = 6391281, upload-time = "2026-07-01T11:55:26.252Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/87/24233f785f55474dc02ce3e739c5528a77e3a862e9333d1dd7a25cc31f70/pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931", size = 7096716, upload-time = "2026-07-01T11:55:28.318Z" },
+ { url = "https://files.pythonhosted.org/packages/23/26/fcb2f6e37175b04f53570b59937867e2b80ee1685e744023153028fc14f9/pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7", size = 6474125, upload-time = "2026-07-01T11:55:30.956Z" },
+ { url = "https://files.pythonhosted.org/packages/90/de/3634abee5f1c9e13c56787b7d5517b0ba8d6de51700b95578cf338349c9f/pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c", size = 7242939, upload-time = "2026-07-01T11:55:34.044Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/2a/fd13f8eb24de5714a6eb444a3d67e2842c6c576e159a43793adf23051351/pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45", size = 2567506, upload-time = "2026-07-01T11:55:35.988Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/dc/8fdce34ec725a33c81c6ba122b904d6b9024e50ea9ac7bede62fab54506c/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139", size = 4162063, upload-time = "2026-07-01T11:55:37.941Z" },
+ { url = "https://files.pythonhosted.org/packages/76/66/2044b9a63d3b84ff048228dfcb7cd9bf0df983e8470971bf7d4c57b693de/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402", size = 4255549, upload-time = "2026-07-01T11:55:40.022Z" },
+ { url = "https://files.pythonhosted.org/packages/52/7e/1f67e6f4ece6b582ee4b539decbcc9f848dc245a93ed8cd7338bafef72f1/pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c", size = 3696331, upload-time = "2026-07-01T11:55:41.98Z" },
+ { url = "https://files.pythonhosted.org/packages/12/40/d306fc2c8e4d45d7f175c77edca7063be7b86fe7fe6e68f4353bf71d808c/pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f", size = 5350370, upload-time = "2026-07-01T11:55:44.028Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/44/668fb1437e8ce420f62d6106eb66e44a5971602a4d794615bdf79315d82d/pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701", size = 4780147, upload-time = "2026-07-01T11:55:46.073Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/08/93fa2e70e30a2d81547e481b6ee2bb9522117221fb1e0ce4b5df70967677/pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace", size = 6273659, upload-time = "2026-07-01T11:55:48.264Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/6d/043e96ff814fc31a33077e4cba86082167db520c93632afdf2042febbb0c/pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4", size = 6947439, upload-time = "2026-07-01T11:55:50.503Z" },
+ { url = "https://files.pythonhosted.org/packages/af/92/ba71d2ee2ac0edf3fa33bd9d5ee9ee080da70b1766f3ca3934f9938ddac9/pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39", size = 6353577, upload-time = "2026-07-01T11:55:52.697Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/ce/e63064e2122923ff687c8ad792d0d736a7b3920a56a46982e81a7fdd25d6/pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71", size = 7060394, upload-time = "2026-07-01T11:55:55.149Z" },
+ { url = "https://files.pythonhosted.org/packages/54/76/a09cc3ccc8d773a7283d34c38bec1708f9e3cc932093cbc4c5e71ac4060b/pillow-12.3.0-cp315-cp315-win32.whl", hash = "sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827", size = 6467375, upload-time = "2026-07-01T11:55:57.769Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/03/1846c49ba3b1d5550392a4bbd06d6fb4578e1cd91a803198b5c90f5f7d53/pillow-12.3.0-cp315-cp315-win_amd64.whl", hash = "sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5", size = 7237048, upload-time = "2026-07-01T11:55:59.975Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/bb/89f35dcc79610423f9f195504d7def7f0d1416a711541b42867e25fe3412/pillow-12.3.0-cp315-cp315-win_arm64.whl", hash = "sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658", size = 2566006, upload-time = "2026-07-01T11:56:02.143Z" },
+ { url = "https://files.pythonhosted.org/packages/30/88/707027ba09942dfa2c28759b5c222d769290a41c6d20ea60ec250801941f/pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf", size = 5352509, upload-time = "2026-07-01T11:56:04.2Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/6d/00352fa25332c2569cd387851f568cc5a4b75a9adbfb37ac4fbce4c02eec/pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64", size = 4783167, upload-time = "2026-07-01T11:56:06.631Z" },
+ { url = "https://files.pythonhosted.org/packages/13/4f/9e049dfa21af7c22427275720e2490267ba8138120add5c4c574deb69782/pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e", size = 6329237, upload-time = "2026-07-01T11:56:08.868Z" },
+ { url = "https://files.pythonhosted.org/packages/36/16/cf6eeaae8d0fce8dd390a33437cf68c5d5bd73834a2bc6e2f14efda0ab45/pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777", size = 6997047, upload-time = "2026-07-01T11:56:11.379Z" },
+ { url = "https://files.pythonhosted.org/packages/1e/69/dbf769bdd55f48bf5733cac28edc6364ffaa072ec9ba336266e4fe66be55/pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1", size = 6400440, upload-time = "2026-07-01T11:56:13.908Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/e1/ffc9cfc2eea0d178da8018e18e959301ad9d6bc9f3edb7181e748a474b97/pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9", size = 7105895, upload-time = "2026-07-01T11:56:16.575Z" },
+ { url = "https://files.pythonhosted.org/packages/18/f0/a5595c1e8c3ae44b9828cb2f0fa8155e5095ef04d6327b8f61cf44a3df85/pillow-12.3.0-cp315-cp315t-win32.whl", hash = "sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8", size = 6474384, upload-time = "2026-07-01T11:56:18.855Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/04/62bcd9f844984c5938d3b05264a61d797a29d3e0812341a8204af70bbdee/pillow-12.3.0-cp315-cp315t-win_amd64.whl", hash = "sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418", size = 7243537, upload-time = "2026-07-01T11:56:21.214Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/68/1f3066acedf37673694a7141381d8f811ae97f30d34413d236abe7d489f1/pillow-12.3.0-cp315-cp315t-win_arm64.whl", hash = "sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59", size = 2567491, upload-time = "2026-07-01T11:56:23.506Z" },
+ { url = "https://files.pythonhosted.org/packages/75/18/2e8b40223153ccbc60df07f9e8928dc0c76202aa4e55ae9f53962b6510d6/pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468", size = 5302510, upload-time = "2026-07-01T11:56:25.736Z" },
+ { url = "https://files.pythonhosted.org/packages/46/3e/51fabf59d5ab801ceab709453d3ab6b180083496579549de4c45ced6528a/pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94", size = 4736058, upload-time = "2026-07-01T11:56:28.041Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/20/22fe9384b7949e25fb1293bcfc84fb82590ff4ea6b37c95b24d26d793d86/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e", size = 5237776, upload-time = "2026-07-01T11:56:30.263Z" },
+ { url = "https://files.pythonhosted.org/packages/08/14/f6ba68107680ffa74b39985f3f30884e41318fbc4250caa423c79b4788bb/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3", size = 5860358, upload-time = "2026-07-01T11:56:32.68Z" },
+ { url = "https://files.pythonhosted.org/packages/36/54/0169bc772ec491108b62f644f8ecf1fe5d8ae5ebafde2ee2142210166903/pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a", size = 7231786, upload-time = "2026-07-01T11:56:35.046Z" },
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.20.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
+]
+
+[[package]]
+name = "pyparsing"
+version = "3.3.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "9.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "iniconfig" },
+ { name = "packaging" },
+ { name = "pluggy" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" },
+]
+
+[[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 = "pyyaml"
+version = "6.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" },
+ { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" },
+ { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" },
+ { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" },
+ { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" },
+ { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
+ { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
+ { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
+ { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
+ { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
+ { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
+ { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
+ { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
+ { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
+ { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
+ { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
+ { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
+ { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
+ { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
+ { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
+ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
+]
+
+[[package]]
+name = "ruff"
+version = "0.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/4d/94/1e5e4967626faf12fa56999cd6222dff6992ceb086ad7945756baf70c7a7/ruff-0.16.0.tar.gz", hash = "sha256:e460aafd5495ec89efaa6ced2e4a9a581116451e1c88b9d37ef497e0f8e93982", size = 4790557, upload-time = "2026-07-23T19:11:30.981Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/4b/81/1c8818fee7ce1a04cd7d1b3172e0a8f8e4f1dc4feb7fc390e16daa8af323/ruff-0.16.0-py3-none-linux_armv6l.whl", hash = "sha256:e5115729eb08c585e5121978ba5d5b60caeae394ce21b9fb5e6cd33a1c6c9b1e", size = 10754633, upload-time = "2026-07-23T19:10:46.415Z" },
+ { url = "https://files.pythonhosted.org/packages/23/df/beaf59c09d68db84304d555f188b276a77132a5d5b0b67a5c762aa143628/ruff-0.16.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3c954b1d580bfa035b41654f7858cc7e71d5fc3ac5b723dd62bd9133830ed522", size = 10969164, upload-time = "2026-07-23T19:10:50.271Z" },
+ { url = "https://files.pythonhosted.org/packages/42/ce/741cd197496a1abbf51352710fd15ed995d2a2be87189c1da26a450d6e83/ruff-0.16.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e01c21d10eb1b29f47b7454e1f4056db9a3f0260c646aa88457c610291db9f81", size = 10488846, upload-time = "2026-07-23T19:10:52.639Z" },
+ { url = "https://files.pythonhosted.org/packages/52/2a/a2db8e88cade358f5cdcb05674a917751074109315d014eb6352d9a893f7/ruff-0.16.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e364e5ed22ed8dc05082fd78e35308618260907ac2d3c1d637b2e682415b6c9", size = 10889729, upload-time = "2026-07-23T19:10:54.89Z" },
+ { url = "https://files.pythonhosted.org/packages/42/65/62a771694ebd63029dc953e27dbad40e1588bd4860ff9fe881018fddaa49/ruff-0.16.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d327b8fc113a1d4421a04f3839d3752057c8dd1ee320223a6f3f52d04ada462a", size = 10568275, upload-time = "2026-07-23T19:10:56.993Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/e2/ced249fe8af5f086c5c58cc21cc3356d50f32f7401c5df87050c999620a7/ruff-0.16.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b50c55e263103586b3dcf5f73d479eb8cb5fdb6098fec59a62891dab653717", size = 11385112, upload-time = "2026-07-23T19:10:59.615Z" },
+ { url = "https://files.pythonhosted.org/packages/87/0b/05154977a8fd69eeb6c103271f55403bfd8711f5c0f8ed07489d95a504e7/ruff-0.16.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ff4a79ce3ec0172f3241943835de1c4cb4e2dcd07f0f8c2d02603dbbbee4b17", size = 12207008, upload-time = "2026-07-23T19:11:02.154Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/29/98225831a3a1eab0e02f4acc6ca6559a98611dcc68b6965ff4b7234627c1/ruff-0.16.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e95c448fca1fb2a18372a9440926c5a6ee789639bb975c72e7ae6d0b04218ab4", size = 11650842, upload-time = "2026-07-23T19:11:04.557Z" },
+ { url = "https://files.pythonhosted.org/packages/91/66/6bd3cf90500653d55dc0ffc8507aa8300bd49d0214b2e8cb4d3fef2943ba/ruff-0.16.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f11a8d11010301d0a398a2fdef67691feca7294da6aef55e2150e8fa2cd520b", size = 11400718, upload-time = "2026-07-23T19:11:09.233Z" },
+ { url = "https://files.pythonhosted.org/packages/8e/a2/a54eb4eae05d66364050a5d3b8a9c5ef88196531b3cbe7109d873f87f819/ruff-0.16.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:48044c678e9cb8698246c99b14aaccfa6601dea7379eb48a6f8f73f7a6d86cd0", size = 11426177, upload-time = "2026-07-23T19:11:11.994Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/be/16e3eea4b2a478a496919f5e36f17c4559e54620bd3bbac5d6affa068006/ruff-0.16.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7aa0959bad8eb8bef50340154fc9b58678dae31fa4293afa38b44b6e552c0213", size = 10856126, upload-time = "2026-07-23T19:11:14.221Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/84/252eb8b868a16eec7257c14f504f77537e734b2d69c762e639e588e304a3/ruff-0.16.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28ea2b7df8ebf7f9da6b7d47b230ab48f387c0a29be3b474c4d0740e197bb9af", size = 10571208, upload-time = "2026-07-23T19:11:16.378Z" },
+ { url = "https://files.pythonhosted.org/packages/21/09/817a482f542f7570cbb4554b26e896610c7114f539b1d9e2d2145bf6bef6/ruff-0.16.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:33a3dfac8c35f81498dea9181bccc2f4c4bc8f1521a1dd9406e77643e0f0fb09", size = 11063329, upload-time = "2026-07-23T19:11:19.173Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/23/9403c180ca1cb9b1f7335f5c3e5305c09d49ea5b345196682a36028bde4a/ruff-0.16.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a5237a0bda500d30d81b8e07a6973a5cbc772864cbf746ae2f4e8a2e01c9f4ed", size = 11489751, upload-time = "2026-07-23T19:11:21.74Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/1d/1b2ef7bcde851c78d7f17f1cca13fd6dc695fc4b3d6197941e72cae5b132/ruff-0.16.0-py3-none-win32.whl", hash = "sha256:7fab76fa065c873f41ff744347c6e77bcc3dfec4bcc754dc26b63d23c0f7f5fb", size = 10785885, upload-time = "2026-07-23T19:11:23.947Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/a3/d5e4ef7a56be3f928ffb90b94c25ba7d3cb9c7fe0736aeaaedf361770712/ruff-0.16.0-py3-none-win_amd64.whl", hash = "sha256:429c117f022bf481fabd9d551e7a3952b24c65e6ef44337ea09d90bebef14472", size = 11923141, upload-time = "2026-07-23T19:11:26.409Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/9a/8415f2657cbe200f41a4531ccededf135505a92d4a012229121f885b26f9/ruff-0.16.0-py3-none-win_arm64.whl", hash = "sha256:14296fedcd2705c77ab8235439278bbb38f285cf7da5528b00b3e330c3d4872d", size = 11273407, upload-time = "2026-07-23T19:11:28.705Z" },
+]
+
+[[package]]
+name = "scipy"
+version = "1.17.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "numpy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" },
+ { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" },
+ { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" },
+ { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" },
+ { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" },
+ { url = "https://files.pythonhosted.org/packages/35/f5/906eda513271c8deb5af284e5ef0206d17a96239af79f9fa0aebfe0e36b4/scipy-1.17.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c80be5ede8f3f8eded4eff73cc99a25c388ce98e555b17d31da05287015ffa5b", size = 22704017, upload-time = "2026-02-23T00:18:21.502Z" },
+ { url = "https://files.pythonhosted.org/packages/da/34/16f10e3042d2f1d6b66e0428308ab52224b6a23049cb2f5c1756f713815f/scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e19ebea31758fac5893a2ac360fedd00116cbb7628e650842a6691ba7ca28a21", size = 32927842, upload-time = "2026-02-23T00:18:35.367Z" },
+ { url = "https://files.pythonhosted.org/packages/01/8e/1e35281b8ab6d5d72ebe9911edcdffa3f36b04ed9d51dec6dd140396e220/scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02ae3b274fde71c5e92ac4d54bc06c42d80e399fec704383dcd99b301df37458", size = 35235890, upload-time = "2026-02-23T00:18:49.188Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/5c/9d7f4c88bea6e0d5a4f1bc0506a53a00e9fcb198de372bfe4d3652cef482/scipy-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a604bae87c6195d8b1045eddece0514d041604b14f2727bbc2b3020172045eb", size = 35003557, upload-time = "2026-02-23T00:18:54.74Z" },
+ { url = "https://files.pythonhosted.org/packages/65/94/7698add8f276dbab7a9de9fb6b0e02fc13ee61d51c7c3f85ac28b65e1239/scipy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f590cd684941912d10becc07325a3eeb77886fe981415660d9265c4c418d0bea", size = 37625856, upload-time = "2026-02-23T00:19:00.307Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/84/dc08d77fbf3d87d3ee27f6a0c6dcce1de5829a64f2eae85a0ecc1f0daa73/scipy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:41b71f4a3a4cab9d366cd9065b288efc4d4f3c0b37a91a8e0947fb5bd7f31d87", size = 36549682, upload-time = "2026-02-23T00:19:07.67Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/98/fe9ae9ffb3b54b62559f52dedaebe204b408db8109a8c66fdd04869e6424/scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3", size = 24547340, upload-time = "2026-02-23T00:19:12.024Z" },
+ { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" },
+ { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" },
+ { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" },
+ { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" },
+ { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" },
+ { url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" },
+ { url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" },
+ { url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" },
+ { url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" },
+ { url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" },
+ { url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" },
+ { url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" },
+ { url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" },
+ { url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" },
+ { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" },
+]
+
+[[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 = "tensornetwork"
+version = "0.4.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "graphviz" },
+ { name = "h5py" },
+ { name = "numpy" },
+ { name = "opt-einsum" },
+ { name = "scipy" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a5/87/2e042a26284d76e71903f014b4148f1572a28d58af9ae0c7e86924c0ea93/tensornetwork-0.4.3.tar.gz", hash = "sha256:c23b1089327d1fd7b6038b15f597a4c3dad31a7231c628039dc6d99a1e499da8", size = 173862, upload-time = "2020-11-13T20:11:04.958Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0f/7f/5a5ecca306b61734669794bf43a560def309fdcf721150ea57a61b0b0085/tensornetwork-0.4.3-py3-none-any.whl", hash = "sha256:b1679e84c46947e55610b3bf73adb45f90a23a9621c21cf711e044c41dee446c", size = 372351, upload-time = "2020-11-13T20:11:03.393Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" },
+]
diff --git a/tracks/mps/solutions/Ranger-123/validation/ARTIFACT_PROVENANCE.json b/tracks/mps/solutions/Ranger-123/validation/ARTIFACT_PROVENANCE.json
new file mode 100644
index 000000000..7f5afed3c
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/validation/ARTIFACT_PROVENANCE.json
@@ -0,0 +1,58 @@
+{
+ "schema_version": 1,
+ "generated_date": "2026-07-30",
+ "source_snapshot_commit": "2a6d61b5028c7960d3808111c51663cb65893ca9",
+ "heat_valve_generated_date": "2026-07-30",
+ "heat_valve_source_snapshot_commit": "b42725363a01e2ca88b951c3d28026df8104aa40",
+ "uniform_tempo_revision": "b76a018c32e5415989761d902b1b0e95f1a337da",
+ "verification": {
+ "pytest": "110 passed",
+ "ruff": "passed",
+ "mypy": "passed",
+ "result_audit": "passed: 6 result files",
+ "paper_audit": "passed",
+ "julia_import_smoke": "passed: 2/2 environment tests",
+ "wheel_build": "passed",
+ "heat_valve_audit": "expected rejection: dark-channel gates not met"
+ },
+ "sha256": {
+ "results/paper/n3_heat_manifest.json": "67e157c8bcf353873c3c9bc725ef7d92267f0074c04a11ca0c53c430ef0bf507",
+ "results/paper/error_map_manifest.json": "482182b661fa63d243a929771339d553d6b1588ce7f52fa088736dff24658230",
+ "results/paper/model_comparison_manifest.json": "30e5bc4bf4228c9da1f83cc15f85ac921788bd2c0d4b4923bc9374309a75cef8",
+ "results/validation/uniform_tempo_single_spin.json": "ffa32de8d9fdc64b191a1168ea4285639d7fcaae962d8701d1c0a3be789d8720",
+ "results/validation/uniform_tempo_oqupy_crosscheck.json": "7f0cb2840805180ddb157100fd1a6f3fea92178a9aa7e95813a3025c1b1940b7",
+ "figures/paper/n3_sector_heat.png": "0e37e61b6c74464fbd051239712617d67513602c6edcbaa95b0490fb80554828",
+ "figures/paper/n3_sector_heat.pdf": "af783a170eddbc79c155cd2ff4df100040dbbad73b0b9a0d8bee76e336387ae5",
+ "figures/paper/n3_odd_difference.png": "f048a37aed6b68c89eb42cf93fdd45bfbb62e34e5250d07aa01a93b4f8f7bc4b",
+ "figures/paper/n3_odd_difference.pdf": "4fe9f941b069475e2304f9b037a7da3ba59bf0121e270cbfb35fce39d86deae1",
+ "figures/paper/error_maps.png": "366055d2284c83a9e3c88fcf1ae53931f2af86254d3693266441592ea59eeb4b",
+ "figures/paper/error_maps.pdf": "9ea3153a169ffb090a1201eab6feae16e2aabac1aa670895b8e8cf9d0838ca3a",
+ "figures/paper/dark_diagnostics.png": "511a625e345768d88a51bc0fc28a02124dc83ac4cdde9af8bc929956a8bc764e",
+ "figures/paper/dark_diagnostics.pdf": "960b07cacf57529c06cc0f3db6d6c4968c7e6fd72453ec48c4d0687082d5b7d6",
+ "figures/paper/model_variants.png": "b19332ffaabc4cce65890df12a053814427ae3191a9a28c4482aa0a8e134091f",
+ "figures/paper/model_variants.pdf": "2e494978fd56104c83cf7e9e84f0b962a4ddfa3c413fccfbd3b6bf3d8adcbbaf",
+ "results/heat-valve/isolated_scan.json": "629a7fc00fad22912de6f2ed3ce0197b4aa467334791e1b7b9ff54baa3a9eb40",
+ "results/heat-valve/heat_valve_manifest.json": "d7bb70e257089a4b7f88ba278a85e5533f1ac3fb8e5a6a7f637e98c714693303",
+ "figures/heat-valve/heat_valve_hero.png": "fd203c4bab0f6a95da7b13139339f7e4a124c26a494e20d249ef1c77f6d56134",
+ "figures/heat-valve/heat_valve_hero.pdf": "ebc15ff891106b3592f41e3b1770a2dfae7d8b02533e1793d24a725f1a2a86d4",
+ "results/validation/fig3_transversal_wd1.json": "5747407d5c19494d826d1bc8a52cd29a654dc774dc2fc69dfa30d8c19ec5cd1e",
+ "results/validation/fig3_transversal_wd1p5.json": "531b1705c89a42bdb2fa7f8a707f99f42e162ee9c72958f15e2acb806fa15464",
+ "results/validation/fig3_transversal_wd2.json": "a45949df0bde3cf7688cbd7863035950203f0aace7ea790975f40ebb5e0a4494",
+ "validation/fig3_transversal_summary.json": "5aef6a8c161dd18d8c434c33544786589bb8c4b4344d5d0e54c5405f2b68d9e3",
+ "validation/fig3_transversal_wd2.json": "3bac6b1566f7f97b74132797b2bf64cecf40debd480fc5d4e1f5de3688948fbf",
+ "figures/validation/fig3_transversal_summary.pdf": "b61fff7fcfb3743720891a0d85614039c280438d1c00507d45cbe29dedce3c15",
+ "figures/validation/fig3_transversal_summary.png": "c51e6280b5e48a332753174ef2d74c1c5f6e2948f49f9ffbb0604bdf6d8347ef",
+ "validation/n3_same_model_error_map.json": "a9588ee808b66f984e45f724e7f201dfd9e617c611a68068a8452c4df6158320",
+ "figures/paper/n3_error_maps.pdf": "958ecd31b08da93d168942ef7fc61e7d22ac21ecc7a8fed6aae9b045af622dd7",
+ "figures/paper/n3_error_maps.png": "07c5d5444285c07a0c2a47c4d988702189a18bd8cca603191cb0b4515c2c883c",
+ "results/paper/n4_even_j0.25.json": "cdd9d5c2694d788e807568f101be31924b2d829c83fcab7bd58e58ad00516cb5",
+ "results/paper/n4_odd_j0.25.json": "e7f97894653ac16e9ec937e61e332862d05684a454b9adc01798b83d9f713096",
+ "validation/n4_pilot.json": "b32fa3f65c4128b46d827272450c83b7547a16a951600f40aa7890f70a53cba6",
+ "figures/paper/n4_even_j0p25_comparison.pdf": "a616fb969ba5c3493cec393f18794670b121b8567b34901766cc8fd06b09cccd",
+ "figures/paper/n4_even_j0p25_comparison.png": "b09f1efd0997a4de43f7ec3994e4b4f9250c323dfd29e5abc39c204d322a3013",
+ "figures/paper/n4_odd_j0p25_comparison.pdf": "f92914262b4b9acc7ef96b6e65e2dc19e10338f612c9b87fe3210fe626c3b529",
+ "figures/paper/n4_odd_j0p25_comparison.png": "e6a59cf9d95593b8ce5d2637b01909215f39caa72502acdb206cb639decaa391",
+ "report/data-summary.txt": "680d05b2243e07038dcca60cef09d2264ba15284fb108fe2fefc8210bb6c542e",
+ "output/pdf/Ranger-123-technical-report.pdf": "69447a7643c9e145e9507601af4af48c77bc0c1c9e93bf0ceafd6709a60035b8"
+ }
+}
diff --git a/tracks/mps/solutions/Ranger-123/validation/fig3_transversal_summary.json b/tracks/mps/solutions/Ranger-123/validation/fig3_transversal_summary.json
new file mode 100644
index 000000000..c97b8e175
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/validation/fig3_transversal_summary.json
@@ -0,0 +1,41 @@
+{
+ "method": "uniform_tempo_fig3_transversal_reproduction",
+ "complete": true,
+ "converged_points": 3,
+ "scope": "independent N=1 reproduction of all three published Fig. 3 bottom-panel curves",
+ "reference": {
+ "record": "https://zenodo.org/records/19593671",
+ "archive_md5": "0f3f9d9d8538aa96aee089973df7d9c2",
+ "panel": "Fig. 3 bottom"
+ },
+ "points": [
+ {
+ "drive_frequency": 1.0,
+ "converged": true,
+ "controls": {"steps_per_period": 120, "tolerance": 1e-7, "phase_samples": 15, "delay_periods": 12},
+ "diagnostics": {"bond_dimension": 26, "connected_tail_amplitude": 0.001627256392104337, "fixed_point_residual": 0.00008087148135240392, "hermiticity_error": 0.0036099263191221318, "trace_error": 0.0000749222438648638, "minimum_density_eigenvalue": 0.2358702724786363},
+ "metrics": {"continuous_relative_l1": 0.06333707191194522, "normalized_shape_relative_l1": 0.056243489156938865, "integrated_magnitude_ratio": 1.026771197996517}
+ },
+ {
+ "drive_frequency": 1.5,
+ "converged": true,
+ "controls": {"steps_per_period": 80, "tolerance": 1e-6, "phase_samples": 4, "delay_periods": 12},
+ "diagnostics": {"bond_dimension": 14, "connected_tail_amplitude": 0.0023604904459384114, "fixed_point_residual": 0.0005313576529202555, "hermiticity_error": 0.004272614695140364, "trace_error": 0.0003929538774845975, "minimum_density_eigenvalue": 0.15004045531920804},
+ "metrics": {"continuous_relative_l1": 0.23826748531590006, "normalized_shape_relative_l1": 0.2735649534808351, "integrated_magnitude_ratio": 1.1622298099461896}
+ },
+ {
+ "drive_frequency": 2.0,
+ "converged": true,
+ "controls": {"steps_per_period": 60, "tolerance": 1e-6, "phase_samples": 4, "delay_periods": 12},
+ "diagnostics": {"bond_dimension": 14, "connected_tail_amplitude": 0.015605745626824328, "fixed_point_residual": 0.0003084472032725321, "hermiticity_error": 0.00320077988078783, "trace_error": 0.00022911934882153764, "minimum_density_eigenvalue": 0.05449589091447455},
+ "metrics": {"continuous_relative_l1": 0.3455071050704775, "normalized_shape_relative_l1": 0.37183146692817987, "integrated_magnitude_ratio": 1.3118951143348248}
+ }
+ ],
+ "artifact_sha256": {
+ "results/validation/fig3_transversal_wd1.json": "5747407d5c19494d826d1bc8a52cd29a654dc774dc2fc69dfa30d8c19ec5cd1e",
+ "results/validation/fig3_transversal_wd1p5.json": "531b1705c89a42bdb2fa7f8a707f99f42e162ee9c72958f15e2acb806fa15464",
+ "results/validation/fig3_transversal_wd2.json": "a45949df0bde3cf7688cbd7863035950203f0aace7ea790975f40ebb5e0a4494",
+ "figures/validation/fig3_transversal_summary.pdf": "b61fff7fcfb3743720891a0d85614039c280438d1c00507d45cbe29dedce3c15",
+ "figures/validation/fig3_transversal_summary.png": "c51e6280b5e48a332753174ef2d74c1c5f6e2948f49f9ffbb0604bdf6d8347ef"
+ }
+}
diff --git a/tracks/mps/solutions/Ranger-123/validation/fig3_transversal_wd2.json b/tracks/mps/solutions/Ranger-123/validation/fig3_transversal_wd2.json
new file mode 100644
index 000000000..f8e1a5a22
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/validation/fig3_transversal_wd2.json
@@ -0,0 +1,39 @@
+{
+ "method": "uniform_tempo_fig3_transversal_reproduction",
+ "complete": true,
+ "scope": "independent N=1 reproduction of the published Fig. 3 bottom-panel curve at drive frequency 2.0",
+ "reference": {
+ "record": "https://zenodo.org/records/19593671",
+ "archive_md5": "0f3f9d9d8538aa96aee089973df7d9c2",
+ "panel": "Fig. 3 bottom"
+ },
+ "controls": {
+ "steps_per_period": 60,
+ "delay_periods": 12,
+ "phase_samples": 4,
+ "tolerance": 1e-6
+ },
+ "diagnostics": {
+ "bond_dimension": 14,
+ "connected_tail_amplitude": 0.015605745626824328,
+ "fixed_point_residual": 0.0003084472032725321,
+ "hermiticity_error": 0.00320077988078783,
+ "trace_error": 0.00022911934882153764,
+ "minimum_density_eigenvalue": 0.05449589091447455,
+ "process_tensor_cache_hit": 1
+ },
+ "comparison": {
+ "continuous_relative_l1": 0.3455071050704775,
+ "normalized_shape_relative_l1": 0.37183146692817987,
+ "integrated_magnitude_ratio": 1.3118951143348248
+ },
+ "delta_peaks": [
+ {"frequency": 2.0, "harmonic": 1, "weight": 0.028133718980199732},
+ {"frequency": 4.0, "harmonic": 2, "weight": 3.5293284163875763e-10}
+ ],
+ "artifact_sha256": {
+ "results/validation/fig3_transversal_wd2.json": "a45949df0bde3cf7688cbd7863035950203f0aace7ea790975f40ebb5e0a4494",
+ "figures/validation/fig3_transversal_wd2.pdf": "3ba0bf730d41e3da1d37fde8e35f7ca7eb2c0cc0c2aa6fc2379e939be51e04d7",
+ "figures/validation/fig3_transversal_wd2.png": "a93859b38040c02a90a177af9ada81a06b905481302d4d385aa6d046482f381f"
+ }
+}
diff --git a/tracks/mps/solutions/Ranger-123/validation/n3_same_model_error_map.json b/tracks/mps/solutions/Ranger-123/validation/n3_same_model_error_map.json
new file mode 100644
index 000000000..d80b87f96
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/validation/n3_same_model_error_map.json
@@ -0,0 +1,19 @@
+{
+ "method": "n3_uniform_tempo_vs_floquet_markov_qr",
+ "complete": true,
+ "converged_points": 6,
+ "model_scope": "same N=3 reflection sector, Hamiltonian, drive and bath parameters",
+ "points": [
+ {"j": 0.25, "sector": "even", "trace_distance": 0.9996997375851921, "correlation_error": 1.1529657847337855, "heat_error": 9.016706811174881},
+ {"j": 0.50, "sector": "even", "trace_distance": 0.9999010667013211, "correlation_error": 1.0341250650150768, "heat_error": 11.715780183401042},
+ {"j": 1.00, "sector": "even", "trace_distance": 0.9920891824177340, "correlation_error": 1.0243258716943124, "heat_error": 9.077234824882260},
+ {"j": 0.25, "sector": "odd", "trace_distance": 0.4752509683642790, "correlation_error": 0.5666192029309954, "heat_error": 0.3920114223680808},
+ {"j": 0.50, "sector": "odd", "trace_distance": 0.4752509683642792, "correlation_error": 0.5666192029309957, "heat_error": 0.3920114223680807},
+ {"j": 1.00, "sector": "odd", "trace_distance": 0.4752509683642792, "correlation_error": 0.5666192029309958, "heat_error": 0.3920114223680807}
+ ],
+ "artifact_sha256": {
+ "results/paper/n3_error_map_manifest.json": "287f9cb189a57f0348791ce194adf75bccb5628dbe4975baf99b2f43597770ad",
+ "figures/paper/n3_error_maps.pdf": "958ecd31b08da93d168942ef7fc61e7d22ac21ecc7a8fed6aae9b045af622dd7",
+ "figures/paper/n3_error_maps.png": "07c5d5444285c07a0c2a47c4d988702189a18bd8cca603191cb0b4515c2c883c"
+ }
+}
diff --git a/tracks/mps/solutions/Ranger-123/validation/n4_pilot.json b/tracks/mps/solutions/Ranger-123/validation/n4_pilot.json
new file mode 100644
index 000000000..a7e922af5
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/validation/n4_pilot.json
@@ -0,0 +1,49 @@
+{
+ "method": "n4_uniform_tempo_convergence_pilot",
+ "complete": true,
+ "converged_points": 2,
+ "model_scope": "same N=4 Hamiltonian and bath at J/Omega=0.25, resolved by reflection sector",
+ "points": [
+ {
+ "sector": "even",
+ "dimension": 10,
+ "delay_periods": 6,
+ "bond_dimension": 13,
+ "connected_tail_amplitude": 0.02133175984671692,
+ "fixed_point_residual": 0.00035886128826079347,
+ "hermiticity_error": 0.0008819593032858546,
+ "trace_error": 0.0003388881943872353,
+ "minimum_density_eigenvalue": -0.00046822521586976576,
+ "markov_metrics": {
+ "trace_distance_raw": 1.0008536447854561,
+ "correlation_error": 1.6286041909228848,
+ "heat_error": 5.493776886006749
+ }
+ },
+ {
+ "sector": "odd",
+ "dimension": 6,
+ "delay_periods": 3,
+ "bond_dimension": 8,
+ "connected_tail_amplitude": 0.036779095635906804,
+ "fixed_point_residual": 0.00037773511660346736,
+ "hermiticity_error": 0.00009174537985208175,
+ "trace_error": 0.0003542407259329822,
+ "minimum_density_eigenvalue": -0.003262969712857272,
+ "markov_metrics": {
+ "trace_distance_raw": 1.0043613609854345,
+ "correlation_error": 1.601339921831332,
+ "heat_error": 3.4047954293441243
+ }
+ }
+ ],
+ "note": "Raw trace-norm diagnostics can exceed one slightly because the accepted UniformTEMPO density matrices retain small negative eigenvalues within the preregistered -0.005 gate.",
+ "artifact_sha256": {
+ "results/paper/n4_even_j0.25.json": "cdd9d5c2694d788e807568f101be31924b2d829c83fcab7bd58e58ad00516cb5",
+ "results/paper/n4_odd_j0.25.json": "e7f97894653ac16e9ec937e61e332862d05684a454b9adc01798b83d9f713096",
+ "figures/paper/n4_even_j0p25_comparison.pdf": "a616fb969ba5c3493cec393f18794670b121b8567b34901766cc8fd06b09cccd",
+ "figures/paper/n4_even_j0p25_comparison.png": "b09f1efd0997a4de43f7ec3994e4b4f9250c323dfd29e5abc39c204d322a3013",
+ "figures/paper/n4_odd_j0p25_comparison.pdf": "f92914262b4b9acc7ef96b6e65e2dc19e10338f612c9b87fe3210fe626c3b529",
+ "figures/paper/n4_odd_j0p25_comparison.png": "e6a59cf9d95593b8ce5d2637b01909215f39caa72502acdb206cb639decaa391"
+ }
+}
diff --git a/tracks/mps/solutions/Ranger-123/validation/uniform_tempo_oqupy_crosscheck.json b/tracks/mps/solutions/Ranger-123/validation/uniform_tempo_oqupy_crosscheck.json
new file mode 100644
index 000000000..dc155588d
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/validation/uniform_tempo_oqupy_crosscheck.json
@@ -0,0 +1,17 @@
+{
+ "complete": true,
+ "converged": true,
+ "interpretation": "independent coarse-backend diagnostic; not a convergence refinement",
+ "method": "coarse_uniform_tempo_vs_oqupy_cross_validation",
+ "metrics": {
+ "connected_correlation_relative_l1": 0.28171563084762685,
+ "continuous_heat_relative_l1": 0.51707850109946,
+ "phase_state_frobenius": 0.373843235587285
+ },
+ "oqupy_fingerprint": "1639ce757970ef3819ad72ab1cd7d40b2c1a3527f5e53a6b6d57c2fff34e847e",
+ "projected_odd_j_invariance": {
+ "coupling_frobenius_residual": 0.0,
+ "h0_frobenius_residual": 0.0
+ },
+ "uniform_fingerprint": "97688130575f00aa3234cef5ca7abff20ab1214cd5a472355cb3f7bd78b7a5a4"
+}
\ No newline at end of file
diff --git a/tracks/mps/solutions/Ranger-123/validation/uniform_tempo_single_spin.json b/tracks/mps/solutions/Ranger-123/validation/uniform_tempo_single_spin.json
new file mode 100644
index 000000000..8dbdb4f19
--- /dev/null
+++ b/tracks/mps/solutions/Ranger-123/validation/uniform_tempo_single_spin.json
@@ -0,0 +1,884 @@
+{
+ "bath": {
+ "alpha": 0.05,
+ "cutoff": 2.5,
+ "temperature": 0.0
+ },
+ "continuous": [
+ 0.0,
+ 6.246011012345299e-07,
+ 2.410763291657597e-06,
+ 5.234328797497268e-06,
+ 8.980661160415742e-06,
+ 1.3544313806662395e-05,
+ 1.8828632121399976e-05,
+ 2.474529868847087e-05,
+ 3.121383461272567e-05,
+ 3.816107227429673e-05,
+ 4.552061634074449e-05,
+ 5.3232310327801245e-05,
+ 6.124172547315725e-05,
+ 6.949968726153122e-05,
+ 7.796185276194096e-05,
+ 8.658834919810844e-05,
+ 9.534348107795442e-05,
+ 0.00010419550996421254,
+ 0.00011311650776146267,
+ 0.00012208228137754667,
+ 0.00013107236389979477,
+ 0.00014007006507585866,
+ 0.00014906257193429427,
+ 0.0001580410888228165,
+ 0.0001670010049702479,
+ 0.00017594207688128747,
+ 0.00018486861245667883,
+ 0.00019378964372608447,
+ 0.0002027190755477618,
+ 0.00021167579865498395,
+ 0.00022068375711660235,
+ 0.00022977196272779308,
+ 0.00023897445213050202,
+ 0.00024833018660273376,
+ 0.0002578828993960251,
+ 0.00026768090108819783,
+ 0.00027777685939189,
+ 0.0002882275758477462,
+ 0.0002990937873694214,
+ 0.00031044002516536745,
+ 0.00032233456658811217,
+ 0.0003348495164372542,
+ 0.0003480610527466853,
+ 0.00036204986785957026,
+ 0.00037690182859772214,
+ 0.00039270886979465315,
+ 0.0004095701239096078,
+ 0.0004275932766976175,
+ 0.00044689612607343306,
+ 0.00046760830968146656,
+ 0.0004898731576963622,
+ 0.000513849622457748,
+ 0.0005397142369798788,
+ 0.0005676630611781005,
+ 0.0005979135883935308,
+ 0.0006307066054864546,
+ 0.0006663080267570033,
+ 0.0007050107538693615,
+ 0.000747136648714555,
+ 0.0007930387410017162,
+ 0.0008431038240458586,
+ 0.0008977556171160274,
+ 0.000957458687134105,
+ 0.001022723322999492,
+ 0.0010941115394219277,
+ 0.0011722443517982592,
+ 0.0012578104084528515,
+ 0.0013515759919694621,
+ 0.0014543963094495098,
+ 0.0015672278860644879,
+ 0.0016911417625596556,
+ 0.001827337082167944,
+ 0.0019771545435792706,
+ 0.0021420891027325735,
+ 0.0023238012359485995,
+ 0.0025241260385128112,
+ 0.0027450794333238326,
+ 0.0029888608089216756,
+ 0.0032578514979777606,
+ 0.003554608646137877,
+ 0.0038818542036702826,
+ 0.004242458991971475,
+ 0.0046394220435401505,
+ 0.005075845674398835,
+ 0.005554907006453562,
+ 0.006079826896525985,
+ 0.006653837430604904,
+ 0.007280149288463577,
+ 0.007961920359016139,
+ 0.008702226977356037,
+ 0.009504039051119701,
+ 0.010370200142555379,
+ 0.011303413275290448,
+ 0.012306232849570735,
+ 0.013381062591569914,
+ 0.014530158952447329,
+ 0.015755638838007992,
+ 0.017059490021459265,
+ 0.01844358210424675,
+ 0.019909675478874882,
+ 0.021459425447689518,
+ 0.02309437849448109,
+ 0.024815957717866585,
+ 0.02662543463581758,
+ 0.028523884969403633,
+ 0.030512126610282724,
+ 0.03259063875876238,
+ 0.034759462163744315,
+ 0.037018081467599676,
+ 0.03936529181276555,
+ 0.04179905304881195,
+ 0.04431633602888158,
+ 0.04691296653933202,
+ 0.04958347330254375,
+ 0.052320947169898636,
+ 0.05511691902636733,
+ 0.05796126401654035,
+ 0.06084213944393731,
+ 0.06374596307617525,
+ 0.06665743761042427,
+ 0.06955962573701086,
+ 0.07243407862258716,
+ 0.07526101877359367,
+ 0.07801957620653377,
+ 0.08068807472683338,
+ 0.08324436299441287,
+ 0.08566618302757315,
+ 0.08793156696321491,
+ 0.09001925134156058,
+ 0.09190909699851277,
+ 0.09358250189555437,
+ 0.09502279394479701,
+ 0.09621559112370455,
+ 0.09714911692560853,
+ 0.09781446044013849,
+ 0.09820577206044577,
+ 0.09832038790805815,
+ 0.09815887846856566,
+ 0.09772501954372242,
+ 0.09702568633854354,
+ 0.09607067420023278,
+ 0.094872452093565,
+ 0.093445857224106,
+ 0.09180774120638563,
+ 0.08997657973426544,
+ 0.08797205878025015,
+ 0.08581465088705342,
+ 0.08352519510073898,
+ 0.08112449353807687,
+ 0.07863293651418907,
+ 0.07607016663607512,
+ 0.0734547903693923,
+ 0.07080414340237419,
+ 0.06813411376600319,
+ 0.06545902423378377,
+ 0.06279157312872291,
+ 0.06014283041573984,
+ 0.05752228395115928,
+ 0.054937929079241055,
+ 0.05239639347281331,
+ 0.04990308825409039,
+ 0.04746237602338244,
+ 0.0450777464655552,
+ 0.04275199067274957,
+ 0.04048736617297138,
+ 0.03828574582658395,
+ 0.036148745172022,
+ 0.03407782438471032,
+ 0.032074362671401936,
+ 0.03013970456850261,
+ 0.028275179164932985,
+ 0.026482094654240597,
+ 0.024761711776094063,
+ 0.02311520058824644,
+ 0.021543585587731773,
+ 0.020047684463321065,
+ 0.01862804571636736,
+ 0.017284890056578375,
+ 0.01601805989957762,
+ 0.014826980512379866,
+ 0.013710635427307723,
+ 0.01266755773522004,
+ 0.011695837836988979,
+ 0.010793147237193124,
+ 0.009956777059483236,
+ 0.009183689194081784,
+ 0.008470577388920302,
+ 0.007813935189634262,
+ 0.007210127430158404,
+ 0.006655461972797193,
+ 0.006146258580707288,
+ 0.005678912153087279,
+ 0.00524994803240645,
+ 0.004856067666507089,
+ 0.00449418353612073,
+ 0.004161442899545035,
+ 0.003855240522247892,
+ 0.0035732211155493853,
+ 0.0033132726768626613,
+ 0.003073512283217107,
+ 0.002852266127077364,
+ 0.002648045694368223,
+ 0.0024595219728006565,
+ 0.002285499455095534,
+ 0.002124891483686128,
+ 0.001976698192759018,
+ 0.0018399879647930412,
+ 0.0017138829579565883,
+ 0.001597548903088936,
+ 0.0014901890375920684,
+ 0.0013910417579155814,
+ 0.001299381347372743,
+ 0.001214520981484704,
+ 0.0011358171331080653,
+ 0.00106267449305273,
+ 0.000994550582605109,
+ 0.0009309593520365432,
+ 0.0008714732203275623,
+ 0.0008157232004945066,
+ 0.0007633969557819144,
+ 0.0007142348286891056,
+ 0.0006680240629174083,
+ 0.0006245915858405593,
+ 0.0005837958270802037,
+ 0.0005455181118071931,
+ 0.000509654183748004,
+ 0.00047610638438916244,
+ 0.0004447769465754355,
+ 0.0004155627602590262,
+ 0.0003883518451691195,
+ 0.00036302163031462134,
+ 0.00033943900444167633,
+ 0.00031746197520494203,
+ 0.00029694266693248045,
+ 0.0002777313046381088,
+ 0.0002596807801969557,
+ 0.00024265137764888035,
+ 0.0002265152481332754,
+ 0.0002111602682808947,
+ 0.0001964929841924191,
+ 0.00018244042999277698,
+ 0.00016895070789036326,
+ 0.00015599231775973588,
+ 0.00014355232075598362,
+ 0.0001316335063469672,
+ 0.00012025079963577542,
+ 0.0001094271917698799,
+ 9.918949825548104e-05,
+ 8.956424770619113e-05,
+ 8.057397840287908e-05,
+ 7.223417513333661e-05,
+ 6.455101857490847e-05,
+ 5.752004937241045e-05,
+ 5.112577493528866e-05,
+ 4.534217473327122e-05,
+ 4.0133994971937194e-05,
+ 3.545867061808132e-05,
+ 3.1268675301135906e-05,
+ 2.7514079766677046e-05,
+ 2.414509795697805e-05,
+ 2.1114415648912646e-05,
+ 1.8379127776497666e-05,
+ 1.5902153881429813e-05,
+ 1.365305255057466e-05,
+ 1.160821073093934e-05,
+ 9.750437893802853e-06,
+ 8.068043851781972e-06,
+ 6.553518920850745e-06,
+ 5.2019632249287885e-06,
+ 4.009426487953308e-06,
+ 2.971320016066192e-06,
+ 2.0810492755028896e-06,
+ 1.3289901246175193e-06,
+ 7.018968824839849e-07,
+ 1.8278920251107496e-07,
+ -2.4867922989856276e-07,
+ -6.154101399343436e-07,
+ -9.416867209043845e-07,
+ -1.2517457687521384e-06,
+ -1.5682264763202102e-06,
+ -1.9106362244907943e-06,
+ -2.293971563464242e-06,
+ -2.7276189585202674e-06,
+ -3.2146361273416363e-06,
+ -3.751483031279505e-06,
+ -4.328234520155807e-06,
+ -4.929267336101747e-06,
+ -5.534375846017151e-06,
+ -6.120236543725711e-06,
+ -6.662113697021515e-06,
+ -7.135679616969436e-06,
+ -7.518814239190242e-06,
+ -7.793250584713019e-06,
+ -7.945944894230563e-06,
+ -7.970071705246924e-06,
+ -7.865573056088375e-06,
+ -7.639225005139216e-06,
+ -7.304221041871067e-06,
+ -6.879307911220924e-06,
+ -6.387542113219607e-06,
+ -5.854762439603197e-06,
+ -5.307893388222404e-06,
+ -4.773204813549458e-06,
+ -4.274654093869671e-06,
+ -3.832428533081928e-06,
+ -3.461788505312902e-06,
+ -3.1722874719828353e-06,
+ -2.9674154453741266e-06,
+ -2.8446800882510058e-06,
+ -2.7961069352961516e-06,
+ -2.8091096776415734e-06,
+ -2.867655327913706e-06,
+ -2.953629253437597e-06,
+ -3.048292876251104e-06,
+ -3.133723031945004e-06,
+ -3.19412663664551e-06,
+ -3.2169368670804377e-06,
+ -3.193616359200054e-06,
+ -3.12011734374322e-06,
+ -2.9969761657336124e-06,
+ -2.829048106688348e-06,
+ -2.6249156496848735e-06,
+ -2.396027244610756e-06,
+ -2.1556425140629426e-06,
+ -1.9176723674966236e-06,
+ -1.6955078749642935e-06,
+ -1.5009297688840276e-06,
+ -1.3431814348506852e-06,
+ -1.2282731081206876e-06,
+ -1.1585650264511285e-06,
+ -1.1326541851574782e-06,
+ -1.1455649486427197e-06,
+ -1.1892200206827555e-06,
+ -1.2531469903617537e-06,
+ -1.3253584231551742e-06,
+ -1.3933315133993586e-06,
+ -1.4450074306286894e-06,
+ -1.4697309948797156e-06,
+ -1.4590580096524046e-06,
+ -1.4073697819941927e-06,
+ -1.3122509962422335e-06,
+ -1.174606773575466e-06,
+ -9.985158321836042e-07,
+ -7.908375007426227e-07,
+ -5.606092905270369e-07,
+ -3.1828738416581947e-07,
+ -7.489358609634583e-08,
+ 1.5886175841486835e-07,
+ 3.7341098830728163e-07,
+ 5.610497130600683e-07,
+ 7.164920533038756e-07,
+ 8.372199705885996e-07,
+ 9.23603156470485e-07,
+ 9.78784465638975e-07,
+ 1.0083444187214016e-06,
+ 1.019775400614051e-06,
+ 1.0218105501853628e-06,
+ 1.0236629058586623e-06,
+ 1.0342363957985784e-06,
+ 1.0613713631006854e-06,
+ 1.1111835125557713e-06,
+ 1.1875468519034401e-06,
+ 1.291759111538605e-06,
+ 1.4224132832291594e-06,
+ 1.5754825287733385e-06,
+ 1.7446090751373544e-06,
+ 1.9215721328552543e-06,
+ 2.096896531138668e-06,
+ 2.2605536501127856e-06,
+ 2.4027000577264358e-06,
+ 2.5143974197989927e-06,
+ 2.5882598061354867e-06,
+ 2.6189811514391164e-06,
+ 2.6037057633254813e-06,
+ 2.5422175206331893e-06,
+ 2.4369377405892855e-06,
+ 2.2927364512581446e-06,
+ 2.116575848709978e-06,
+ 1.9170169540328347e-06,
+ 1.7036300267540895e-06,
+ 1.4863554420418504e-06,
+ 1.274864121381414e-06,
+ 1.0779651106404536e-06,
+ 9.03102756660979e-07,
+ 7.559776195583648e-07,
+ 6.403145233659729e-07,
+ 5.577888822905056e-07,
+ 5.081096583452525e-07,
+ 4.892450270079437e-07,
+ 4.97766012176329e-07,
+ 5.292748175392958e-07,
+ 5.788789572754247e-07,
+ 6.416699475921113e-07,
+ 7.131663699147851e-07,
+ 7.896853931353791e-07,
+ 8.686139344297933e-07,
+ 9.485598888763598e-07,
+ 1.029374509619914e-06,
+ 1.1120481397888362e-06,
+ 1.1984922107641867e-06,
+ 1.2912298391609135e-06
+ ],
+ "controls": {
+ "auto_nc": true,
+ "cap_rank": 5000,
+ "delay_periods": 6,
+ "low_rank_svd": true,
+ "max_rank": 10000,
+ "memory_cutoff": 100000,
+ "phase_samples": 3,
+ "steps_per_period": 60,
+ "tolerance": 1e-06,
+ "truncation": "abs"
+ },
+ "converged": true,
+ "delta_peaks": [
+ {
+ "frequency": 1.0,
+ "harmonic": 1,
+ "weight": 0.025497244175075658
+ }
+ ],
+ "diagnostics": {
+ "bond_dimension": 19,
+ "connected_tail_amplitude": 0.005549383080176303,
+ "dt": 0.10471975511965977,
+ "fixed_point_residual": 0.00014007807758301285,
+ "floquet_transfer_residual": 0.00014007807758162496,
+ "hermiticity_error": 0.0004168835562094166,
+ "julia_version": "1.12.6",
+ "manifest_sha256": "6038d836b15eeb9b2f1b20bf675fa3d464b6d7c21b534cd6df430e748bdda0f7",
+ "minimum_density_eigenvalue": 0.10636006886047145,
+ "period_steps": 60,
+ "phase_samples": 3,
+ "process_tensor_cache_hit": 1,
+ "tolerance": 1e-06,
+ "trace_error": 9.243986058611653e-05,
+ "uniform_tempo_revision": "b76a018c32e5415989761d902b1b0e95f1a337da"
+ },
+ "frequency": [
+ 0.0,
+ 0.0075,
+ 0.015,
+ 0.0225,
+ 0.03,
+ 0.0375,
+ 0.045,
+ 0.0525,
+ 0.06,
+ 0.0675,
+ 0.075,
+ 0.08249999999999999,
+ 0.09,
+ 0.0975,
+ 0.105,
+ 0.11249999999999999,
+ 0.12,
+ 0.1275,
+ 0.135,
+ 0.1425,
+ 0.15,
+ 0.1575,
+ 0.16499999999999998,
+ 0.1725,
+ 0.18,
+ 0.1875,
+ 0.195,
+ 0.20249999999999999,
+ 0.21,
+ 0.2175,
+ 0.22499999999999998,
+ 0.23249999999999998,
+ 0.24,
+ 0.2475,
+ 0.255,
+ 0.2625,
+ 0.27,
+ 0.27749999999999997,
+ 0.285,
+ 0.2925,
+ 0.3,
+ 0.3075,
+ 0.315,
+ 0.3225,
+ 0.32999999999999996,
+ 0.33749999999999997,
+ 0.345,
+ 0.3525,
+ 0.36,
+ 0.3675,
+ 0.375,
+ 0.3825,
+ 0.39,
+ 0.39749999999999996,
+ 0.40499999999999997,
+ 0.4125,
+ 0.42,
+ 0.4275,
+ 0.435,
+ 0.4425,
+ 0.44999999999999996,
+ 0.45749999999999996,
+ 0.46499999999999997,
+ 0.4725,
+ 0.48,
+ 0.4875,
+ 0.495,
+ 0.5025,
+ 0.51,
+ 0.5175,
+ 0.525,
+ 0.5325,
+ 0.54,
+ 0.5475,
+ 0.5549999999999999,
+ 0.5625,
+ 0.57,
+ 0.5775,
+ 0.585,
+ 0.5925,
+ 0.6,
+ 0.6074999999999999,
+ 0.615,
+ 0.6224999999999999,
+ 0.63,
+ 0.6375,
+ 0.645,
+ 0.6525,
+ 0.6599999999999999,
+ 0.6675,
+ 0.6749999999999999,
+ 0.6825,
+ 0.69,
+ 0.6975,
+ 0.705,
+ 0.7125,
+ 0.72,
+ 0.7274999999999999,
+ 0.735,
+ 0.7424999999999999,
+ 0.75,
+ 0.7575,
+ 0.765,
+ 0.7725,
+ 0.78,
+ 0.7875,
+ 0.7949999999999999,
+ 0.8025,
+ 0.8099999999999999,
+ 0.8175,
+ 0.825,
+ 0.8325,
+ 0.84,
+ 0.8474999999999999,
+ 0.855,
+ 0.8624999999999999,
+ 0.87,
+ 0.8775,
+ 0.885,
+ 0.8925,
+ 0.8999999999999999,
+ 0.9075,
+ 0.9149999999999999,
+ 0.9225,
+ 0.9299999999999999,
+ 0.9375,
+ 0.945,
+ 0.9525,
+ 0.96,
+ 0.9674999999999999,
+ 0.975,
+ 0.9824999999999999,
+ 0.99,
+ 0.9974999999999999,
+ 1.005,
+ 1.0125,
+ 1.02,
+ 1.0274999999999999,
+ 1.035,
+ 1.0425,
+ 1.05,
+ 1.0574999999999999,
+ 1.065,
+ 1.0725,
+ 1.08,
+ 1.0875,
+ 1.095,
+ 1.1025,
+ 1.1099999999999999,
+ 1.1175,
+ 1.125,
+ 1.1325,
+ 1.14,
+ 1.1475,
+ 1.155,
+ 1.1624999999999999,
+ 1.17,
+ 1.1775,
+ 1.185,
+ 1.1925,
+ 1.2,
+ 1.2075,
+ 1.2149999999999999,
+ 1.2225,
+ 1.23,
+ 1.2375,
+ 1.2449999999999999,
+ 1.2525,
+ 1.26,
+ 1.2674999999999998,
+ 1.275,
+ 1.2825,
+ 1.29,
+ 1.2974999999999999,
+ 1.305,
+ 1.3125,
+ 1.3199999999999998,
+ 1.3275,
+ 1.335,
+ 1.3425,
+ 1.3499999999999999,
+ 1.3575,
+ 1.365,
+ 1.3725,
+ 1.38,
+ 1.3875,
+ 1.395,
+ 1.4024999999999999,
+ 1.41,
+ 1.4175,
+ 1.425,
+ 1.4324999999999999,
+ 1.44,
+ 1.4475,
+ 1.4549999999999998,
+ 1.4625,
+ 1.47,
+ 1.4775,
+ 1.4849999999999999,
+ 1.4925,
+ 1.5,
+ 1.5074999999999998,
+ 1.515,
+ 1.5225,
+ 1.53,
+ 1.5374999999999999,
+ 1.545,
+ 1.5525,
+ 1.56,
+ 1.5675,
+ 1.575,
+ 1.5825,
+ 1.5899999999999999,
+ 1.5975,
+ 1.605,
+ 1.6125,
+ 1.6199999999999999,
+ 1.6275,
+ 1.635,
+ 1.6424999999999998,
+ 1.65,
+ 1.6575,
+ 1.665,
+ 1.6724999999999999,
+ 1.68,
+ 1.6875,
+ 1.6949999999999998,
+ 1.7025,
+ 1.71,
+ 1.7175,
+ 1.7249999999999999,
+ 1.7325,
+ 1.74,
+ 1.7474999999999998,
+ 1.755,
+ 1.7625,
+ 1.77,
+ 1.7774999999999999,
+ 1.785,
+ 1.7925,
+ 1.7999999999999998,
+ 1.8074999999999999,
+ 1.815,
+ 1.8225,
+ 1.8299999999999998,
+ 1.8375,
+ 1.845,
+ 1.8525,
+ 1.8599999999999999,
+ 1.8675,
+ 1.875,
+ 1.8824999999999998,
+ 1.89,
+ 1.8975,
+ 1.905,
+ 1.9124999999999999,
+ 1.92,
+ 1.9275,
+ 1.9349999999999998,
+ 1.9425,
+ 1.95,
+ 1.9575,
+ 1.9649999999999999,
+ 1.9725,
+ 1.98,
+ 1.9874999999999998,
+ 1.9949999999999999,
+ 2.0025,
+ 2.01,
+ 2.0175,
+ 2.025,
+ 2.0324999999999998,
+ 2.04,
+ 2.0475,
+ 2.0549999999999997,
+ 2.0625,
+ 2.07,
+ 2.0775,
+ 2.085,
+ 2.0925,
+ 2.1,
+ 2.1075,
+ 2.1149999999999998,
+ 2.1225,
+ 2.13,
+ 2.1374999999999997,
+ 2.145,
+ 2.1525,
+ 2.16,
+ 2.1675,
+ 2.175,
+ 2.1825,
+ 2.19,
+ 2.1975,
+ 2.205,
+ 2.2125,
+ 2.2199999999999998,
+ 2.2275,
+ 2.235,
+ 2.2424999999999997,
+ 2.25,
+ 2.2575,
+ 2.265,
+ 2.2725,
+ 2.28,
+ 2.2875,
+ 2.295,
+ 2.3024999999999998,
+ 2.31,
+ 2.3175,
+ 2.3249999999999997,
+ 2.3325,
+ 2.34,
+ 2.3474999999999997,
+ 2.355,
+ 2.3625,
+ 2.37,
+ 2.3775,
+ 2.385,
+ 2.3925,
+ 2.4,
+ 2.4074999999999998,
+ 2.415,
+ 2.4225,
+ 2.4299999999999997,
+ 2.4375,
+ 2.445,
+ 2.4525,
+ 2.46,
+ 2.4675,
+ 2.475,
+ 2.4825,
+ 2.4899999999999998,
+ 2.4975,
+ 2.505,
+ 2.5124999999999997,
+ 2.52,
+ 2.5275,
+ 2.5349999999999997,
+ 2.5425,
+ 2.55,
+ 2.5575,
+ 2.565,
+ 2.5725,
+ 2.58,
+ 2.5875,
+ 2.5949999999999998,
+ 2.6025,
+ 2.61,
+ 2.6174999999999997,
+ 2.625,
+ 2.6325,
+ 2.6399999999999997,
+ 2.6475,
+ 2.655,
+ 2.6625,
+ 2.67,
+ 2.6774999999999998,
+ 2.685,
+ 2.6925,
+ 2.6999999999999997,
+ 2.7075,
+ 2.715,
+ 2.7224999999999997,
+ 2.73,
+ 2.7375,
+ 2.745,
+ 2.7525,
+ 2.76,
+ 2.7675,
+ 2.775,
+ 2.7824999999999998,
+ 2.79,
+ 2.7975,
+ 2.8049999999999997,
+ 2.8125,
+ 2.82,
+ 2.8274999999999997,
+ 2.835,
+ 2.8425,
+ 2.85,
+ 2.8575,
+ 2.8649999999999998,
+ 2.8725,
+ 2.88,
+ 2.8874999999999997,
+ 2.895,
+ 2.9025,
+ 2.9099999999999997,
+ 2.9175,
+ 2.925,
+ 2.9325,
+ 2.94,
+ 2.9475,
+ 2.955,
+ 2.9625,
+ 2.9699999999999998,
+ 2.9775,
+ 2.985,
+ 2.9924999999999997,
+ 3.0
+ ],
+ "method": "uniform_tempo_single_spin_runtime_validation",
+ "model": {
+ "counterterm": false,
+ "counterterm_strength": 0.0,
+ "drive_amplitude": 0.2,
+ "drive_frequency": 1.0,
+ "j": 0.0,
+ "n": 1,
+ "normalization": "bounded",
+ "omega": 1.0
+ },
+ "phase_state": {
+ "imag": [
+ [
+ 8.178808486123777e-05,
+ 0.3214524432432307
+ ],
+ [
+ -0.3215171909840441,
+ -8.178808486123777e-05
+ ]
+ ],
+ "real": [
+ [
+ 0.6387540788942603,
+ -0.17669544164632084
+ ],
+ [
+ -0.1767535416258371,
+ 0.3612459211057398
+ ]
+ ]
+ },
+ "uniform_tempo_revision": "b76a018c32e5415989761d902b1b0e95f1a337da"
+}
\ No newline at end of file