scikit-complexity 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scikit_complexity-0.2.0.dist-info/METADATA +317 -0
- scikit_complexity-0.2.0.dist-info/RECORD +1748 -0
- scikit_complexity-0.2.0.dist-info/WHEEL +4 -0
- scikit_complexity-0.2.0.dist-info/entry_points.txt +4 -0
- scikit_complexity-0.2.0.dist-info/licenses/LICENSE +21 -0
- skcomplex/__init__.py +1 -0
- skcomplex/analysis/__init__.py +101 -0
- skcomplex/analysis/_alignment.py +263 -0
- skcomplex/analysis/_automata.py +658 -0
- skcomplex/analysis/_base.py +841 -0
- skcomplex/analysis/_clusters.py +298 -0
- skcomplex/analysis/_coarse_grain.py +183 -0
- skcomplex/analysis/_collapse.py +318 -0
- skcomplex/analysis/_complexity.py +129 -0
- skcomplex/analysis/_computational_mechanics.py +220 -0
- skcomplex/analysis/_correlation.py +364 -0
- skcomplex/analysis/_defects.py +111 -0
- skcomplex/analysis/_discovery.py +101 -0
- skcomplex/analysis/_displacement.py +135 -0
- skcomplex/analysis/_distribution.py +327 -0
- skcomplex/analysis/_domains.py +220 -0
- skcomplex/analysis/_embedding.py +235 -0
- skcomplex/analysis/_emergence.py +503 -0
- skcomplex/analysis/_entropy.py +425 -0
- skcomplex/analysis/_ergodicity.py +228 -0
- skcomplex/analysis/_events.py +301 -0
- skcomplex/analysis/_fit.py +368 -0
- skcomplex/analysis/_groups.py +205 -0
- skcomplex/analysis/_information.py +488 -0
- skcomplex/analysis/_invariants.py +409 -0
- skcomplex/analysis/_irreversibility.py +421 -0
- skcomplex/analysis/_kramers_moyal.py +104 -0
- skcomplex/analysis/_large_deviations.py +378 -0
- skcomplex/analysis/_linearization.py +231 -0
- skcomplex/analysis/_local_information.py +166 -0
- skcomplex/analysis/_loops.py +394 -0
- skcomplex/analysis/_lyapunov.py +342 -0
- skcomplex/analysis/_markov.py +303 -0
- skcomplex/analysis/_mode_decomposition.py +209 -0
- skcomplex/analysis/_motifs.py +239 -0
- skcomplex/analysis/_neighbors.py +303 -0
- skcomplex/analysis/_networks.py +286 -0
- skcomplex/analysis/_operator.py +312 -0
- skcomplex/analysis/_partial_information.py +118 -0
- skcomplex/analysis/_passage.py +244 -0
- skcomplex/analysis/_recurrence.py +202 -0
- skcomplex/analysis/_reservoirs.py +387 -0
- skcomplex/analysis/_rolling.py +168 -0
- skcomplex/analysis/_scaling.py +370 -0
- skcomplex/analysis/_sections.py +225 -0
- skcomplex/analysis/_signatures.py +250 -0
- skcomplex/analysis/_sparse_identification.py +398 -0
- skcomplex/analysis/_spectrum.py +164 -0
- skcomplex/analysis/_stability.py +547 -0
- skcomplex/analysis/_surrogates.py +127 -0
- skcomplex/analysis/_symbolic.py +639 -0
- skcomplex/analysis/types.py +43 -0
- skcomplex/base.py +159 -0
- skcomplex/core/__init__.py +1 -0
- skcomplex/core/base.py +150 -0
- skcomplex/core/elements/__init__.py +21 -0
- skcomplex/core/elements/_base.py +84 -0
- skcomplex/core/elements/_compartment.py +52 -0
- skcomplex/core/elements/_density.py +52 -0
- skcomplex/core/elements/_element.py +80 -0
- skcomplex/core/elements/_field.py +192 -0
- skcomplex/core/elements/_group.py +241 -0
- skcomplex/core/elements/_lattice.py +115 -0
- skcomplex/core/elements/_point.py +66 -0
- skcomplex/core/interactions/__init__.py +89 -0
- skcomplex/core/interactions/_advection.py +134 -0
- skcomplex/core/interactions/_base.py +361 -0
- skcomplex/core/interactions/_cascade.py +195 -0
- skcomplex/core/interactions/_choice.py +320 -0
- skcomplex/core/interactions/_conservation.py +164 -0
- skcomplex/core/interactions/_coupling.py +741 -0
- skcomplex/core/interactions/_crossing.py +136 -0
- skcomplex/core/interactions/_diffusion.py +99 -0
- skcomplex/core/interactions/_encounter.py +201 -0
- skcomplex/core/interactions/_euler_lagrange.py +183 -0
- skcomplex/core/interactions/_evolution.py +520 -0
- skcomplex/core/interactions/_feedback.py +79 -0
- skcomplex/core/interactions/_gradient.py +293 -0
- skcomplex/core/interactions/_grouping.py +399 -0
- skcomplex/core/interactions/_hamiltonian.py +191 -0
- skcomplex/core/interactions/_hyperedge.py +96 -0
- skcomplex/core/interactions/_imitation.py +357 -0
- skcomplex/core/interactions/_impulse.py +133 -0
- skcomplex/core/interactions/_interaction.py +58 -0
- skcomplex/core/interactions/_jump.py +201 -0
- skcomplex/core/interactions/_life_cycle.py +424 -0
- skcomplex/core/interactions/_local_rule.py +134 -0
- skcomplex/core/interactions/_map.py +239 -0
- skcomplex/core/interactions/_matching.py +701 -0
- skcomplex/core/interactions/_movement.py +377 -0
- skcomplex/core/interactions/_neighbor.py +88 -0
- skcomplex/core/interactions/_optimization.py +206 -0
- skcomplex/core/interactions/_pair.py +82 -0
- skcomplex/core/interactions/_pair_coupling.py +169 -0
- skcomplex/core/interactions/_rate.py +240 -0
- skcomplex/core/interactions/_reaction.py +466 -0
- skcomplex/core/interactions/_reinforcement.py +226 -0
- skcomplex/core/interactions/_relaxation.py +103 -0
- skcomplex/core/interactions/_sampling.py +177 -0
- skcomplex/core/interactions/_satisfiability.py +145 -0
- skcomplex/core/interactions/_sign_adjustment.py +222 -0
- skcomplex/core/interactions/_topology.py +215 -0
- skcomplex/core/interactions/_training.py +184 -0
- skcomplex/core/interactions/_transfer.py +669 -0
- skcomplex/core/interactions/_transition.py +427 -0
- skcomplex/core/laws/__init__.py +60 -0
- skcomplex/core/laws/_base.py +194 -0
- skcomplex/core/laws/_bilinear.py +91 -0
- skcomplex/core/laws/_boundary.py +59 -0
- skcomplex/core/laws/_cascade.py +79 -0
- skcomplex/core/laws/_crossing.py +87 -0
- skcomplex/core/laws/_dissipator.py +79 -0
- skcomplex/core/laws/_drive.py +56 -0
- skcomplex/core/laws/_emission.py +81 -0
- skcomplex/core/laws/_encounter.py +96 -0
- skcomplex/core/laws/_equation.py +105 -0
- skcomplex/core/laws/_extremal.py +94 -0
- skcomplex/core/laws/_flux.py +108 -0
- skcomplex/core/laws/_fractional_noise.py +65 -0
- skcomplex/core/laws/_generator.py +66 -0
- skcomplex/core/laws/_gradient_step.py +89 -0
- skcomplex/core/laws/_jump.py +137 -0
- skcomplex/core/laws/_local_rule.py +92 -0
- skcomplex/core/laws/_match.py +321 -0
- skcomplex/core/laws/_noise.py +125 -0
- skcomplex/core/laws/_rate.py +82 -0
- skcomplex/core/laws/_rule.py +82 -0
- skcomplex/core/laws/_sample.py +65 -0
- skcomplex/core/laws/_transfer.py +165 -0
- skcomplex/core/laws/_transition.py +77 -0
- skcomplex/core/laws/_update.py +121 -0
- skcomplex/core/laws/utils/__init__.py +142 -0
- skcomplex/core/laws/utils/_agents.py +127 -0
- skcomplex/core/laws/utils/_components.py +63 -0
- skcomplex/core/laws/utils/_conditions.py +198 -0
- skcomplex/core/laws/utils/_contractions.py +74 -0
- skcomplex/core/laws/utils/_delays.py +170 -0
- skcomplex/core/laws/utils/_history.py +167 -0
- skcomplex/core/laws/utils/_local_operators.py +68 -0
- skcomplex/core/laws/utils/_lookups.py +40 -0
- skcomplex/core/laws/utils/_moments.py +122 -0
- skcomplex/core/laws/utils/_operators.py +237 -0
- skcomplex/core/laws/utils/_phase.py +126 -0
- skcomplex/core/laws/utils/_pointwise.py +160 -0
- skcomplex/core/laws/utils/_reductions.py +942 -0
- skcomplex/core/laws/utils/_signals.py +214 -0
- skcomplex/core/laws/utils/_tables.py +4 -0
- skcomplex/core/laws/utils/_tensors.py +235 -0
- skcomplex/core/spaces/__init__.py +52 -0
- skcomplex/core/spaces/_adjacency.py +34 -0
- skcomplex/core/spaces/_base.py +218 -0
- skcomplex/core/spaces/_box.py +41 -0
- skcomplex/core/spaces/_cayley.py +352 -0
- skcomplex/core/spaces/_cone.py +65 -0
- skcomplex/core/spaces/_continuous.py +93 -0
- skcomplex/core/spaces/_continuous_time.py +27 -0
- skcomplex/core/spaces/_discrete_time.py +53 -0
- skcomplex/core/spaces/_generator.py +51 -0
- skcomplex/core/spaces/_lattice.py +194 -0
- skcomplex/core/spaces/_lattice_neighborhood.py +50 -0
- skcomplex/core/spaces/_memory.py +45 -0
- skcomplex/core/spaces/_mesh.py +71 -0
- skcomplex/core/spaces/_moore.py +49 -0
- skcomplex/core/spaces/_nearest.py +41 -0
- skcomplex/core/spaces/_network.py +256 -0
- skcomplex/core/spaces/_phase.py +136 -0
- skcomplex/core/spaces/_radius.py +40 -0
- skcomplex/core/spaces/_static_time.py +34 -0
- skcomplex/core/spaces/_triangular.py +37 -0
- skcomplex/core/spaces/_von_neumann.py +51 -0
- skcomplex/core/specs/__init__.py +25 -0
- skcomplex/core/specs/_census_record_spec.py +72 -0
- skcomplex/core/specs/_census_spec.py +40 -0
- skcomplex/core/specs/_compiled_agents_spec.py +62 -0
- skcomplex/core/specs/_compiled_element_spec.py +59 -0
- skcomplex/core/specs/_compiled_interaction_spec.py +33 -0
- skcomplex/core/specs/_lattice_context_spec.py +40 -0
- skcomplex/core/specs/_lattice_state_spec.py +49 -0
- skcomplex/core/specs/_node_spec.py +64 -0
- skcomplex/core/specs/_operator_view_spec.py +135 -0
- skcomplex/core/specs/_scenario_spec.py +45 -0
- skcomplex/core/specs/_subsystem_spec.py +24 -0
- skcomplex/core/system.py +140 -0
- skcomplex/core/types.py +249 -0
- skcomplex/engine/__init__.py +5 -0
- skcomplex/engine/_utils.py +278 -0
- skcomplex/engine/backends/__init__.py +13 -0
- skcomplex/engine/backends/_base.py +329 -0
- skcomplex/engine/backends/_jax.py +285 -0
- skcomplex/engine/backends/_numba.py +601 -0
- skcomplex/engine/backends/_numba_components.py +67 -0
- skcomplex/engine/backends/_numba_loops.py +163 -0
- skcomplex/engine/backends/_numba_neighbours.py +435 -0
- skcomplex/engine/backends/_numba_printer.py +1023 -0
- skcomplex/engine/backends/_numba_stencils.py +66 -0
- skcomplex/engine/backends/_numpy.py +215 -0
- skcomplex/engine/compile/__init__.py +27 -0
- skcomplex/engine/compile/_base.py +582 -0
- skcomplex/engine/compile/_bound_renewal_spec.py +47 -0
- skcomplex/engine/compile/_compilation.py +351 -0
- skcomplex/engine/compile/_compile.py +100 -0
- skcomplex/engine/compile/_complex.py +216 -0
- skcomplex/engine/compile/_draw_lowering.py +373 -0
- skcomplex/engine/compile/_field_lowering.py +1668 -0
- skcomplex/engine/compile/_flows.py +691 -0
- skcomplex/engine/compile/_forms.py +48 -0
- skcomplex/engine/compile/_laws.py +42 -0
- skcomplex/engine/compile/_learning_compiler.py +481 -0
- skcomplex/engine/compile/_member_reductions.py +206 -0
- skcomplex/engine/compile/_members.py +244 -0
- skcomplex/engine/compile/_observables.py +940 -0
- skcomplex/engine/compile/_observer.py +185 -0
- skcomplex/engine/compile/_pass_compiler.py +1534 -0
- skcomplex/engine/compile/_probe.py +78 -0
- skcomplex/engine/compile/_renewal_law.py +70 -0
- skcomplex/engine/compile/passes/__init__.py +34 -0
- skcomplex/engine/compile/passes/_agents.py +111 -0
- skcomplex/engine/compile/passes/_agents_problem.py +143 -0
- skcomplex/engine/compile/passes/_census.py +808 -0
- skcomplex/engine/compile/passes/_check_fractional_noise.py +107 -0
- skcomplex/engine/compile/passes/_collect.py +31 -0
- skcomplex/engine/compile/passes/_compile_encounters.py +301 -0
- skcomplex/engine/compile/passes/_complex.py +198 -0
- skcomplex/engine/compile/passes/_conserved_noise.py +224 -0
- skcomplex/engine/compile/passes/_core.py +116 -0
- skcomplex/engine/compile/passes/_declare_renewals.py +84 -0
- skcomplex/engine/compile/passes/_draws.py +29 -0
- skcomplex/engine/compile/passes/_encounter_functions.py +60 -0
- skcomplex/engine/compile/passes/_encounter_jacobian.py +25 -0
- skcomplex/engine/compile/passes/_encounter_problem.py +32 -0
- skcomplex/engine/compile/passes/_events.py +204 -0
- skcomplex/engine/compile/passes/_expand_flows.py +32 -0
- skcomplex/engine/compile/passes/_field_functions.py +647 -0
- skcomplex/engine/compile/passes/_field_jacobian.py +38 -0
- skcomplex/engine/compile/passes/_field_problem.py +106 -0
- skcomplex/engine/compile/passes/_flatten.py +339 -0
- skcomplex/engine/compile/passes/_flows_problem.py +29 -0
- skcomplex/engine/compile/passes/_form.py +82 -0
- skcomplex/engine/compile/passes/_fractional_form.py +172 -0
- skcomplex/engine/compile/passes/_fractional_problem.py +91 -0
- skcomplex/engine/compile/passes/_functions.py +485 -0
- skcomplex/engine/compile/passes/_hilbert_space_error.py +10 -0
- skcomplex/engine/compile/passes/_hyperedges.py +598 -0
- skcomplex/engine/compile/passes/_jacobian.py +38 -0
- skcomplex/engine/compile/passes/_kernels.py +407 -0
- skcomplex/engine/compile/passes/_lattices.py +818 -0
- skcomplex/engine/compile/passes/_layout.py +667 -0
- skcomplex/engine/compile/passes/_lower_fields.py +225 -0
- skcomplex/engine/compile/passes/_lower_flows.py +28 -0
- skcomplex/engine/compile/passes/_markov.py +329 -0
- skcomplex/engine/compile/passes/_mask_requests.py +121 -0
- skcomplex/engine/compile/passes/_members.py +30 -0
- skcomplex/engine/compile/passes/_noise.py +196 -0
- skcomplex/engine/compile/passes/_operator_compiler.py +843 -0
- skcomplex/engine/compile/passes/_orders.py +409 -0
- skcomplex/engine/compile/passes/_owners.py +90 -0
- skcomplex/engine/compile/passes/_particles.py +69 -0
- skcomplex/engine/compile/passes/_plan.py +130 -0
- skcomplex/engine/compile/passes/_problem.py +802 -0
- skcomplex/engine/compile/passes/_reduction_lowering.py +1193 -0
- skcomplex/engine/compile/passes/_reductions.py +84 -0
- skcomplex/engine/compile/passes/_renewal_problem.py +357 -0
- skcomplex/engine/compile/passes/_request_jumps.py +51 -0
- skcomplex/engine/compile/passes/_residences.py +140 -0
- skcomplex/engine/compile/passes/_rows.py +162 -0
- skcomplex/engine/compile/passes/_set_renewals_apart.py +29 -0
- skcomplex/engine/compile/passes/_set_rules_apart.py +28 -0
- skcomplex/engine/compile/passes/_specs.py +1317 -0
- skcomplex/engine/compile/passes/_split_requests.py +44 -0
- skcomplex/engine/compile/passes/_topology_functions.py +265 -0
- skcomplex/engine/compile/passes/_topology_problem.py +27 -0
- skcomplex/engine/compile/passes/_towards.py +66 -0
- skcomplex/engine/compile/passes/_unpack_matches.py +29 -0
- skcomplex/engine/compile/passes/_unpack_renewals.py +41 -0
- skcomplex/engine/problems/__init__.py +61 -0
- skcomplex/engine/problems/_base.py +150 -0
- skcomplex/engine/problems/_base_problem_spec.py +153 -0
- skcomplex/engine/problems/_block_spec.py +48 -0
- skcomplex/engine/problems/_born_spec.py +24 -0
- skcomplex/engine/problems/_cascade_kernel.py +134 -0
- skcomplex/engine/problems/_collision_kernel.py +147 -0
- skcomplex/engine/problems/_compiled_delay_spec.py +21 -0
- skcomplex/engine/problems/_compiled_request_spec.py +46 -0
- skcomplex/engine/problems/_control_problem_spec.py +90 -0
- skcomplex/engine/problems/_declarations_spec.py +126 -0
- skcomplex/engine/problems/_delayed_state_spec.py +50 -0
- skcomplex/engine/problems/_diffusive_limit_spec.py +50 -0
- skcomplex/engine/problems/_draw_kernel.py +128 -0
- skcomplex/engine/problems/_drive_kernel.py +65 -0
- skcomplex/engine/problems/_dynamics_spec.py +28 -0
- skcomplex/engine/problems/_edge_row_search.py +78 -0
- skcomplex/engine/problems/_edge_search.py +64 -0
- skcomplex/engine/problems/_encounter_kernel.py +200 -0
- skcomplex/engine/problems/_event_kernel.py +70 -0
- skcomplex/engine/problems/_expression_printer.py +410 -0
- skcomplex/engine/problems/_extremal_kernel.py +125 -0
- skcomplex/engine/problems/_field_operator_kernel.py +105 -0
- skcomplex/engine/problems/_finite_volume_kernel.py +423 -0
- skcomplex/engine/problems/_flow_term_spec.py +45 -0
- skcomplex/engine/problems/_frame_spec.py +105 -0
- skcomplex/engine/problems/_jacobian_kernel.py +575 -0
- skcomplex/engine/problems/_kernel_spec.py +130 -0
- skcomplex/engine/problems/_kinetic_problem_spec.py +23 -0
- skcomplex/engine/problems/_law_kernel.py +604 -0
- skcomplex/engine/problems/_learning_problem_spec.py +67 -0
- skcomplex/engine/problems/_linear_term_spec.py +50 -0
- skcomplex/engine/problems/_loop_term_spec.py +44 -0
- skcomplex/engine/problems/_lowered_kernels_spec.py +59 -0
- skcomplex/engine/problems/_markov_kernel.py +68 -0
- skcomplex/engine/problems/_metric_search.py +155 -0
- skcomplex/engine/problems/_monte_carlo_kernel.py +213 -0
- skcomplex/engine/problems/_neighborhood_kernel.py +594 -0
- skcomplex/engine/problems/_noise_term_spec.py +26 -0
- skcomplex/engine/problems/_observed_spec.py +22 -0
- skcomplex/engine/problems/_operator_kernel.py +102 -0
- skcomplex/engine/problems/_operator_lowering.py +323 -0
- skcomplex/engine/problems/_operator_problem_spec.py +138 -0
- skcomplex/engine/problems/_output_spec.py +78 -0
- skcomplex/engine/problems/_pair_search.py +86 -0
- skcomplex/engine/problems/_partials_spec.py +27 -0
- skcomplex/engine/problems/_partition_spec.py +39 -0
- skcomplex/engine/problems/_printed_spec.py +24 -0
- skcomplex/engine/problems/_problem_functions_spec.py +102 -0
- skcomplex/engine/problems/_problem_spec.py +365 -0
- skcomplex/engine/problems/_random_stream.py +49 -0
- skcomplex/engine/problems/_record_spec.py +22 -0
- skcomplex/engine/problems/_recorded_spec.py +21 -0
- skcomplex/engine/problems/_reduction_kernel.py +254 -0
- skcomplex/engine/problems/_reduction_schedule_spec.py +97 -0
- skcomplex/engine/problems/_reference_spec.py +114 -0
- skcomplex/engine/problems/_relation_spec.py +29 -0
- skcomplex/engine/problems/_renewal_kernel.py +250 -0
- skcomplex/engine/problems/_request_spec.py +27 -0
- skcomplex/engine/problems/_rule_kernel.py +227 -0
- skcomplex/engine/problems/_set_symbol_spec.py +28 -0
- skcomplex/engine/problems/_source_loader.py +113 -0
- skcomplex/engine/problems/_static_search.py +42 -0
- skcomplex/engine/problems/_steps.py +39 -0
- skcomplex/engine/problems/_sweep_spec.py +26 -0
- skcomplex/engine/problems/_symmetry_spec.py +29 -0
- skcomplex/engine/problems/_too_dense.py +8 -0
- skcomplex/engine/problems/_topology_kernel.py +589 -0
- skcomplex/engine/problems/_transfer_network.py +4 -0
- skcomplex/engine/problems/_transfer_network_spec.py +50 -0
- skcomplex/engine/problems/_transfer_state_spec.py +68 -0
- skcomplex/engine/runtime/__init__.py +22 -0
- skcomplex/engine/runtime/_as_fast_as_possible.py +17 -0
- skcomplex/engine/runtime/_base.py +137 -0
- skcomplex/engine/runtime/_conservation.py +125 -0
- skcomplex/engine/runtime/_invariants.py +100 -0
- skcomplex/engine/runtime/_real_time.py +55 -0
- skcomplex/engine/runtime/_recorder.py +84 -0
- skcomplex/engine/runtime/_simulations.py +665 -0
- skcomplex/engine/runtime/_trajectories.py +314 -0
- skcomplex/engine/solvers/__init__.py +95 -0
- skcomplex/engine/solvers/_base.py +372 -0
- skcomplex/engine/solvers/_caputo.py +194 -0
- skcomplex/engine/solvers/_collocation.py +334 -0
- skcomplex/engine/solvers/_convolution.py +155 -0
- skcomplex/engine/solvers/_cosimulation.py +400 -0
- skcomplex/engine/solvers/_crank_nicolson.py +32 -0
- skcomplex/engine/solvers/_defaults.py +34 -0
- skcomplex/engine/solvers/_etdrk4.py +86 -0
- skcomplex/engine/solvers/_euler_maruyama.py +161 -0
- skcomplex/engine/solvers/_event_locator.py +249 -0
- skcomplex/engine/solvers/_external.py +94 -0
- skcomplex/engine/solvers/_fractional_abm.py +126 -0
- skcomplex/engine/solvers/_fractional_euler_maruyama.py +322 -0
- skcomplex/engine/solvers/_gillespie.py +135 -0
- skcomplex/engine/solvers/_gradient_descent.py +353 -0
- skcomplex/engine/solvers/_grunwald_letnikov.py +83 -0
- skcomplex/engine/solvers/_heun.py +89 -0
- skcomplex/engine/solvers/_history.py +184 -0
- skcomplex/engine/solvers/_horizon_error.py +10 -0
- skcomplex/engine/solvers/_imex2.py +40 -0
- skcomplex/engine/solvers/_imex_euler.py +35 -0
- skcomplex/engine/solvers/_jump_trajectories.py +98 -0
- skcomplex/engine/solvers/_kinetics.py +242 -0
- skcomplex/engine/solvers/_l1.py +91 -0
- skcomplex/engine/solvers/_lammps.py +745 -0
- skcomplex/engine/solvers/_lammps_fix_spec.py +41 -0
- skcomplex/engine/solvers/_lattice.py +79 -0
- skcomplex/engine/solvers/_lindblad.py +70 -0
- skcomplex/engine/solvers/_maps.py +105 -0
- skcomplex/engine/solvers/_mesa.py +1624 -0
- skcomplex/engine/solvers/_milstein.py +93 -0
- skcomplex/engine/solvers/_monte_carlo.py +43 -0
- skcomplex/engine/solvers/_operator.py +212 -0
- skcomplex/engine/solvers/_optimal_control.py +368 -0
- skcomplex/engine/solvers/_pontryagin.py +298 -0
- skcomplex/engine/solvers/_renewal.py +90 -0
- skcomplex/engine/solvers/_renewals.py +190 -0
- skcomplex/engine/solvers/_rk4.py +263 -0
- skcomplex/engine/solvers/_root.py +176 -0
- skcomplex/engine/solvers/_rows.py +49 -0
- skcomplex/engine/solvers/_scipy_ode.py +602 -0
- skcomplex/engine/solvers/_sde.py +164 -0
- skcomplex/engine/solvers/_semi_lagrangian.py +213 -0
- skcomplex/engine/solvers/_solver.py +159 -0
- skcomplex/engine/solvers/_split.py +394 -0
- skcomplex/engine/solvers/_ssprk.py +147 -0
- skcomplex/engine/solvers/_strang_splitting.py +178 -0
- skcomplex/engine/solvers/_unitary.py +68 -0
- skcomplex/engine/solvers/_velocity_verlet.py +171 -0
- skcomplex/engine/solvers/_yoshida4.py +242 -0
- skcomplex/engine/types.py +90 -0
- skcomplex/engine/viz/__init__.py +35 -0
- skcomplex/engine/viz/_agents.py +223 -0
- skcomplex/engine/viz/_axes.py +146 -0
- skcomplex/engine/viz/_base.py +365 -0
- skcomplex/engine/viz/_bodies.py +334 -0
- skcomplex/engine/viz/_cayley.py +133 -0
- skcomplex/engine/viz/_expectation.py +208 -0
- skcomplex/engine/viz/_histograms.py +218 -0
- skcomplex/engine/viz/_images.py +307 -0
- skcomplex/engine/viz/_matrices.py +141 -0
- skcomplex/engine/viz/_meshes.py +149 -0
- skcomplex/engine/viz/_points.py +238 -0
- skcomplex/engine/viz/_rerun.py +527 -0
- skcomplex/engine/viz/_rings.py +127 -0
- skcomplex/engine/viz/_scalars.py +129 -0
- skcomplex/engine/viz/_sites.py +228 -0
- skcomplex/errors.py +112 -0
- skcomplex/experiments/__init__.py +36 -0
- skcomplex/experiments/_base.py +373 -0
- skcomplex/experiments/_basin_stability.py +153 -0
- skcomplex/experiments/_calibration.py +194 -0
- skcomplex/experiments/_experiment.py +327 -0
- skcomplex/experiments/_grid.py +36 -0
- skcomplex/experiments/_latin_hypercube.py +44 -0
- skcomplex/experiments/_morris.py +50 -0
- skcomplex/experiments/_one_at_a_time.py +28 -0
- skcomplex/experiments/_orbit_diagram.py +146 -0
- skcomplex/experiments/_random.py +44 -0
- skcomplex/experiments/_results.py +148 -0
- skcomplex/experiments/_rows.py +45 -0
- skcomplex/experiments/_saltelli.py +50 -0
- skcomplex/experiments/_sensitivity.py +122 -0
- skcomplex/experiments/_sobol.py +43 -0
- skcomplex/experiments/specs/__init__.py +1 -0
- skcomplex/experiments/specs/_task_spec.py +78 -0
- skcomplex/experiments/types.py +14 -0
- skcomplex/models/__init__.py +18 -0
- skcomplex/models/_catalog.py +243 -0
- skcomplex/models/_model_catalog.py +270 -0
- skcomplex/models/_model_entry.py +170 -0
- skcomplex/models/_model_listing.py +38 -0
- skcomplex/models/biology/__init__.py +1 -0
- skcomplex/models/biology/collective_behaviour/__init__.py +48 -0
- skcomplex/models/biology/collective_behaviour/_alarm.py +99 -0
- skcomplex/models/biology/collective_behaviour/_ant.py +101 -0
- skcomplex/models/biology/collective_behaviour/_ant_view.py +24 -0
- skcomplex/models/biology/collective_behaviour/_boid.py +104 -0
- skcomplex/models/biology/collective_behaviour/_boid_view.py +25 -0
- skcomplex/models/biology/collective_behaviour/_branch.py +41 -0
- skcomplex/models/biology/collective_behaviour/_decisions.py +149 -0
- skcomplex/models/biology/collective_behaviour/_flight.py +52 -0
- skcomplex/models/biology/collective_behaviour/_flocking.py +75 -0
- skcomplex/models/biology/collective_behaviour/_flocks.py +169 -0
- skcomplex/models/biology/collective_behaviour/_foraging.py +232 -0
- skcomplex/models/biology/collective_behaviour/_ground.py +67 -0
- skcomplex/models/biology/collective_behaviour/_leadership.py +207 -0
- skcomplex/models/biology/collective_behaviour/_morse_potential.py +87 -0
- skcomplex/models/biology/collective_behaviour/_pheromone.py +55 -0
- skcomplex/models/biology/collective_behaviour/_rats.py +41 -0
- skcomplex/models/biology/collective_behaviour/_schooling.py +102 -0
- skcomplex/models/biology/collective_behaviour/_self_propulsion.py +64 -0
- skcomplex/models/biology/collective_behaviour/_shoal_member_view.py +25 -0
- skcomplex/models/biology/collective_behaviour/_swimming.py +66 -0
- skcomplex/models/biology/collective_behaviour/_trail_choice.py +105 -0
- skcomplex/models/biology/collective_behaviour/_trails.py +245 -0
- skcomplex/models/biology/collective_behaviour/_walker.py +97 -0
- skcomplex/models/biology/collective_behaviour/_walker_view.py +23 -0
- skcomplex/models/biology/common/__init__.py +3 -0
- skcomplex/models/biology/common/excitable/__init__.py +7 -0
- skcomplex/models/biology/common/excitable/_fitzhugh_nagumo.py +121 -0
- skcomplex/models/biology/common/kinetics/__init__.py +7 -0
- skcomplex/models/biology/common/kinetics/_michaelis_menten.py +137 -0
- skcomplex/models/biology/common/networks/__init__.py +9 -0
- skcomplex/models/biology/common/networks/_edge_draw.py +95 -0
- skcomplex/models/biology/common/networks/_weighted_edge.py +48 -0
- skcomplex/models/biology/common/pharmacokinetics/__init__.py +7 -0
- skcomplex/models/biology/common/pharmacokinetics/_dosing.py +125 -0
- skcomplex/models/biology/common/populations/__init__.py +19 -0
- skcomplex/models/biology/common/populations/_exponential_growth.py +66 -0
- skcomplex/models/biology/common/populations/_gompertz_growth.py +75 -0
- skcomplex/models/biology/common/populations/_growth.py +176 -0
- skcomplex/models/biology/common/populations/_logistic_growth.py +92 -0
- skcomplex/models/biology/common/populations/_mortality.py +69 -0
- skcomplex/models/biology/common/populations/_population.py +41 -0
- skcomplex/models/biology/common/populations/_power_law_growth.py +71 -0
- skcomplex/models/biology/common/stigmergy/__init__.py +7 -0
- skcomplex/models/biology/common/stigmergy/_evaporation.py +95 -0
- skcomplex/models/biology/ecology/__init__.py +128 -0
- skcomplex/models/biology/ecology/_abundance.py +52 -0
- skcomplex/models/biology/ecology/_agent_predation.py +170 -0
- skcomplex/models/biology/ecology/_cell_quota.py +163 -0
- skcomplex/models/biology/ecology/_clustering.py +96 -0
- skcomplex/models/biology/ecology/_communities.py +234 -0
- skcomplex/models/biology/ecology/_competition.py +95 -0
- skcomplex/models/biology/ecology/_cow.py +49 -0
- skcomplex/models/biology/ecology/_cow_view.py +15 -0
- skcomplex/models/biology/ecology/_emotion_marks.py +65 -0
- skcomplex/models/biology/ecology/_factories.py +322 -0
- skcomplex/models/biology/ecology/_forager.py +116 -0
- skcomplex/models/biology/ecology/_forager_view.py +25 -0
- skcomplex/models/biology/ecology/_fronts.py +128 -0
- skcomplex/models/biology/ecology/_generalized_lotka_volterra.py +66 -0
- skcomplex/models/biology/ecology/_grass.py +96 -0
- skcomplex/models/biology/ecology/_grass_view.py +17 -0
- skcomplex/models/biology/ecology/_grazing.py +66 -0
- skcomplex/models/biology/ecology/_habitat_patch.py +49 -0
- skcomplex/models/biology/ecology/_herding.py +84 -0
- skcomplex/models/biology/ecology/_higher_order.py +102 -0
- skcomplex/models/biology/ecology/_hopping.py +68 -0
- skcomplex/models/biology/ecology/_instability.py +180 -0
- skcomplex/models/biology/ecology/_linear_growth.py +70 -0
- skcomplex/models/biology/ecology/_meadow.py +102 -0
- skcomplex/models/biology/ecology/_microbe.py +47 -0
- skcomplex/models/biology/ecology/_microbial_communities.py +90 -0
- skcomplex/models/biology/ecology/_mutualism.py +81 -0
- skcomplex/models/biology/ecology/_neutral.py +144 -0
- skcomplex/models/biology/ecology/_neutral_replacement.py +54 -0
- skcomplex/models/biology/ecology/_organism.py +63 -0
- skcomplex/models/biology/ecology/_organism_view.py +15 -0
- skcomplex/models/biology/ecology/_parasitism.py +78 -0
- skcomplex/models/biology/ecology/_pasture.py +83 -0
- skcomplex/models/biology/ecology/_pasture_view.py +16 -0
- skcomplex/models/biology/ecology/_pioneer_growth.py +101 -0
- skcomplex/models/biology/ecology/_plant.py +56 -0
- skcomplex/models/biology/ecology/_plant_view.py +16 -0
- skcomplex/models/biology/ecology/_predation.py +290 -0
- skcomplex/models/biology/ecology/_predation_interaction.py +71 -0
- skcomplex/models/biology/ecology/_predator.py +63 -0
- skcomplex/models/biology/ecology/_predator_prey_events.py +120 -0
- skcomplex/models/biology/ecology/_predator_view.py +17 -0
- skcomplex/models/biology/ecology/_prey.py +52 -0
- skcomplex/models/biology/ecology/_prey_view.py +15 -0
- skcomplex/models/biology/ecology/_rosenzweig_macarthur.py +91 -0
- skcomplex/models/biology/ecology/_seasonal_logistic_growth.py +71 -0
- skcomplex/models/biology/ecology/_sequential.py +114 -0
- skcomplex/models/biology/ecology/_sheep.py +63 -0
- skcomplex/models/biology/ecology/_sheep_view.py +17 -0
- skcomplex/models/biology/ecology/_speciation.py +71 -0
- skcomplex/models/biology/ecology/_stand.py +47 -0
- skcomplex/models/biology/ecology/_stigmergic_predator.py +98 -0
- skcomplex/models/biology/ecology/_stigmergic_prey.py +54 -0
- skcomplex/models/biology/ecology/_stigmergy.py +413 -0
- skcomplex/models/biology/ecology/_succession.py +92 -0
- skcomplex/models/biology/ecology/_successional_growth.py +88 -0
- skcomplex/models/biology/ecology/_triplet.py +55 -0
- skcomplex/models/biology/ecology/_wolf.py +63 -0
- skcomplex/models/biology/ecology/_wolf_sheep.py +156 -0
- skcomplex/models/biology/ecology/_wolf_view.py +17 -0
- skcomplex/models/biology/epidemiology/__init__.py +53 -0
- skcomplex/models/biology/epidemiology/_active_host.py +61 -0
- skcomplex/models/biology/epidemiology/_adaptive.py +316 -0
- skcomplex/models/biology/epidemiology/_agents.py +484 -0
- skcomplex/models/biology/epidemiology/_carrier.py +66 -0
- skcomplex/models/biology/epidemiology/_degree_class.py +65 -0
- skcomplex/models/biology/epidemiology/_factories.py +186 -0
- skcomplex/models/biology/epidemiology/_host.py +49 -0
- skcomplex/models/biology/epidemiology/_immunity_loss.py +84 -0
- skcomplex/models/biology/epidemiology/_infection.py +93 -0
- skcomplex/models/biology/epidemiology/_networks.py +170 -0
- skcomplex/models/biology/epidemiology/_outbreaks.py +216 -0
- skcomplex/models/biology/epidemiology/_person.py +103 -0
- skcomplex/models/biology/epidemiology/_person_view.py +23 -0
- skcomplex/models/biology/epidemiology/_recovery.py +92 -0
- skcomplex/models/biology/epidemiology/_recurrent.py +149 -0
- skcomplex/models/biology/epidemiology/_spreading.py +144 -0
- skcomplex/models/biology/epidemiology/_subpopulation.py +92 -0
- skcomplex/models/biology/epidemiology/_traveller.py +65 -0
- skcomplex/models/biology/epidemiology/_traveller_view.py +17 -0
- skcomplex/models/biology/epidemiology/_vaccination.py +184 -0
- skcomplex/models/biology/epidemiology/_walker.py +66 -0
- skcomplex/models/biology/epidemiology/_walker_view.py +17 -0
- skcomplex/models/biology/evolution/__init__.py +60 -0
- skcomplex/models/biology/evolution/_adaptive_climbing.py +106 -0
- skcomplex/models/biology/evolution/_catalysis.py +76 -0
- skcomplex/models/biology/evolution/_catalytic_link.py +21 -0
- skcomplex/models/biology/evolution/_chemical.py +111 -0
- skcomplex/models/biology/evolution/_climber.py +125 -0
- skcomplex/models/biology/evolution/_climber_view.py +19 -0
- skcomplex/models/biology/evolution/_coevolution.py +148 -0
- skcomplex/models/biology/evolution/_cyclic_species.py +44 -0
- skcomplex/models/biology/evolution/_dependency_field.py +56 -0
- skcomplex/models/biology/evolution/_finite_populations.py +287 -0
- skcomplex/models/biology/evolution/_games.py +143 -0
- skcomplex/models/biology/evolution/_genotype_class.py +42 -0
- skcomplex/models/biology/evolution/_individual.py +54 -0
- skcomplex/models/biology/evolution/_individual_view.py +16 -0
- skcomplex/models/biology/evolution/_locus.py +47 -0
- skcomplex/models/biology/evolution/_master_sequence.py +55 -0
- skcomplex/models/biology/evolution/_molecule.py +47 -0
- skcomplex/models/biology/evolution/_moran_step.py +83 -0
- skcomplex/models/biology/evolution/_networks.py +194 -0
- skcomplex/models/biology/evolution/_prebiotic.py +169 -0
- skcomplex/models/biology/evolution/_replicator.py +109 -0
- skcomplex/models/biology/evolution/_strategy.py +42 -0
- skcomplex/models/biology/evolution/_substitution.py +113 -0
- skcomplex/models/biology/evolution/_substitutions.py +126 -0
- skcomplex/models/biology/evolution/_tangled_nature_life_cycle.py +159 -0
- skcomplex/models/biology/evolution/_taxon.py +49 -0
- skcomplex/models/biology/neuroscience/__init__.py +63 -0
- skcomplex/models/biology/neuroscience/_conductances.py +193 -0
- skcomplex/models/biology/neuroscience/_delayed_synapse.py +70 -0
- skcomplex/models/biology/neuroscience/_excitable.py +178 -0
- skcomplex/models/biology/neuroscience/_fitz_hugh_nagumo_neuron.py +46 -0
- skcomplex/models/biology/neuroscience/_global_inhibition.py +71 -0
- skcomplex/models/biology/neuroscience/_hodgkin_huxley.py +103 -0
- skcomplex/models/biology/neuroscience/_inhibitor.py +62 -0
- skcomplex/models/biology/neuroscience/_inhibitor_drive.py +61 -0
- skcomplex/models/biology/neuroscience/_izhikevich.py +77 -0
- skcomplex/models/biology/neuroscience/_leaky_integrate_and_fire.py +80 -0
- skcomplex/models/biology/neuroscience/_mutual_inhibition.py +55 -0
- skcomplex/models/biology/neuroscience/_networks.py +235 -0
- skcomplex/models/biology/neuroscience/_neural_field_site.py +66 -0
- skcomplex/models/biology/neuroscience/_neural_fields.py +94 -0
- skcomplex/models/biology/neuroscience/_neurons.py +129 -0
- skcomplex/models/biology/neuroscience/_polyhomeostatic_neuron.py +93 -0
- skcomplex/models/biology/neuroscience/_populations.py +333 -0
- skcomplex/models/biology/neuroscience/_pulse_coupling.py +71 -0
- skcomplex/models/biology/neuroscience/_rate_unit.py +67 -0
- skcomplex/models/biology/neuroscience/_spike_reset.py +95 -0
- skcomplex/models/biology/neuroscience/_spiking_neuron.py +67 -0
- skcomplex/models/biology/neuroscience/_synapses.py +226 -0
- skcomplex/models/biology/neuroscience/_terman_wang.py +113 -0
- skcomplex/models/biology/neuroscience/_theta_neuron.py +66 -0
- skcomplex/models/biology/neuroscience/_wilson_cowan.py +122 -0
- skcomplex/models/biology/neuroscience/types.py +8 -0
- skcomplex/models/biology/oncology/__init__.py +212 -0
- skcomplex/models/biology/oncology/_androgen_receptor_prostate.py +240 -0
- skcomplex/models/biology/oncology/_androgen_suppression.py +109 -0
- skcomplex/models/biology/oncology/_angiogenesis.py +306 -0
- skcomplex/models/biology/oncology/_angiogenesis_immunotherapy_tumour.py +247 -0
- skcomplex/models/biology/oncology/_angiogenic_tumour.py +110 -0
- skcomplex/models/biology/oncology/_antiangiogenic.py +227 -0
- skcomplex/models/biology/oncology/_bone_marrow_blood.py +196 -0
- skcomplex/models/biology/oncology/_cell_cycle.py +85 -0
- skcomplex/models/biology/oncology/_cell_kinetics.py +285 -0
- skcomplex/models/biology/oncology/_cell_quota_prostate.py +207 -0
- skcomplex/models/biology/oncology/_cell_survival.py +72 -0
- skcomplex/models/biology/oncology/_checkpoint_tumour.py +161 -0
- skcomplex/models/biology/oncology/_chemoimmunotherapy_tumour.py +251 -0
- skcomplex/models/biology/oncology/_chemotherapy.py +565 -0
- skcomplex/models/biology/oncology/_chemovirotherapy_tumour.py +139 -0
- skcomplex/models/biology/oncology/_clonal_tumour.py +134 -0
- skcomplex/models/biology/oncology/_combination_therapy.py +989 -0
- skcomplex/models/biology/oncology/_delayed_vaccinated_tumour.py +341 -0
- skcomplex/models/biology/oncology/_dormant_cell_cycle.py +95 -0
- skcomplex/models/biology/oncology/_erythropoiesis.py +129 -0
- skcomplex/models/biology/oncology/_exponential_linear_growth.py +66 -0
- skcomplex/models/biology/oncology/_gene_viral_therapy.py +480 -0
- skcomplex/models/biology/oncology/_glioma_brain.py +165 -0
- skcomplex/models/biology/oncology/_growth.py +378 -0
- skcomplex/models/biology/oncology/_her2_tumour.py +156 -0
- skcomplex/models/biology/oncology/_hormone_therapy.py +985 -0
- skcomplex/models/biology/oncology/_immune_competition.py +241 -0
- skcomplex/models/biology/oncology/_immunotherapy.py +1001 -0
- skcomplex/models/biology/oncology/_intermittent_suppression.py +130 -0
- skcomplex/models/biology/oncology/_irradiated_tumour.py +105 -0
- skcomplex/models/biology/oncology/_irradiation.py +97 -0
- skcomplex/models/biology/oncology/_kirschner_panetta_tumour.py +132 -0
- skcomplex/models/biology/oncology/_leukaemia_stem_cells.py +150 -0
- skcomplex/models/biology/oncology/_linear_quadratic_survival.py +112 -0
- skcomplex/models/biology/oncology/_log_kill.py +81 -0
- skcomplex/models/biology/oncology/_metastasis_chemotherapy.py +211 -0
- skcomplex/models/biology/oncology/_multidrug_resistance.py +201 -0
- skcomplex/models/biology/oncology/_oncolytic_virus.py +68 -0
- skcomplex/models/biology/oncology/_oncolytic_virus_dendritic.py +155 -0
- skcomplex/models/biology/oncology/_optimal_chemotherapy.py +157 -0
- skcomplex/models/biology/oncology/_optimal_immunotherapy.py +137 -0
- skcomplex/models/biology/oncology/_optimal_therapy.py +208 -0
- skcomplex/models/biology/oncology/_piecewise_linear_prostate.py +147 -0
- skcomplex/models/biology/oncology/_radiation_competition.py +104 -0
- skcomplex/models/biology/oncology/_radiotherapy.py +311 -0
- skcomplex/models/biology/oncology/_resistance_switching.py +148 -0
- skcomplex/models/biology/oncology/_resting_hunting_chemotherapy.py +136 -0
- skcomplex/models/biology/oncology/_sirna_tgf_beta.py +189 -0
- skcomplex/models/biology/oncology/_sprout.py +65 -0
- skcomplex/models/biology/oncology/_sprout_view.py +17 -0
- skcomplex/models/biology/oncology/_stem_cell_differentiation.py +262 -0
- skcomplex/models/biology/oncology/_stem_cells.py +548 -0
- skcomplex/models/biology/oncology/_suppressed_tumour.py +338 -0
- skcomplex/models/biology/oncology/_tamoxifen_tumour.py +172 -0
- skcomplex/models/biology/oncology/_tcr_gene_therapy.py +98 -0
- skcomplex/models/biology/oncology/_therapy_switch.py +86 -0
- skcomplex/models/biology/oncology/_tissue.py +71 -0
- skcomplex/models/biology/oncology/_tumour_cell.py +85 -0
- skcomplex/models/biology/oncology/_tumour_cell_view.py +21 -0
- skcomplex/models/biology/oncology/_tumour_immune_chemotherapy.py +169 -0
- skcomplex/models/biology/oncology/_vaccinated_tumour.py +180 -0
- skcomplex/models/biology/oncology/_vascular_support.py +71 -0
- skcomplex/models/biology/oncology/_vascularized_spheroid.py +264 -0
- skcomplex/models/biology/oncology/_vasculature.py +42 -0
- skcomplex/models/biology/oncology/_vessel.py +49 -0
- skcomplex/models/biology/oncology/_vessel_view.py +15 -0
- skcomplex/models/biology/physiology/__init__.py +46 -0
- skcomplex/models/biology/physiology/_adaptivity.py +277 -0
- skcomplex/models/biology/physiology/_cardiac.py +167 -0
- skcomplex/models/biology/physiology/_chamber.py +71 -0
- skcomplex/models/biology/physiology/_circulation.py +97 -0
- skcomplex/models/biology/physiology/_coagulation.py +130 -0
- skcomplex/models/biology/physiology/_contour_cell.py +61 -0
- skcomplex/models/biology/physiology/_contour_uptake.py +61 -0
- skcomplex/models/biology/physiology/_exchange.py +165 -0
- skcomplex/models/biology/physiology/_exchanging_cell.py +83 -0
- skcomplex/models/biology/physiology/_fitz_hugh_nagumo.py +46 -0
- skcomplex/models/biology/physiology/_glucose_control.py +136 -0
- skcomplex/models/biology/physiology/_mackey_glass.py +81 -0
- skcomplex/models/biology/physiology/_pharmacokinetics.py +104 -0
- skcomplex/models/biology/physiology/_physiology.py +118 -0
- skcomplex/models/biology/physiology/_regulation.py +251 -0
- skcomplex/models/biology/physiology/_resistive_flow.py +67 -0
- skcomplex/models/biology/physiology/_toxicity.py +164 -0
- skcomplex/models/biology/systems_biology/__init__.py +52 -0
- skcomplex/models/biology/systems_biology/_boolean.py +141 -0
- skcomplex/models/biology/systems_biology/_boolean_function.py +84 -0
- skcomplex/models/biology/systems_biology/_boolean_models.py +206 -0
- skcomplex/models/biology/systems_biology/_boolean_node.py +41 -0
- skcomplex/models/biology/systems_biology/_cascades.py +178 -0
- skcomplex/models/biology/systems_biology/_clocks.py +274 -0
- skcomplex/models/biology/systems_biology/_generalized_mass_action.py +123 -0
- skcomplex/models/biology/systems_biology/_genes.py +296 -0
- skcomplex/models/biology/systems_biology/_min_proteins.py +230 -0
- skcomplex/models/biology/systems_biology/_networks.py +359 -0
- skcomplex/models/biology/systems_biology/_phosphorylation_loop.py +121 -0
- skcomplex/models/biology/systems_biology/_probabilistic.py +75 -0
- skcomplex/models/biology/systems_biology/_probabilistic_function.py +127 -0
- skcomplex/models/biology/systems_biology/_probabilistic_node.py +47 -0
- skcomplex/models/biology/systems_biology/_repression.py +104 -0
- skcomplex/models/biology/systems_biology/_s_system.py +88 -0
- skcomplex/models/biology/systems_biology/_species.py +44 -0
- skcomplex/models/biology/systems_biology/_threshold_function.py +63 -0
- skcomplex/models/biology/systems_biology/types.py +9 -0
- skcomplex/models/chemistry/__init__.py +1 -0
- skcomplex/models/chemistry/common/__init__.py +3 -0
- skcomplex/models/chemistry/common/kinetics/__init__.py +9 -0
- skcomplex/models/chemistry/common/kinetics/_brusselator.py +61 -0
- skcomplex/models/chemistry/common/kinetics/_cubic_autocatalysis.py +80 -0
- skcomplex/models/chemistry/kinetics/__init__.py +38 -0
- skcomplex/models/chemistry/kinetics/_catalyst_pellet.py +60 -0
- skcomplex/models/chemistry/kinetics/_cubic_autocatalysis.py +60 -0
- skcomplex/models/chemistry/kinetics/_cyclic.py +130 -0
- skcomplex/models/chemistry/kinetics/_hodgepodge.py +157 -0
- skcomplex/models/chemistry/kinetics/_nanoparticles.py +103 -0
- skcomplex/models/chemistry/kinetics/_oregonator.py +76 -0
- skcomplex/models/chemistry/kinetics/_oscillators.py +244 -0
- skcomplex/models/chemistry/kinetics/_pulsed_electrode.py +107 -0
- skcomplex/models/chemistry/kinetics/_reactions.py +332 -0
- skcomplex/models/chemistry/kinetics/_reactors.py +144 -0
- skcomplex/models/chemistry/pattern_formation/__init__.py +15 -0
- skcomplex/models/chemistry/pattern_formation/_brusselator.py +62 -0
- skcomplex/models/chemistry/pattern_formation/_gray_scott.py +68 -0
- skcomplex/models/chemistry/pattern_formation/_reaction_diffusion.py +268 -0
- skcomplex/models/chemistry/pattern_formation/_schnakenberg.py +67 -0
- skcomplex/models/computer_science/__init__.py +1 -0
- skcomplex/models/computer_science/automata/__init__.py +56 -0
- skcomplex/models/computer_science/automata/_automata.py +229 -0
- skcomplex/models/computer_science/automata/_automaton.py +202 -0
- skcomplex/models/computer_science/automata/_binary_cell.py +41 -0
- skcomplex/models/computer_science/automata/_codes.py +73 -0
- skcomplex/models/computer_science/automata/_diffusion_cell.py +47 -0
- skcomplex/models/computer_science/automata/_group_automata.py +449 -0
- skcomplex/models/computer_science/automata/_groups.py +132 -0
- skcomplex/models/computer_science/automata/_linear_automaton.py +128 -0
- skcomplex/models/computer_science/automata/_noisy_elementary_cell.py +46 -0
- skcomplex/models/computer_science/automata/_pascal_cell.py +41 -0
- skcomplex/models/computer_science/automata/_subshift.py +192 -0
- skcomplex/models/computer_science/automata/_variants.py +292 -0
- skcomplex/models/computer_science/evolutionary_computation/__init__.py +27 -0
- skcomplex/models/computer_science/evolutionary_computation/_annealed_candidate.py +39 -0
- skcomplex/models/computer_science/evolutionary_computation/_bit_string.py +55 -0
- skcomplex/models/computer_science/evolutionary_computation/_bit_string_view.py +13 -0
- skcomplex/models/computer_science/evolutionary_computation/_genetic_algorithms.py +92 -0
- skcomplex/models/computer_science/evolutionary_computation/_landscapes.py +82 -0
- skcomplex/models/computer_science/evolutionary_computation/_optimisers.py +217 -0
- skcomplex/models/computer_science/evolutionary_computation/_reproduction.py +129 -0
- skcomplex/models/computer_science/evolutionary_computation/_room_cleaning.py +170 -0
- skcomplex/models/computer_science/evolutionary_computation/_running_best.py +30 -0
- skcomplex/models/computer_science/evolutionary_computation/_running_best_update.py +58 -0
- skcomplex/models/computer_science/evolutionary_computation/_search_candidate.py +32 -0
- skcomplex/models/computer_science/evolutionary_computation/_strategy.py +54 -0
- skcomplex/models/computer_science/evolutionary_computation/_strategy_view.py +14 -0
- skcomplex/models/computer_science/neural_networks/__init__.py +34 -0
- skcomplex/models/computer_science/neural_networks/_binary_weight.py +32 -0
- skcomplex/models/computer_science/neural_networks/_diluted.py +159 -0
- skcomplex/models/computer_science/neural_networks/_echo_state.py +173 -0
- skcomplex/models/computer_science/neural_networks/_elman.py +160 -0
- skcomplex/models/computer_science/neural_networks/_hidden_unit.py +51 -0
- skcomplex/models/computer_science/neural_networks/_hopfield.py +134 -0
- skcomplex/models/computer_science/neural_networks/_hopfield_update.py +51 -0
- skcomplex/models/computer_science/neural_networks/_input_coupling.py +63 -0
- skcomplex/models/computer_science/neural_networks/_input_unit.py +39 -0
- skcomplex/models/computer_science/neural_networks/_neuron_view.py +14 -0
- skcomplex/models/computer_science/neural_networks/_output_unit.py +51 -0
- skcomplex/models/computer_science/neural_networks/_perceptron.py +72 -0
- skcomplex/models/computer_science/neural_networks/_readout_coupling.py +69 -0
- skcomplex/models/computer_science/neural_networks/_recurrence_coupling.py +66 -0
- skcomplex/models/economics/__init__.py +1 -0
- skcomplex/models/economics/common/__init__.py +3 -0
- skcomplex/models/economics/common/forecasting/__init__.py +7 -0
- skcomplex/models/economics/common/forecasting/_heuristics.py +51 -0
- skcomplex/models/economics/common/resources/__init__.py +7 -0
- skcomplex/models/economics/common/resources/_regrowth.py +70 -0
- skcomplex/models/economics/econophysics/__init__.py +58 -0
- skcomplex/models/economics/econophysics/_crowd_avoidance.py +80 -0
- skcomplex/models/economics/econophysics/_debt_exchange.py +74 -0
- skcomplex/models/economics/econophysics/_diner.py +59 -0
- skcomplex/models/economics/econophysics/_diner_view.py +17 -0
- skcomplex/models/economics/econophysics/_el_farol.py +114 -0
- skcomplex/models/economics/econophysics/_exchange.py +82 -0
- skcomplex/models/economics/econophysics/_game_state_spec.py +26 -0
- skcomplex/models/economics/econophysics/_kinetic.py +80 -0
- skcomplex/models/economics/econophysics/_kolkata.py +87 -0
- skcomplex/models/economics/econophysics/_minority.py +123 -0
- skcomplex/models/economics/econophysics/_minority_game.py +161 -0
- skcomplex/models/economics/econophysics/_minority_player.py +79 -0
- skcomplex/models/economics/econophysics/_minority_player_view.py +22 -0
- skcomplex/models/economics/econophysics/_patron.py +105 -0
- skcomplex/models/economics/econophysics/_patron_view.py +18 -0
- skcomplex/models/economics/econophysics/_predictor_pool.py +181 -0
- skcomplex/models/economics/econophysics/_predictor_pool_view.py +14 -0
- skcomplex/models/economics/econophysics/_restaurants.py +93 -0
- skcomplex/models/economics/econophysics/_saving_exchange.py +73 -0
- skcomplex/models/economics/econophysics/_saving_trader.py +47 -0
- skcomplex/models/economics/econophysics/_saving_trader_view.py +12 -0
- skcomplex/models/economics/econophysics/_wealth_exchange.py +114 -0
- skcomplex/models/economics/econophysics/_welfare.py +210 -0
- skcomplex/models/economics/econophysics/_welfare_policy.py +99 -0
- skcomplex/models/economics/finance/__init__.py +41 -0
- skcomplex/models/economics/finance/_arbitrage.py +139 -0
- skcomplex/models/economics/finance/_asset.py +42 -0
- skcomplex/models/economics/finance/_assets.py +44 -0
- skcomplex/models/economics/finance/_book.py +115 -0
- skcomplex/models/economics/finance/_contagion.py +116 -0
- skcomplex/models/economics/finance/_correlated_assets.py +69 -0
- skcomplex/models/economics/finance/_debt_rank_cascade.py +86 -0
- skcomplex/models/economics/finance/_geometric_brownian_motion.py +89 -0
- skcomplex/models/economics/finance/_gibrat_firm.py +82 -0
- skcomplex/models/economics/finance/_gibrat_firm_view.py +18 -0
- skcomplex/models/economics/finance/_growth_processes.py +195 -0
- skcomplex/models/economics/finance/_interbank.py +76 -0
- skcomplex/models/economics/finance/_interbank_view.py +14 -0
- skcomplex/models/economics/finance/_kesten_firm.py +88 -0
- skcomplex/models/economics/finance/_kesten_firm_view.py +16 -0
- skcomplex/models/economics/finance/_order_book.py +164 -0
- skcomplex/models/economics/finance/_reflecting_floor.py +66 -0
- skcomplex/models/economics/finance/_stock_trader.py +205 -0
- skcomplex/models/economics/finance/_stock_trader_view.py +24 -0
- skcomplex/models/economics/finance/_wealth.py +143 -0
- skcomplex/models/economics/innovation/__init__.py +23 -0
- skcomplex/models/economics/innovation/_adoption.py +233 -0
- skcomplex/models/economics/innovation/_bass.py +124 -0
- skcomplex/models/economics/innovation/_diversity.py +104 -0
- skcomplex/models/economics/innovation/_household_view.py +20 -0
- skcomplex/models/economics/innovation/_invention.py +140 -0
- skcomplex/models/economics/innovation/_part.py +64 -0
- skcomplex/models/economics/innovation/_part_view.py +12 -0
- skcomplex/models/economics/innovation/_redesign.py +88 -0
- skcomplex/models/economics/innovation/_technology.py +203 -0
- skcomplex/models/economics/innovation/_technology_view.py +14 -0
- skcomplex/models/economics/macroeconomics/__init__.py +70 -0
- skcomplex/models/economics/macroeconomics/_banking.py +148 -0
- skcomplex/models/economics/macroeconomics/_business.py +221 -0
- skcomplex/models/economics/macroeconomics/_business_view.py +24 -0
- skcomplex/models/economics/macroeconomics/_capital.py +122 -0
- skcomplex/models/economics/macroeconomics/_central_bank.py +80 -0
- skcomplex/models/economics/macroeconomics/_central_bank_view.py +13 -0
- skcomplex/models/economics/macroeconomics/_circuit.py +93 -0
- skcomplex/models/economics/macroeconomics/_commons.py +77 -0
- skcomplex/models/economics/macroeconomics/_credit.py +219 -0
- skcomplex/models/economics/macroeconomics/_credit_market.py +83 -0
- skcomplex/models/economics/macroeconomics/_depositor.py +114 -0
- skcomplex/models/economics/macroeconomics/_depositor_view.py +19 -0
- skcomplex/models/economics/macroeconomics/_economy.py +42 -0
- skcomplex/models/economics/macroeconomics/_estate.py +88 -0
- skcomplex/models/economics/macroeconomics/_firm.py +184 -0
- skcomplex/models/economics/macroeconomics/_firm_view.py +27 -0
- skcomplex/models/economics/macroeconomics/_firms.py +208 -0
- skcomplex/models/economics/macroeconomics/_firms_element.py +67 -0
- skcomplex/models/economics/macroeconomics/_food_market.py +84 -0
- skcomplex/models/economics/macroeconomics/_growth.py +109 -0
- skcomplex/models/economics/macroeconomics/_households.py +52 -0
- skcomplex/models/economics/macroeconomics/_income.py +59 -0
- skcomplex/models/economics/macroeconomics/_investing_firm_view.py +21 -0
- skcomplex/models/economics/macroeconomics/_labour_market.py +73 -0
- skcomplex/models/economics/macroeconomics/_lender.py +160 -0
- skcomplex/models/economics/macroeconomics/_lender_view.py +18 -0
- skcomplex/models/economics/macroeconomics/_metaphoria.py +257 -0
- skcomplex/models/economics/macroeconomics/_monetary.py +140 -0
- skcomplex/models/economics/macroeconomics/_monetary_bank.py +57 -0
- skcomplex/models/economics/macroeconomics/_optimal_growth.py +173 -0
- skcomplex/models/economics/macroeconomics/_people_spec.py +26 -0
- skcomplex/models/economics/macroeconomics/_plot.py +69 -0
- skcomplex/models/economics/macroeconomics/_plot_view.py +15 -0
- skcomplex/models/economics/macroeconomics/_policy_switch.py +78 -0
- skcomplex/models/economics/macroeconomics/_reserve_bank.py +118 -0
- skcomplex/models/economics/macroeconomics/_reserve_bank_view.py +14 -0
- skcomplex/models/economics/macroeconomics/_settler.py +291 -0
- skcomplex/models/economics/macroeconomics/_settler_view.py +56 -0
- skcomplex/models/economics/macroeconomics/_solow_growth.py +70 -0
- skcomplex/models/economics/macroeconomics/_trade.py +289 -0
- skcomplex/models/economics/markets/__init__.py +128 -0
- skcomplex/models/economics/markets/_auction_ledger.py +81 -0
- skcomplex/models/economics/markets/_barter.py +232 -0
- skcomplex/models/economics/markets/_barter_networks.py +169 -0
- skcomplex/models/economics/markets/_barter_trader.py +136 -0
- skcomplex/models/economics/markets/_barter_trader_view.py +16 -0
- skcomplex/models/economics/markets/_bilateral_barter.py +150 -0
- skcomplex/models/economics/markets/_brewery.py +67 -0
- skcomplex/models/economics/markets/_brock_hommes.py +115 -0
- skcomplex/models/economics/markets/_car.py +75 -0
- skcomplex/models/economics/markets/_car_view.py +14 -0
- skcomplex/models/economics/markets/_car_wash_operation.py +141 -0
- skcomplex/models/economics/markets/_cobweb.py +109 -0
- skcomplex/models/economics/markets/_commodities.py +286 -0
- skcomplex/models/economics/markets/_consumer_view.py +22 -0
- skcomplex/models/economics/markets/_cournot_adjustment.py +65 -0
- skcomplex/models/economics/markets/_cournot_best_response.py +88 -0
- skcomplex/models/economics/markets/_customer.py +147 -0
- skcomplex/models/economics/markets/_customer_view.py +16 -0
- skcomplex/models/economics/markets/_double_auction.py +141 -0
- skcomplex/models/economics/markets/_duopolist.py +54 -0
- skcomplex/models/economics/markets/_duopolist_view.py +13 -0
- skcomplex/models/economics/markets/_duopoly.py +85 -0
- skcomplex/models/economics/markets/_echelon.py +132 -0
- skcomplex/models/economics/markets/_employer.py +102 -0
- skcomplex/models/economics/markets/_employer_view.py +20 -0
- skcomplex/models/economics/markets/_exchange.py +171 -0
- skcomplex/models/economics/markets/_exchange_interaction.py +134 -0
- skcomplex/models/economics/markets/_factory.py +105 -0
- skcomplex/models/economics/markets/_fair_food.py +205 -0
- skcomplex/models/economics/markets/_forager.py +64 -0
- skcomplex/models/economics/markets/_forager_view.py +14 -0
- skcomplex/models/economics/markets/_goods_trader.py +68 -0
- skcomplex/models/economics/markets/_goods_traders.py +139 -0
- skcomplex/models/economics/markets/_heuristic_pricing.py +122 -0
- skcomplex/models/economics/markets/_heuristic_trader.py +108 -0
- skcomplex/models/economics/markets/_heuristic_trader_view.py +14 -0
- skcomplex/models/economics/markets/_inventory.py +212 -0
- skcomplex/models/economics/markets/_jobseeker.py +144 -0
- skcomplex/models/economics/markets/_jobseeker_view.py +26 -0
- skcomplex/models/economics/markets/_labour.py +188 -0
- skcomplex/models/economics/markets/_market.py +39 -0
- skcomplex/models/economics/markets/_market_state_spec.py +25 -0
- skcomplex/models/economics/markets/_oligopoly.py +167 -0
- skcomplex/models/economics/markets/_patch_map_spec.py +22 -0
- skcomplex/models/economics/markets/_perishables.py +150 -0
- skcomplex/models/economics/markets/_price_point.py +95 -0
- skcomplex/models/economics/markets/_prices.py +151 -0
- skcomplex/models/economics/markets/_pricing_firm.py +48 -0
- skcomplex/models/economics/markets/_pricing_firm_view.py +14 -0
- skcomplex/models/economics/markets/_pricing_game_spec.py +81 -0
- skcomplex/models/economics/markets/_produce.py +94 -0
- skcomplex/models/economics/markets/_product.py +97 -0
- skcomplex/models/economics/markets/_product_view.py +13 -0
- skcomplex/models/economics/markets/_queues.py +101 -0
- skcomplex/models/economics/markets/_resident.py +119 -0
- skcomplex/models/economics/markets/_resident_view.py +20 -0
- skcomplex/models/economics/markets/_retail_demand.py +52 -0
- skcomplex/models/economics/markets/_retailer.py +115 -0
- skcomplex/models/economics/markets/_shopper.py +115 -0
- skcomplex/models/economics/markets/_shopper_view.py +15 -0
- skcomplex/models/economics/markets/_shops.py +199 -0
- skcomplex/models/economics/markets/_stall.py +74 -0
- skcomplex/models/economics/markets/_stall_view.py +14 -0
- skcomplex/models/economics/markets/_store.py +171 -0
- skcomplex/models/economics/markets/_store_view.py +27 -0
- skcomplex/models/economics/markets/_sugar_patch.py +61 -0
- skcomplex/models/economics/markets/_sugar_patch_view.py +14 -0
- skcomplex/models/economics/markets/_sugarscape.py +250 -0
- skcomplex/models/economics/markets/_supply_chains.py +217 -0
- skcomplex/models/economics/markets/_supply_link.py +74 -0
- skcomplex/models/economics/markets/_till.py +79 -0
- skcomplex/models/economics/markets/_till_view.py +15 -0
- skcomplex/models/economics/markets/_washer.py +78 -0
- skcomplex/models/economics/markets/_zero_intelligence_buyer.py +99 -0
- skcomplex/models/economics/markets/_zero_intelligence_buyer_view.py +20 -0
- skcomplex/models/economics/markets/_zero_intelligence_seller.py +100 -0
- skcomplex/models/economics/markets/_zero_intelligence_seller_view.py +20 -0
- skcomplex/models/economics/resources/__init__.py +50 -0
- skcomplex/models/economics/resources/_bid_rent.py +104 -0
- skcomplex/models/economics/resources/_commons.py +218 -0
- skcomplex/models/economics/resources/_cow.py +69 -0
- skcomplex/models/economics/resources/_cow_view.py +13 -0
- skcomplex/models/economics/resources/_extraction.py +230 -0
- skcomplex/models/economics/resources/_farmer.py +93 -0
- skcomplex/models/economics/resources/_farmer_view.py +12 -0
- skcomplex/models/economics/resources/_fisheries.py +384 -0
- skcomplex/models/economics/resources/_fishery.py +91 -0
- skcomplex/models/economics/resources/_food.py +370 -0
- skcomplex/models/economics/resources/_grazing.py +148 -0
- skcomplex/models/economics/resources/_harvest.py +69 -0
- skcomplex/models/economics/resources/_harvesting.py +51 -0
- skcomplex/models/economics/resources/_herder.py +78 -0
- skcomplex/models/economics/resources/_herder_view.py +19 -0
- skcomplex/models/economics/resources/_land_cell.py +39 -0
- skcomplex/models/economics/resources/_land_use.py +73 -0
- skcomplex/models/economics/resources/_oil_economy.py +85 -0
- skcomplex/models/economics/resources/_optimal_harvesting.py +180 -0
- skcomplex/models/economics/resources/_pasture.py +98 -0
- skcomplex/models/economics/resources/_pasture_view.py +15 -0
- skcomplex/models/economics/resources/_plantations.py +359 -0
- skcomplex/models/economics/resources/_quota_regulator.py +84 -0
- skcomplex/models/economics/resources/_stock.py +67 -0
- skcomplex/models/engineering/__init__.py +1 -0
- skcomplex/models/engineering/circuits/__init__.py +23 -0
- skcomplex/models/engineering/circuits/_chua_circuit.py +48 -0
- skcomplex/models/engineering/circuits/_circuit.py +47 -0
- skcomplex/models/engineering/circuits/_circuits.py +387 -0
- skcomplex/models/engineering/circuits/_harvesters.py +150 -0
- skcomplex/models/engineering/circuits/_kicked_circuit.py +43 -0
- skcomplex/models/engineering/circuits/_memristor_circuit.py +48 -0
- skcomplex/models/engineering/circuits/_mixed_mode_chua_circuit.py +54 -0
- skcomplex/models/engineering/circuits/_multiscroll_chua_circuit.py +58 -0
- skcomplex/models/engineering/circuits/_tunnel_diode_circuit.py +45 -0
- skcomplex/models/engineering/common/__init__.py +6 -0
- skcomplex/models/engineering/common/mechanics/__init__.py +7 -0
- skcomplex/models/engineering/common/mechanics/_spring_damper.py +121 -0
- skcomplex/models/engineering/control/__init__.py +23 -0
- skcomplex/models/engineering/control/_cart_pendulum.py +119 -0
- skcomplex/models/engineering/control/_control.py +266 -0
- skcomplex/models/engineering/control/_controlled_process.py +72 -0
- skcomplex/models/engineering/control/_driven_oscillator.py +79 -0
- skcomplex/models/engineering/control/_integrator.py +39 -0
- skcomplex/models/engineering/control/_pid.py +106 -0
- skcomplex/models/engineering/control/_regulation.py +170 -0
- skcomplex/models/engineering/control/_room.py +51 -0
- skcomplex/models/engineering/control/_satellite.py +56 -0
- skcomplex/models/engineering/control/_state_feedback.py +82 -0
- skcomplex/models/engineering/control/_swinging_pendulum.py +60 -0
- skcomplex/models/engineering/power_systems/__init__.py +11 -0
- skcomplex/models/engineering/power_systems/_electromechanics.py +224 -0
- skcomplex/models/engineering/power_systems/_faraday_disk.py +93 -0
- skcomplex/models/engineering/power_systems/_grid_node.py +39 -0
- skcomplex/models/engineering/power_systems/_grids.py +89 -0
- skcomplex/models/engineering/power_systems/_rail_segment.py +80 -0
- skcomplex/models/engineering/power_systems/_regenerative_car.py +55 -0
- skcomplex/models/engineering/power_systems/_transmission_line.py +48 -0
- skcomplex/models/engineering/processes/__init__.py +13 -0
- skcomplex/models/engineering/processes/_irrigation_scheme.py +112 -0
- skcomplex/models/engineering/processes/_processes.py +115 -0
- skcomplex/models/engineering/processes/_relief_pipeline.py +79 -0
- skcomplex/models/engineering/processes/_rice_mill.py +112 -0
- skcomplex/models/engineering/processes/_stage.py +34 -0
- skcomplex/models/engineering/processes/_systems.py +316 -0
- skcomplex/models/engineering/processes/_tub.py +42 -0
- skcomplex/models/engineering/processes/_waste_system.py +101 -0
- skcomplex/models/engineering/robotics/__init__.py +12 -0
- skcomplex/models/engineering/robotics/_light_sensitive_robot.py +125 -0
- skcomplex/models/engineering/robotics/_robots.py +177 -0
- skcomplex/models/engineering/robotics/_swarm_robot.py +211 -0
- skcomplex/models/engineering/robotics/_swarm_robot_view.py +23 -0
- skcomplex/models/engineering/traffic/__init__.py +43 -0
- skcomplex/models/engineering/traffic/_arrival.py +117 -0
- skcomplex/models/engineering/traffic/_cab.py +170 -0
- skcomplex/models/engineering/traffic/_cab_view.py +21 -0
- skcomplex/models/engineering/traffic/_car.py +31 -0
- skcomplex/models/engineering/traffic/_car_following.py +245 -0
- skcomplex/models/engineering/traffic/_careless_braking.py +87 -0
- skcomplex/models/engineering/traffic/_continuum.py +429 -0
- skcomplex/models/engineering/traffic/_delayed_following.py +65 -0
- skcomplex/models/engineering/traffic/_driver.py +140 -0
- skcomplex/models/engineering/traffic/_driver_view.py +18 -0
- skcomplex/models/engineering/traffic/_drivers.py +133 -0
- skcomplex/models/engineering/traffic/_gas_kinetic_traffic.py +96 -0
- skcomplex/models/engineering/traffic/_intelligent_driver.py +90 -0
- skcomplex/models/engineering/traffic/_kerner_konhauser.py +42 -0
- skcomplex/models/engineering/traffic/_langevin.py +170 -0
- skcomplex/models/engineering/traffic/_langevin_driving.py +95 -0
- skcomplex/models/engineering/traffic/_lead_car.py +40 -0
- skcomplex/models/engineering/traffic/_lighthill_whitham_richards.py +30 -0
- skcomplex/models/engineering/traffic/_motorist.py +118 -0
- skcomplex/models/engineering/traffic/_motorist_view.py +18 -0
- skcomplex/models/engineering/traffic/_optimal_velocity.py +72 -0
- skcomplex/models/engineering/traffic/_payne.py +38 -0
- skcomplex/models/engineering/traffic/_rider.py +72 -0
- skcomplex/models/engineering/traffic/_rider_view.py +16 -0
- skcomplex/models/engineering/traffic/_ridesharing.py +179 -0
- skcomplex/models/engineering/traffic/_traffic.py +143 -0
- skcomplex/models/engineering/traffic/_traffic_moments.py +57 -0
- skcomplex/models/mathematics/__init__.py +1 -0
- skcomplex/models/mathematics/common/__init__.py +3 -0
- skcomplex/models/mathematics/common/flows/__init__.py +7 -0
- skcomplex/models/mathematics/common/flows/_lorenz.py +90 -0
- skcomplex/models/mathematics/dynamical_systems/__init__.py +90 -0
- skcomplex/models/mathematics/dynamical_systems/_baker_map.py +59 -0
- skcomplex/models/mathematics/dynamical_systems/_blow_up.py +64 -0
- skcomplex/models/mathematics/dynamical_systems/_cat_map.py +44 -0
- skcomplex/models/mathematics/dynamical_systems/_chaotic_ensembles.py +186 -0
- skcomplex/models/mathematics/dynamical_systems/_circle_map.py +49 -0
- skcomplex/models/mathematics/dynamical_systems/_cubic_walk.py +72 -0
- skcomplex/models/mathematics/dynamical_systems/_cusp.py +64 -0
- skcomplex/models/mathematics/dynamical_systems/_doubling_map.py +65 -0
- skcomplex/models/mathematics/dynamical_systems/_driven_flows.py +158 -0
- skcomplex/models/mathematics/dynamical_systems/_flows.py +179 -0
- skcomplex/models/mathematics/dynamical_systems/_henon_map.py +54 -0
- skcomplex/models/mathematics/dynamical_systems/_hopf.py +77 -0
- skcomplex/models/mathematics/dynamical_systems/_intermittency_map.py +44 -0
- skcomplex/models/mathematics/dynamical_systems/_jerk.py +72 -0
- skcomplex/models/mathematics/dynamical_systems/_koopman.py +118 -0
- skcomplex/models/mathematics/dynamical_systems/_logistic_map.py +44 -0
- skcomplex/models/mathematics/dynamical_systems/_maps.py +465 -0
- skcomplex/models/mathematics/dynamical_systems/_newton_map.py +44 -0
- skcomplex/models/mathematics/dynamical_systems/_normal_forms.py +154 -0
- skcomplex/models/mathematics/dynamical_systems/_rossler.py +83 -0
- skcomplex/models/mathematics/dynamical_systems/_saddle_node.py +59 -0
- skcomplex/models/mathematics/dynamical_systems/_skew_tent_map.py +63 -0
- skcomplex/models/mathematics/dynamical_systems/_standard_map.py +52 -0
- skcomplex/models/mathematics/dynamical_systems/_subcritical_forms.py +160 -0
- skcomplex/models/mathematics/dynamical_systems/_takens_bogdanov.py +74 -0
- skcomplex/models/mathematics/dynamical_systems/_tent_map.py +44 -0
- skcomplex/models/mathematics/dynamical_systems/_towel_map.py +59 -0
- skcomplex/models/mathematics/fractals/__init__.py +61 -0
- skcomplex/models/mathematics/fractals/_affine_spec.py +100 -0
- skcomplex/models/mathematics/fractals/_cantor_element.py +92 -0
- skcomplex/models/mathematics/fractals/_chaos_game.py +140 -0
- skcomplex/models/mathematics/fractals/_geometry_spec.py +84 -0
- skcomplex/models/mathematics/fractals/_geometry_visual.py +190 -0
- skcomplex/models/mathematics/fractals/_group_spec.py +24 -0
- skcomplex/models/mathematics/fractals/_koch_element.py +43 -0
- skcomplex/models/mathematics/fractals/_module_spec.py +47 -0
- skcomplex/models/mathematics/fractals/_patch_element.py +89 -0
- skcomplex/models/mathematics/fractals/_patch_kernel.py +200 -0
- skcomplex/models/mathematics/fractals/_patch_structure_spec.py +108 -0
- skcomplex/models/mathematics/fractals/_production_law.py +105 -0
- skcomplex/models/mathematics/fractals/_prototile_spec.py +53 -0
- skcomplex/models/mathematics/fractals/_quadratic.py +191 -0
- skcomplex/models/mathematics/fractals/_random_affine_map.py +100 -0
- skcomplex/models/mathematics/fractals/_rewriting_compiler.py +300 -0
- skcomplex/models/mathematics/fractals/_rewriting_error.py +10 -0
- skcomplex/models/mathematics/fractals/_rewriting_loops.py +180 -0
- skcomplex/models/mathematics/fractals/_rewriting_problem_spec.py +30 -0
- skcomplex/models/mathematics/fractals/_rewriting_solver.py +125 -0
- skcomplex/models/mathematics/fractals/_sierpinski_element.py +110 -0
- skcomplex/models/mathematics/fractals/_substitution.py +130 -0
- skcomplex/models/mathematics/fractals/_substitution_law.py +76 -0
- skcomplex/models/mathematics/fractals/_successor_spec.py +23 -0
- skcomplex/models/mathematics/fractals/_word_element.py +94 -0
- skcomplex/models/mathematics/fractals/_word_kernel.py +526 -0
- skcomplex/models/mathematics/fractals/_word_structure_spec.py +110 -0
- skcomplex/models/mathematics/fractals/_words.py +38 -0
- skcomplex/models/mathematics/fractals/types.py +12 -0
- skcomplex/models/mathematics/fractional_dynamics/__init__.py +29 -0
- skcomplex/models/mathematics/fractional_dynamics/_fractional.py +338 -0
- skcomplex/models/mathematics/fractional_dynamics/_oscillator.py +71 -0
- skcomplex/models/mathematics/fractional_dynamics/_relaxation.py +59 -0
- skcomplex/models/mathematics/fractional_dynamics/_van_der_pol.py +66 -0
- skcomplex/models/mathematics/networks/__init__.py +61 -0
- skcomplex/models/mathematics/networks/_copying_vertex.py +50 -0
- skcomplex/models/mathematics/networks/_ensemble_node.py +48 -0
- skcomplex/models/mathematics/networks/_ensembles.py +195 -0
- skcomplex/models/mathematics/networks/_failing.py +58 -0
- skcomplex/models/mathematics/networks/_giant_component.py +52 -0
- skcomplex/models/mathematics/networks/_growth.py +223 -0
- skcomplex/models/mathematics/networks/_hypergraphs.py +131 -0
- skcomplex/models/mathematics/networks/_link.py +21 -0
- skcomplex/models/mathematics/networks/_network_measures.py +59 -0
- skcomplex/models/mathematics/networks/_network_node.py +86 -0
- skcomplex/models/mathematics/networks/_network_walker.py +49 -0
- skcomplex/models/mathematics/networks/_network_walker_view.py +12 -0
- skcomplex/models/mathematics/networks/_node_content.py +47 -0
- skcomplex/models/mathematics/networks/_node_rank.py +57 -0
- skcomplex/models/mathematics/networks/_processes.py +148 -0
- skcomplex/models/mathematics/networks/_regulated_link.py +47 -0
- skcomplex/models/mathematics/networks/_regulated_node.py +43 -0
- skcomplex/models/mathematics/networks/_simplex.py +46 -0
- skcomplex/models/mathematics/networks/_simplex_ageing.py +46 -0
- skcomplex/models/mathematics/networks/_size_biased_move.py +44 -0
- skcomplex/models/mathematics/networks/_structure.py +170 -0
- skcomplex/models/mathematics/networks/_triad_vertex.py +64 -0
- skcomplex/models/mathematics/networks/_triadic.py +114 -0
- skcomplex/models/mathematics/networks/_triadic_regulation.py +65 -0
- skcomplex/models/mathematics/networks/_vertex.py +52 -0
- skcomplex/models/mathematics/networks/_walker_density.py +51 -0
- skcomplex/models/mathematics/stochastic_processes/__init__.py +62 -0
- skcomplex/models/mathematics/stochastic_processes/_ageing_walker.py +68 -0
- skcomplex/models/mathematics/stochastic_processes/_ageing_walker_view.py +15 -0
- skcomplex/models/mathematics/stochastic_processes/_bernoulli_trial.py +61 -0
- skcomplex/models/mathematics/stochastic_processes/_bernoulli_trial_view.py +14 -0
- skcomplex/models/mathematics/stochastic_processes/_branching.py +103 -0
- skcomplex/models/mathematics/stochastic_processes/_counting.py +88 -0
- skcomplex/models/mathematics/stochastic_processes/_fragment.py +91 -0
- skcomplex/models/mathematics/stochastic_processes/_fragment_view.py +13 -0
- skcomplex/models/mathematics/stochastic_processes/_hidden_markov_source.py +46 -0
- skcomplex/models/mathematics/stochastic_processes/_individual_view.py +13 -0
- skcomplex/models/mathematics/stochastic_processes/_intermittency.py +115 -0
- skcomplex/models/mathematics/stochastic_processes/_markov_source.py +41 -0
- skcomplex/models/mathematics/stochastic_processes/_memory_walker.py +57 -0
- skcomplex/models/mathematics/stochastic_processes/_persistent_walker.py +52 -0
- skcomplex/models/mathematics/stochastic_processes/_poisson_counter.py +47 -0
- skcomplex/models/mathematics/stochastic_processes/_queues.py +117 -0
- skcomplex/models/mathematics/stochastic_processes/_random_walker.py +52 -0
- skcomplex/models/mathematics/stochastic_processes/_reducing.py +104 -0
- skcomplex/models/mathematics/stochastic_processes/_reducing_ball.py +63 -0
- skcomplex/models/mathematics/stochastic_processes/_reducing_ball_view.py +14 -0
- skcomplex/models/mathematics/stochastic_processes/_reducing_jump.py +44 -0
- skcomplex/models/mathematics/stochastic_processes/_sources.py +90 -0
- skcomplex/models/mathematics/stochastic_processes/_urns.py +112 -0
- skcomplex/models/mathematics/stochastic_processes/_walks.py +280 -0
- skcomplex/models/mathematics/stochastic_processes/_weakening_particle.py +57 -0
- skcomplex/models/mathematics/stochastic_processes/types.py +8 -0
- skcomplex/models/physics/__init__.py +1 -0
- skcomplex/models/physics/active_matter/__init__.py +95 -0
- skcomplex/models/physics/active_matter/_active_particle.py +88 -0
- skcomplex/models/physics/active_matter/_alignment.py +192 -0
- skcomplex/models/physics/active_matter/_angular_alignment.py +98 -0
- skcomplex/models/physics/active_matter/_angular_diffusion.py +67 -0
- skcomplex/models/physics/active_matter/_binary_collisions.py +126 -0
- skcomplex/models/physics/active_matter/_chemotaxis.py +173 -0
- skcomplex/models/physics/active_matter/_cohesive_particle.py +132 -0
- skcomplex/models/physics/active_matter/_collective.py +327 -0
- skcomplex/models/physics/active_matter/_collisions.py +127 -0
- skcomplex/models/physics/active_matter/_contractile_gel_site.py +81 -0
- skcomplex/models/physics/active_matter/_cucker_smale_alignment.py +89 -0
- skcomplex/models/physics/active_matter/_depot_particle.py +103 -0
- skcomplex/models/physics/active_matter/_flocker.py +46 -0
- skcomplex/models/physics/active_matter/_flocker_view.py +20 -0
- skcomplex/models/physics/active_matter/_flocks.py +258 -0
- skcomplex/models/physics/active_matter/_gels.py +141 -0
- skcomplex/models/physics/active_matter/_heading_alignment.py +73 -0
- skcomplex/models/physics/active_matter/_kinetic_flocks.py +111 -0
- skcomplex/models/physics/active_matter/_landau_de_gennes_energy.py +107 -0
- skcomplex/models/physics/active_matter/_model_b.py +170 -0
- skcomplex/models/physics/active_matter/_nematic_density_site.py +78 -0
- skcomplex/models/physics/active_matter/_nematic_gel_site.py +115 -0
- skcomplex/models/physics/active_matter/_nematic_particle.py +61 -0
- skcomplex/models/physics/active_matter/_nematics.py +323 -0
- skcomplex/models/physics/active_matter/_nonreciprocal.py +214 -0
- skcomplex/models/physics/active_matter/_ornstein_uhlenbeck_particle.py +87 -0
- skcomplex/models/physics/active_matter/_particles.py +323 -0
- skcomplex/models/physics/active_matter/_phoretic_attraction.py +80 -0
- skcomplex/models/physics/active_matter/_polar_fluid.py +119 -0
- skcomplex/models/physics/active_matter/_polar_gel_site.py +120 -0
- skcomplex/models/physics/active_matter/_propulsion_step.py +64 -0
- skcomplex/models/physics/active_matter/_self_propulsion.py +73 -0
- skcomplex/models/physics/active_matter/_tumbler.py +100 -0
- skcomplex/models/physics/active_matter/_tumbler_view.py +23 -0
- skcomplex/models/physics/active_matter/_vicsek_particle.py +61 -0
- skcomplex/models/physics/celestial_mechanics/__init__.py +19 -0
- skcomplex/models/physics/celestial_mechanics/_dipoles.py +160 -0
- skcomplex/models/physics/celestial_mechanics/_kepler_body.py +76 -0
- skcomplex/models/physics/celestial_mechanics/_orbits.py +332 -0
- skcomplex/models/physics/celestial_mechanics/_rotating_frame_body.py +72 -0
- skcomplex/models/physics/celestial_mechanics/_sitnikov_body.py +54 -0
- skcomplex/models/physics/celestial_mechanics/types.py +6 -0
- skcomplex/models/physics/climate/__init__.py +60 -0
- skcomplex/models/physics/climate/_carbon_cycle.py +169 -0
- skcomplex/models/physics/climate/_climate_anomaly.py +55 -0
- skcomplex/models/physics/climate/_daisyworld.py +158 -0
- skcomplex/models/physics/climate/_delayed_oscillator.py +68 -0
- skcomplex/models/physics/climate/_early_warning.py +102 -0
- skcomplex/models/physics/climate/_energy_balance.py +207 -0
- skcomplex/models/physics/climate/_geodynamo.py +86 -0
- skcomplex/models/physics/climate/_ice_ages.py +179 -0
- skcomplex/models/physics/climate/_ice_albedo_climate.py +100 -0
- skcomplex/models/physics/climate/_latitude_band.py +156 -0
- skcomplex/models/physics/climate/_lorenz84.py +91 -0
- skcomplex/models/physics/climate/_lorenz96.py +67 -0
- skcomplex/models/physics/climate/_low_order.py +162 -0
- skcomplex/models/physics/climate/_net_energy.py +210 -0
- skcomplex/models/physics/climate/_ramped_fold.py +92 -0
- skcomplex/models/physics/climate/_saltzman_maasch.py +123 -0
- skcomplex/models/physics/climate/_soil.py +116 -0
- skcomplex/models/physics/climate/_stochastic_energy_balance.py +124 -0
- skcomplex/models/physics/climate/_tipping.py +141 -0
- skcomplex/models/physics/climate/_tipping_types.py +159 -0
- skcomplex/models/physics/climate/_van_der_pol_ice_ages.py +101 -0
- skcomplex/models/physics/climate/_variability.py +103 -0
- skcomplex/models/physics/common/__init__.py +6 -0
- skcomplex/models/physics/common/fields/__init__.py +14 -0
- skcomplex/models/physics/common/fields/_landau_energy.py +76 -0
- skcomplex/models/physics/common/fields/_phase_field.py +43 -0
- skcomplex/models/physics/common/fields/_swift_hohenberg_energy.py +74 -0
- skcomplex/models/physics/common/fields/_transports.py +119 -0
- skcomplex/models/physics/common/mechanics/__init__.py +5 -0
- skcomplex/models/physics/common/mechanics/_reflection.py +139 -0
- skcomplex/models/physics/common/oscillators/__init__.py +13 -0
- skcomplex/models/physics/common/oscillators/_kuramoto_coupling.py +140 -0
- skcomplex/models/physics/common/oscillators/_phase_oscillator.py +68 -0
- skcomplex/models/physics/common/oscillators/_sited_oscillator.py +55 -0
- skcomplex/models/physics/common/oscillators/_stuart_landau.py +106 -0
- skcomplex/models/physics/common/particles/__init__.py +28 -0
- skcomplex/models/physics/common/particles/_constant_force.py +65 -0
- skcomplex/models/physics/common/particles/_damping.py +72 -0
- skcomplex/models/physics/common/particles/_gravity.py +74 -0
- skcomplex/models/physics/common/particles/_harmonic_potential.py +77 -0
- skcomplex/models/physics/common/particles/_lammps.py +47 -0
- skcomplex/models/physics/common/particles/_langevin_thermostat.py +103 -0
- skcomplex/models/physics/common/particles/_lennard_jones.py +87 -0
- skcomplex/models/physics/common/particles/_mass_point.py +57 -0
- skcomplex/models/physics/common/particles/_potential_energy.py +56 -0
- skcomplex/models/physics/common/particles/_soft_sphere.py +82 -0
- skcomplex/models/physics/common/particles/_spring.py +78 -0
- skcomplex/models/physics/common/particles/_utils.py +25 -0
- skcomplex/models/physics/common/quantum/__init__.py +18 -0
- skcomplex/models/physics/common/quantum/_mode.py +46 -0
- skcomplex/models/physics/common/quantum/_quantum.py +127 -0
- skcomplex/models/physics/common/quantum/_qubit.py +61 -0
- skcomplex/models/physics/common/quantum/_site.py +49 -0
- skcomplex/models/physics/common/quantum/_spin.py +92 -0
- skcomplex/models/physics/common/spins/__init__.py +15 -0
- skcomplex/models/physics/common/spins/_ising_sampling.py +75 -0
- skcomplex/models/physics/common/spins/_potts_sampling.py +73 -0
- skcomplex/models/physics/common/spins/_spin_sampling.py +100 -0
- skcomplex/models/physics/common/spins/_thermal_sampling.py +105 -0
- skcomplex/models/physics/common/spins/_xy_sampling.py +67 -0
- skcomplex/models/physics/cosmology/__init__.py +8 -0
- skcomplex/models/physics/cosmology/_expansion.py +148 -0
- skcomplex/models/physics/criticality/__init__.py +29 -0
- skcomplex/models/physics/criticality/_absorbing.py +210 -0
- skcomplex/models/physics/criticality/_avalanche.py +69 -0
- skcomplex/models/physics/criticality/_crackling_noise.py +129 -0
- skcomplex/models/physics/criticality/_criticality.py +235 -0
- skcomplex/models/physics/criticality/_evolutionary_learning.py +231 -0
- skcomplex/models/physics/criticality/_fire.py +70 -0
- skcomplex/models/physics/criticality/_forest.py +55 -0
- skcomplex/models/physics/criticality/_learning.py +175 -0
- skcomplex/models/physics/criticality/_sandpile_cell.py +47 -0
- skcomplex/models/physics/fluids/__init__.py +49 -0
- skcomplex/models/physics/fluids/_bhatnagar_gross_krook.py +54 -0
- skcomplex/models/physics/fluids/_boussinesq.py +62 -0
- skcomplex/models/physics/fluids/_burgers.py +39 -0
- skcomplex/models/physics/fluids/_carleman_gas.py +61 -0
- skcomplex/models/physics/fluids/_flows.py +436 -0
- skcomplex/models/physics/fluids/_kinetic_equations.py +327 -0
- skcomplex/models/physics/fluids/_kinetics.py +147 -0
- skcomplex/models/physics/fluids/_kuramoto_sivashinsky.py +41 -0
- skcomplex/models/physics/fluids/_lattice_gases.py +217 -0
- skcomplex/models/physics/fluids/_marangoni.py +136 -0
- skcomplex/models/physics/fluids/_shallow_water.py +55 -0
- skcomplex/models/physics/fluids/_vorticity.py +56 -0
- skcomplex/models/physics/fluids/_wave_number.py +50 -0
- skcomplex/models/physics/heat/__init__.py +13 -0
- skcomplex/models/physics/heat/_cooling.py +96 -0
- skcomplex/models/physics/heat/_heat.py +182 -0
- skcomplex/models/physics/mechanics/__init__.py +93 -0
- skcomplex/models/physics/mechanics/_ballistic_pendulum.py +80 -0
- skcomplex/models/physics/mechanics/_bouncing_ball.py +51 -0
- skcomplex/models/physics/mechanics/_cart_pendulum.py +92 -0
- skcomplex/models/physics/mechanics/_cart_pendulum_interaction.py +57 -0
- skcomplex/models/physics/mechanics/_clock_pendulum.py +94 -0
- skcomplex/models/physics/mechanics/_clock_pendulum_interaction.py +60 -0
- skcomplex/models/physics/mechanics/_disc_billiard.py +90 -0
- skcomplex/models/physics/mechanics/_double_pendulum.py +95 -0
- skcomplex/models/physics/mechanics/_double_pendulum_interaction.py +53 -0
- skcomplex/models/physics/mechanics/_elastic_collision.py +78 -0
- skcomplex/models/physics/mechanics/_gyroscope.py +105 -0
- skcomplex/models/physics/mechanics/_gyroscope_interaction.py +57 -0
- skcomplex/models/physics/mechanics/_hanging_ball.py +65 -0
- skcomplex/models/physics/mechanics/_magnet.py +70 -0
- skcomplex/models/physics/mechanics/_mechanics.py +426 -0
- skcomplex/models/physics/mechanics/_parametric_pendulum.py +75 -0
- skcomplex/models/physics/mechanics/_parametric_pendulum_interaction.py +56 -0
- skcomplex/models/physics/mechanics/_pendulum.py +73 -0
- skcomplex/models/physics/mechanics/_pendulum_interaction.py +52 -0
- skcomplex/models/physics/mechanics/_pendulum_spring.py +68 -0
- skcomplex/models/physics/mechanics/_pendulums.py +547 -0
- skcomplex/models/physics/mechanics/_rotating_ball.py +66 -0
- skcomplex/models/physics/mechanics/_rotating_swing.py +100 -0
- skcomplex/models/physics/mechanics/_rotating_swing_interaction.py +70 -0
- skcomplex/models/physics/mechanics/_rotations.py +244 -0
- skcomplex/models/physics/mechanics/_springs.py +176 -0
- skcomplex/models/physics/mechanics/_support_spring.py +65 -0
- skcomplex/models/physics/mechanics/_wells.py +102 -0
- skcomplex/models/physics/nonlinear_oscillators/__init__.py +26 -0
- skcomplex/models/physics/nonlinear_oscillators/_adler_phase.py +73 -0
- skcomplex/models/physics/nonlinear_oscillators/_billiards.py +137 -0
- skcomplex/models/physics/nonlinear_oscillators/_duffing.py +78 -0
- skcomplex/models/physics/nonlinear_oscillators/_henon_heiles.py +57 -0
- skcomplex/models/physics/nonlinear_oscillators/_mushroom_billiard.py +96 -0
- skcomplex/models/physics/nonlinear_oscillators/_oscillators.py +313 -0
- skcomplex/models/physics/nonlinear_oscillators/_sinai_billiard.py +101 -0
- skcomplex/models/physics/nonlinear_oscillators/_van_der_pol.py +92 -0
- skcomplex/models/physics/oceanography/__init__.py +12 -0
- skcomplex/models/physics/oceanography/_gyres.py +145 -0
- skcomplex/models/physics/oceanography/_quasi_geostrophic_site.py +66 -0
- skcomplex/models/physics/oceanography/_thermohaline.py +133 -0
- skcomplex/models/physics/pattern_formation/__init__.py +18 -0
- skcomplex/models/physics/pattern_formation/_conserved.py +168 -0
- skcomplex/models/physics/pattern_formation/_ginzburg_landau.py +83 -0
- skcomplex/models/physics/pattern_formation/_ordering.py +183 -0
- skcomplex/models/physics/pattern_formation/_pattern_field.py +37 -0
- skcomplex/models/physics/pattern_formation/_patterns.py +135 -0
- skcomplex/models/physics/seismology/__init__.py +11 -0
- skcomplex/models/physics/seismology/_faults.py +118 -0
- skcomplex/models/physics/seismology/_spring_blocks.py +175 -0
- skcomplex/models/physics/soft_matter/__init__.py +76 -0
- skcomplex/models/physics/soft_matter/_anomalous.py +331 -0
- skcomplex/models/physics/soft_matter/_brownian.py +137 -0
- skcomplex/models/physics/soft_matter/_brownian_particle.py +58 -0
- skcomplex/models/physics/soft_matter/_colored_noise.py +137 -0
- skcomplex/models/physics/soft_matter/_continuous_time_walker.py +62 -0
- skcomplex/models/physics/soft_matter/_diffusion.py +418 -0
- skcomplex/models/physics/soft_matter/_double_well.py +57 -0
- skcomplex/models/physics/soft_matter/_flashing_sawtooth.py +82 -0
- skcomplex/models/physics/soft_matter/_fractional_walker.py +54 -0
- skcomplex/models/physics/soft_matter/_friction.py +214 -0
- skcomplex/models/physics/soft_matter/_levy_flier.py +54 -0
- skcomplex/models/physics/soft_matter/_levy_walker.py +67 -0
- skcomplex/models/physics/soft_matter/_modulated_particle.py +76 -0
- skcomplex/models/physics/soft_matter/_optical_trap.py +93 -0
- skcomplex/models/physics/soft_matter/_ratchets.py +163 -0
- skcomplex/models/physics/soft_matter/_scaled_walker.py +57 -0
- skcomplex/models/physics/soft_matter/_speckle_field.py +81 -0
- skcomplex/models/physics/soft_matter/_thermal_noise.py +52 -0
- skcomplex/models/physics/soft_matter/_tilted_washboard.py +70 -0
- skcomplex/models/physics/soft_matter/_transient_walker.py +61 -0
- skcomplex/models/physics/soft_matter/_traps.py +166 -0
- skcomplex/models/physics/soft_matter/_wall_particle.py +72 -0
- skcomplex/models/physics/statistical_mechanics/__init__.py +114 -0
- skcomplex/models/physics/statistical_mechanics/_absorbing_processes.py +156 -0
- skcomplex/models/physics/statistical_mechanics/_boltzmann_average.py +44 -0
- skcomplex/models/physics/statistical_mechanics/_boltzmann_sum.py +83 -0
- skcomplex/models/physics/statistical_mechanics/_bond_sampling.py +46 -0
- skcomplex/models/physics/statistical_mechanics/_bond_spin.py +76 -0
- skcomplex/models/physics/statistical_mechanics/_contact_site.py +85 -0
- skcomplex/models/physics/statistical_mechanics/_dephasing.py +59 -0
- skcomplex/models/physics/statistical_mechanics/_disk.py +36 -0
- skcomplex/models/physics/statistical_mechanics/_driven_particles.py +250 -0
- skcomplex/models/physics/statistical_mechanics/_energy_level.py +30 -0
- skcomplex/models/physics/statistical_mechanics/_exclusion_hops.py +76 -0
- skcomplex/models/physics/statistical_mechanics/_exclusion_site.py +61 -0
- skcomplex/models/physics/statistical_mechanics/_fully_connected_spins.py +232 -0
- skcomplex/models/physics/statistical_mechanics/_gases.py +156 -0
- skcomplex/models/physics/statistical_mechanics/_graph_spins.py +93 -0
- skcomplex/models/physics/statistical_mechanics/_ising_spin.py +63 -0
- skcomplex/models/physics/statistical_mechanics/_kinetic_temperature.py +66 -0
- skcomplex/models/physics/statistical_mechanics/_master_equations.py +171 -0
- skcomplex/models/physics/statistical_mechanics/_mattis_spin.py +79 -0
- skcomplex/models/physics/statistical_mechanics/_maxwell_boltzmann.py +96 -0
- skcomplex/models/physics/statistical_mechanics/_microstate.py +102 -0
- skcomplex/models/physics/statistical_mechanics/_order_parameter.py +90 -0
- skcomplex/models/physics/statistical_mechanics/_particle_site.py +41 -0
- skcomplex/models/physics/statistical_mechanics/_percolation.py +60 -0
- skcomplex/models/physics/statistical_mechanics/_percolation_site.py +73 -0
- skcomplex/models/physics/statistical_mechanics/_potts_spin.py +58 -0
- skcomplex/models/physics/statistical_mechanics/_processes.py +355 -0
- skcomplex/models/physics/statistical_mechanics/_q2r_spin.py +51 -0
- skcomplex/models/physics/statistical_mechanics/_quantum_spins.py +153 -0
- skcomplex/models/physics/statistical_mechanics/_random_energy.py +68 -0
- skcomplex/models/physics/statistical_mechanics/_reservoir.py +81 -0
- skcomplex/models/physics/statistical_mechanics/_spin_glasses.py +203 -0
- skcomplex/models/physics/statistical_mechanics/_spins.py +200 -0
- skcomplex/models/physics/statistical_mechanics/_susceptibility.py +112 -0
- skcomplex/models/physics/statistical_mechanics/_traps.py +135 -0
- skcomplex/models/physics/statistical_mechanics/_tree_node.py +48 -0
- skcomplex/models/physics/statistical_mechanics/_urns.py +107 -0
- skcomplex/models/physics/statistical_mechanics/_walker.py +81 -0
- skcomplex/models/physics/statistical_mechanics/_walker_view.py +20 -0
- skcomplex/models/physics/statistical_mechanics/_xxz_exchange.py +67 -0
- skcomplex/models/physics/statistical_mechanics/_xy_spin.py +58 -0
- skcomplex/models/physics/statistical_mechanics/_zeeman_field.py +56 -0
- skcomplex/models/physics/statistical_mechanics/_zero_range_hop.py +86 -0
- skcomplex/models/physics/statistical_mechanics/_zero_range_hops.py +81 -0
- skcomplex/models/physics/statistical_mechanics/_zone.py +78 -0
- skcomplex/models/physics/synchronization/__init__.py +64 -0
- skcomplex/models/physics/synchronization/_aggregate_averaging.py +63 -0
- skcomplex/models/physics/synchronization/_amplitude_death.py +278 -0
- skcomplex/models/physics/synchronization/_chaos.py +152 -0
- skcomplex/models/physics/synchronization/_diffusive_coupling.py +69 -0
- skcomplex/models/physics/synchronization/_edge_coupling.py +50 -0
- skcomplex/models/physics/synchronization/_hypergraphs.py +166 -0
- skcomplex/models/physics/synchronization/_integrate_and_fire_oscillator.py +80 -0
- skcomplex/models/physics/synchronization/_kuramoto.py +423 -0
- skcomplex/models/physics/synchronization/_link.py +46 -0
- skcomplex/models/physics/synchronization/_logistic_coupling.py +78 -0
- skcomplex/models/physics/synchronization/_logistic_node.py +59 -0
- skcomplex/models/physics/synchronization/_logistic_unit.py +43 -0
- skcomplex/models/physics/synchronization/_networks.py +184 -0
- skcomplex/models/physics/synchronization/_pulses.py +138 -0
- skcomplex/models/physics/synchronization/_rossler_oscillator.py +95 -0
- skcomplex/models/physics/synchronization/_swarmalator.py +48 -0
- skcomplex/models/physics/synchronization/_swarmalators.py +182 -0
- skcomplex/models/physics/synchronization/_utils.py +29 -0
- skcomplex/models/physics/synchronization/_winfree_mean_field.py +62 -0
- skcomplex/models/physics/waves/__init__.py +23 -0
- skcomplex/models/physics/waves/_charged.py +203 -0
- skcomplex/models/physics/waves/_driven_anchor.py +63 -0
- skcomplex/models/physics/waves/_lattice_hamiltonian.py +60 -0
- skcomplex/models/physics/waves/_position_dephasing.py +64 -0
- skcomplex/models/physics/waves/_quantum.py +125 -0
- skcomplex/models/physics/waves/_strings.py +169 -0
- skcomplex/models/physics/waves/_wave_function.py +79 -0
- skcomplex/models/physics/waves/_wave_string.py +52 -0
- skcomplex/models/social/__init__.py +1 -0
- skcomplex/models/social/cooperation/__init__.py +34 -0
- skcomplex/models/social/cooperation/_contributor.py +62 -0
- skcomplex/models/social/cooperation/_dilemma.py +56 -0
- skcomplex/models/social/cooperation/_hyperedge_goods.py +54 -0
- skcomplex/models/social/cooperation/_hypergraph_games.py +249 -0
- skcomplex/models/social/cooperation/_prisoner.py +56 -0
- skcomplex/models/social/cooperation/_prisoners_dilemma.py +126 -0
- skcomplex/models/social/cooperation/_public_goods.py +54 -0
- skcomplex/models/social/cooperation/_simplicial_dilemma.py +119 -0
- skcomplex/models/social/cooperation/_spatial_games.py +159 -0
- skcomplex/models/social/cooperation/_strategist.py +57 -0
- skcomplex/models/social/cooperation/_strategist_view.py +14 -0
- skcomplex/models/social/cooperation/_tournament.py +126 -0
- skcomplex/models/social/cooperation/_tournaments.py +87 -0
- skcomplex/models/social/crowds/__init__.py +46 -0
- skcomplex/models/social/crowds/_criminal_contagion.py +108 -0
- skcomplex/models/social/crowds/_criminality.py +223 -0
- skcomplex/models/social/crowds/_crowding.py +115 -0
- skcomplex/models/social/crowds/_deterrence.py +101 -0
- skcomplex/models/social/crowds/_evacuation.py +196 -0
- skcomplex/models/social/crowds/_guidance.py +69 -0
- skcomplex/models/social/crowds/_motivation.py +67 -0
- skcomplex/models/social/crowds/_pedestrians.py +85 -0
- skcomplex/models/social/crowds/_recruitment.py +90 -0
- skcomplex/models/social/crowds/_security_agents.py +48 -0
- skcomplex/models/social/crowds/_social_repulsion.py +86 -0
- skcomplex/models/social/crowds/_walking.py +186 -0
- skcomplex/models/social/crowds/_walls.py +69 -0
- skcomplex/models/social/language/__init__.py +13 -0
- skcomplex/models/social/language/_language.py +30 -0
- skcomplex/models/social/language/_least_effort.py +69 -0
- skcomplex/models/social/language/_word.py +39 -0
- skcomplex/models/social/language/_word_frequencies.py +48 -0
- skcomplex/models/social/opinion_dynamics/__init__.py +142 -0
- skcomplex/models/social/opinion_dynamics/_adopter.py +61 -0
- skcomplex/models/social/opinion_dynamics/_adopter_view.py +14 -0
- skcomplex/models/social/opinion_dynamics/_adoption.py +83 -0
- skcomplex/models/social/opinion_dynamics/_axelrod.py +160 -0
- skcomplex/models/social/opinion_dynamics/_believer.py +71 -0
- skcomplex/models/social/opinion_dynamics/_believer_view.py +16 -0
- skcomplex/models/social/opinion_dynamics/_bounded_confidence.py +126 -0
- skcomplex/models/social/opinion_dynamics/_citizen.py +49 -0
- skcomplex/models/social/opinion_dynamics/_citizen_view.py +12 -0
- skcomplex/models/social/opinion_dynamics/_club_member.py +78 -0
- skcomplex/models/social/opinion_dynamics/_coevolution.py +187 -0
- skcomplex/models/social/opinion_dynamics/_coevolving_voter.py +63 -0
- skcomplex/models/social/opinion_dynamics/_cognition.py +73 -0
- skcomplex/models/social/opinion_dynamics/_complex_agent.py +58 -0
- skcomplex/models/social/opinion_dynamics/_complex_agent_view.py +13 -0
- skcomplex/models/social/opinion_dynamics/_confidence_coupling.py +76 -0
- skcomplex/models/social/opinion_dynamics/_confident.py +50 -0
- skcomplex/models/social/opinion_dynamics/_conventions.py +44 -0
- skcomplex/models/social/opinion_dynamics/_conversations.py +116 -0
- skcomplex/models/social/opinion_dynamics/_cultural_influence.py +93 -0
- skcomplex/models/social/opinion_dynamics/_diffusion.py +205 -0
- skcomplex/models/social/opinion_dynamics/_discussant.py +60 -0
- skcomplex/models/social/opinion_dynamics/_discussant_view.py +14 -0
- skcomplex/models/social/opinion_dynamics/_discussions.py +51 -0
- skcomplex/models/social/opinion_dynamics/_encounters.py +48 -0
- skcomplex/models/social/opinion_dynamics/_hypergraph_consensus.py +106 -0
- skcomplex/models/social/opinion_dynamics/_influencee.py +70 -0
- skcomplex/models/social/opinion_dynamics/_influencee_view.py +16 -0
- skcomplex/models/social/opinion_dynamics/_kinetic_opinion.py +287 -0
- skcomplex/models/social/opinion_dynamics/_majority_voter.py +43 -0
- skcomplex/models/social/opinion_dynamics/_namer.py +53 -0
- skcomplex/models/social/opinion_dynamics/_namer_view.py +13 -0
- skcomplex/models/social/opinion_dynamics/_naming_games.py +68 -0
- skcomplex/models/social/opinion_dynamics/_opinion.py +39 -0
- skcomplex/models/social/opinion_dynamics/_persuader.py +52 -0
- skcomplex/models/social/opinion_dynamics/_persuader_view.py +12 -0
- skcomplex/models/social/opinion_dynamics/_persuasion.py +247 -0
- skcomplex/models/social/opinion_dynamics/_random_pairs.py +53 -0
- skcomplex/models/social/opinion_dynamics/_schedule.py +39 -0
- skcomplex/models/social/opinion_dynamics/_separation.py +71 -0
- skcomplex/models/social/opinion_dynamics/_social_impact.py +60 -0
- skcomplex/models/social/opinion_dynamics/_standardization.py +212 -0
- skcomplex/models/social/opinion_dynamics/_thinker.py +61 -0
- skcomplex/models/social/opinion_dynamics/_thinker_view.py +15 -0
- skcomplex/models/social/opinion_dynamics/_three_body_consensus.py +71 -0
- skcomplex/models/social/opinion_dynamics/_tie.py +21 -0
- skcomplex/models/social/opinion_dynamics/_variant_voter.py +67 -0
- skcomplex/models/social/opinion_dynamics/_variant_voter_view.py +14 -0
- skcomplex/models/social/opinion_dynamics/_variant_voting.py +63 -0
- skcomplex/models/social/opinion_dynamics/_village.py +61 -0
- skcomplex/models/social/opinion_dynamics/_village_view.py +14 -0
- skcomplex/models/social/opinion_dynamics/_voter.py +49 -0
- skcomplex/models/social/opinion_dynamics/_voter_imitation.py +48 -0
- skcomplex/models/social/opinion_dynamics/_voter_view.py +12 -0
- skcomplex/models/social/opinion_dynamics/_voters.py +197 -0
- skcomplex/models/social/organizations/__init__.py +68 -0
- skcomplex/models/social/organizations/_arms_race.py +34 -0
- skcomplex/models/social/organizations/_burden.py +38 -0
- skcomplex/models/social/organizations/_city_resident.py +41 -0
- skcomplex/models/social/organizations/_contender_view.py +14 -0
- skcomplex/models/social/organizations/_contest.py +32 -0
- skcomplex/models/social/organizations/_daily_movements.py +144 -0
- skcomplex/models/social/organizations/_eater.py +282 -0
- skcomplex/models/social/organizations/_eater_view.py +24 -0
- skcomplex/models/social/organizations/_employee.py +173 -0
- skcomplex/models/social/organizations/_employee_view.py +35 -0
- skcomplex/models/social/organizations/_employment.py +127 -0
- skcomplex/models/social/organizations/_execution.py +79 -0
- skcomplex/models/social/organizations/_gravity_contact.py +69 -0
- skcomplex/models/social/organizations/_hierarchies.py +174 -0
- skcomplex/models/social/organizations/_obesity.py +131 -0
- skcomplex/models/social/organizations/_premises.py +75 -0
- skcomplex/models/social/organizations/_premises_view.py +16 -0
- skcomplex/models/social/organizations/_queues.py +52 -0
- skcomplex/models/social/organizations/_restaurant.py +59 -0
- skcomplex/models/social/organizations/_restaurant_view.py +14 -0
- skcomplex/models/social/organizations/_sabotage.py +183 -0
- skcomplex/models/social/organizations/_supervisor.py +25 -0
- skcomplex/models/social/organizations/_task.py +65 -0
- skcomplex/models/social/organizations/_task_view.py +15 -0
- skcomplex/models/social/organizations/_trafficking.py +184 -0
- skcomplex/models/social/organizations/_traps.py +322 -0
- skcomplex/models/social/organizations/_traveller.py +55 -0
- skcomplex/models/social/organizations/_traveller_view.py +13 -0
- skcomplex/models/social/organizations/_urban_scaling.py +72 -0
- skcomplex/models/social/segregation/__init__.py +21 -0
- skcomplex/models/social/segregation/_block_moves.py +127 -0
- skcomplex/models/social/segregation/_blocks.py +111 -0
- skcomplex/models/social/segregation/_dweller.py +70 -0
- skcomplex/models/social/segregation/_dweller_view.py +16 -0
- skcomplex/models/social/segregation/_relocation.py +60 -0
- skcomplex/models/social/segregation/_resident.py +55 -0
- skcomplex/models/social/segregation/_resident_view.py +13 -0
- skcomplex/models/social/segregation/_schelling.py +75 -0
- skcomplex/models/social/spreading/__init__.py +37 -0
- skcomplex/models/social/spreading/_cascades.py +118 -0
- skcomplex/models/social/spreading/_exposure.py +166 -0
- skcomplex/models/social/spreading/_growing_word.py +55 -0
- skcomplex/models/social/spreading/_growing_word_view.py +13 -0
- skcomplex/models/social/spreading/_growth.py +52 -0
- skcomplex/models/social/spreading/_infective.py +55 -0
- skcomplex/models/social/spreading/_listeners.py +41 -0
- skcomplex/models/social/spreading/_participant.py +50 -0
- skcomplex/models/social/spreading/_rumour_contacts.py +81 -0
- skcomplex/models/social/spreading/_rumours.py +57 -0
- skcomplex/models/social/spreading/_simplicial.py +120 -0
- skcomplex/models/social/spreading/_simplicial_infection.py +64 -0
- skcomplex/models/social/spreading/_threshold_activation.py +50 -0
- skcomplex/models/social/spreading/_threshold_node_view.py +13 -0
- skcomplex/models/social/spreading/_writing.py +86 -0
- skcomplex/models/types.py +10 -0
- skcomplex/specs/__init__.py +198 -0
- skcomplex/specs/_accelerated_spec.py +46 -0
- skcomplex/specs/_agent_snapshot_spec.py +34 -0
- skcomplex/specs/_agent_state_spec.py +26 -0
- skcomplex/specs/_arguments_spec.py +60 -0
- skcomplex/specs/_axis_spec.py +59 -0
- skcomplex/specs/_base_record_spec.py +16 -0
- skcomplex/specs/_base_spec.py +73 -0
- skcomplex/specs/_base_structure_spec.py +173 -0
- skcomplex/specs/_batch_matching_spec.py +23 -0
- skcomplex/specs/_breakpoints_spec.py +58 -0
- skcomplex/specs/_call_spec.py +64 -0
- skcomplex/specs/_capacity_rows_spec.py +120 -0
- skcomplex/specs/_cardinality_spec.py +58 -0
- skcomplex/specs/_cascade_record_spec.py +36 -0
- skcomplex/specs/_clamp_spec.py +54 -0
- skcomplex/specs/_clause_spec.py +42 -0
- skcomplex/specs/_compiled_flow_spec.py +20 -0
- skcomplex/specs/_composed_rule_spec.py +33 -0
- skcomplex/specs/_continuous_matching_spec.py +48 -0
- skcomplex/specs/_control_solution_spec.py +54 -0
- skcomplex/specs/_control_spec.py +21 -0
- skcomplex/specs/_covariance_adaptation_spec.py +25 -0
- skcomplex/specs/_dataset_spec.py +85 -0
- skcomplex/specs/_delay_spec.py +27 -0
- skcomplex/specs/_dialect_spec.py +207 -0
- skcomplex/specs/_differential_evolution_spec.py +33 -0
- skcomplex/specs/_direction_spec.py +44 -0
- skcomplex/specs/_draw_spec.py +273 -0
- skcomplex/specs/_entry_spec.py +403 -0
- skcomplex/specs/_event_record_spec.py +37 -0
- skcomplex/specs/_evolution_strategy_spec.py +25 -0
- skcomplex/specs/_extremal_record_spec.py +32 -0
- skcomplex/specs/_fractional_rows_spec.py +33 -0
- skcomplex/specs/_fractional_state_spec.py +30 -0
- skcomplex/specs/_held_reduction_spec.py +29 -0
- skcomplex/specs/_hilbert_spec.py +75 -0
- skcomplex/specs/_hyperedge_reduction_spec.py +38 -0
- skcomplex/specs/_issue_spec.py +52 -0
- skcomplex/specs/_iterative_matching_spec.py +39 -0
- skcomplex/specs/_jump_channels_spec.py +40 -0
- skcomplex/specs/_jump_path_spec.py +29 -0
- skcomplex/specs/_layer_spec.py +47 -0
- skcomplex/specs/_layout_spec.py +158 -0
- skcomplex/specs/_local_operator_spec.py +72 -0
- skcomplex/specs/_lookup_spec.py +33 -0
- skcomplex/specs/_loop_spec.py +17 -0
- skcomplex/specs/_lowered_functions_spec.py +71 -0
- skcomplex/specs/_match_spec.py +37 -0
- skcomplex/specs/_matrix_law_spec.py +31 -0
- skcomplex/specs/_move_spec.py +69 -0
- skcomplex/specs/_neighbor_read_spec.py +83 -0
- skcomplex/specs/_neighbor_reduction_spec.py +39 -0
- skcomplex/specs/_network_rows_spec.py +124 -0
- skcomplex/specs/_network_snapshot_spec.py +61 -0
- skcomplex/specs/_noise_process_spec.py +41 -0
- skcomplex/specs/_objective_spec.py +39 -0
- skcomplex/specs/_observable_spec.py +79 -0
- skcomplex/specs/_operator_spec.py +170 -0
- skcomplex/specs/_orders_spec.py +16 -0
- skcomplex/specs/_outer_totalistic_spec.py +38 -0
- skcomplex/specs/_owners_spec.py +28 -0
- skcomplex/specs/_pair_read_spec.py +38 -0
- skcomplex/specs/_parameter_spec.py +81 -0
- skcomplex/specs/_parameters_spec.py +26 -0
- skcomplex/specs/_particle_swarm_spec.py +33 -0
- skcomplex/specs/_partner_spec.py +98 -0
- skcomplex/specs/_partner_switch_spec.py +39 -0
- skcomplex/specs/_phase_spec.py +61 -0
- skcomplex/specs/_phases_schedule_spec.py +59 -0
- skcomplex/specs/_plan_spec.py +18 -0
- skcomplex/specs/_planned_partition_spec.py +30 -0
- skcomplex/specs/_queue_spec.py +46 -0
- skcomplex/specs/_radius_spec.py +66 -0
- skcomplex/specs/_random_search_spec.py +51 -0
- skcomplex/specs/_read_spec.py +45 -0
- skcomplex/specs/_reduction_spec.py +48 -0
- skcomplex/specs/_renewal_record_spec.py +49 -0
- skcomplex/specs/_requirement_spec.py +32 -0
- skcomplex/specs/_role_spec.py +54 -0
- skcomplex/specs/_run_result_spec.py +52 -0
- skcomplex/specs/_run_state_spec.py +41 -0
- skcomplex/specs/_sampled_draw_spec.py +32 -0
- skcomplex/specs/_sampler_spec.py +57 -0
- skcomplex/specs/_samples_spec.py +29 -0
- skcomplex/specs/_schedule_spec.py +17 -0
- skcomplex/specs/_sector_spec.py +31 -0
- skcomplex/specs/_segment_spec.py +21 -0
- skcomplex/specs/_series_spec.py +29 -0
- skcomplex/specs/_signature_spec.py +55 -0
- skcomplex/specs/_snapshots_spec.py +56 -0
- skcomplex/specs/_stable_matching_spec.py +58 -0
- skcomplex/specs/_state_spec.py +138 -0
- skcomplex/specs/_step_spec.py +39 -0
- skcomplex/specs/_structure_state_spec.py +30 -0
- skcomplex/specs/_support_spec.py +76 -0
- skcomplex/specs/_symmetry_spec.py +59 -0
- skcomplex/specs/_table_spec.py +42 -0
- skcomplex/specs/_table_values_spec.py +36 -0
- skcomplex/specs/_tensor_spec.py +197 -0
- skcomplex/specs/_topology_request_spec.py +97 -0
- skcomplex/specs/_totalistic_spec.py +37 -0
- skcomplex/specs/_unknown_spec.py +22 -0
- skcomplex/specs/_validation_report_spec.py +62 -0
- skcomplex/specs/_variable_spec.py +124 -0
- skcomplex/specs/_visual_spec.py +30 -0
- skcomplex/specs/_weight_spec.py +16 -0
- skcomplex/specs/_wiener_block_spec.py +31 -0
- skcomplex/specs/_wiener_process_spec.py +54 -0
- skcomplex/types.py +140 -0
|
@@ -0,0 +1,1668 @@
|
|
|
1
|
+
"""Lower differential operators on fields to finite-difference stencils and graph Laplacians."""
|
|
2
|
+
|
|
3
|
+
# Author: Georgios Douzas <gdouzas@icloud.com>
|
|
4
|
+
# License: MIT
|
|
5
|
+
|
|
6
|
+
import functools
|
|
7
|
+
import re
|
|
8
|
+
from collections import defaultdict
|
|
9
|
+
from collections.abc import Callable, Mapping
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
import numpy.typing as npt
|
|
13
|
+
import scipy.fft
|
|
14
|
+
from sage.all__sagemath_symbolics import SR, Expression
|
|
15
|
+
from sage.modules.free_module_element import FreeModuleElement
|
|
16
|
+
from scipy.ndimage import convolve, map_coordinates
|
|
17
|
+
from scipy.signal import oaconvolve
|
|
18
|
+
from scipy.sparse import csr_matrix, diags, identity
|
|
19
|
+
from scipy.sparse.linalg import factorized
|
|
20
|
+
from skfem import Basis, ElementTetP1, ElementTriP1, asm
|
|
21
|
+
from skfem.models.poisson import laplace, mass
|
|
22
|
+
|
|
23
|
+
from ...core.elements import FieldElement
|
|
24
|
+
from ...core.laws import BaseLaw, BoundaryLaw, FluxLaw, NoiseLaw, RateLaw, UpdateLaw
|
|
25
|
+
from ...core.laws.utils import COORDINATE_PREFIX, INVERSION_BOUNDARIES, displacement, where
|
|
26
|
+
from ...core.spaces import (
|
|
27
|
+
AdjacencyNeighborhood,
|
|
28
|
+
LatticeNeighborhood,
|
|
29
|
+
LatticeSpace,
|
|
30
|
+
MeshSpace,
|
|
31
|
+
NetworkSpace,
|
|
32
|
+
PhaseSpace,
|
|
33
|
+
)
|
|
34
|
+
from ...errors import ValidationError
|
|
35
|
+
from ...specs import NeighborReadSpec, RunStateSpec
|
|
36
|
+
from ...types import Indices, IntTuple
|
|
37
|
+
from .._utils import domain_of, symbol
|
|
38
|
+
from ..problems import (
|
|
39
|
+
CollisionKernel,
|
|
40
|
+
DeclarationsSpec,
|
|
41
|
+
DiffusiveLimitSpec,
|
|
42
|
+
ExpressionPrinter,
|
|
43
|
+
KernelSpec,
|
|
44
|
+
ReferenceSpec,
|
|
45
|
+
)
|
|
46
|
+
from ..problems._field_operator_kernel import FieldOperatorKernel
|
|
47
|
+
from ..problems._law_kernel import LATTICE_BOUNDARIES, MODES
|
|
48
|
+
from ..types import ReadKind
|
|
49
|
+
from ._base import BaseLowering, BasePass
|
|
50
|
+
from ._compilation import Compilation
|
|
51
|
+
|
|
52
|
+
OPERATOR_NAMES = (
|
|
53
|
+
'laplacian',
|
|
54
|
+
'partial',
|
|
55
|
+
'upwind',
|
|
56
|
+
'inverse_helmholtz',
|
|
57
|
+
'convolve',
|
|
58
|
+
'shifted',
|
|
59
|
+
'reduce_axes',
|
|
60
|
+
'maximum_entropy',
|
|
61
|
+
'collision',
|
|
62
|
+
)
|
|
63
|
+
PHASE_OPERATOR_NAMES = ('reduce_axes', 'maximum_entropy', 'collision')
|
|
64
|
+
NEWTON_STEPS = 50
|
|
65
|
+
NEWTON_TOLERANCE = 1e-14
|
|
66
|
+
LARGEST_EXPONENT_CHANGE = 5.0
|
|
67
|
+
TIME = symbol('t')
|
|
68
|
+
PLANE = 2
|
|
69
|
+
SMALL_KERNEL = 7
|
|
70
|
+
WHOLE_SITE = 1e-9
|
|
71
|
+
SHIFTED_MODES = {'periodic': 'grid-wrap', 'zero-flux': 'reflect', 'fixed': 'grid-constant'}
|
|
72
|
+
FILTER_MODES = {'periodic': 'wrap', 'zero-flux': 'reflect', 'fixed': 'constant'}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class FieldLowering(BaseLowering[list[BaseLaw]]):
|
|
76
|
+
"""Lowering of the differential operators in the laws of one component to stencils, with the symbols they read.
|
|
77
|
+
|
|
78
|
+
`prepare(compilation)` reads the fields and the initial values of the compilation, and `run(laws)` returns the laws
|
|
79
|
+
with every operator replaced by its stencil, noting the stable steps of the Laplacians of rate laws.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
spec:
|
|
83
|
+
The kernel spec of the component, which `_apply_references` replaces by a copy with the neighbour reads
|
|
84
|
+
and the derived values.
|
|
85
|
+
|
|
86
|
+
Attributes:
|
|
87
|
+
fields_:
|
|
88
|
+
The field of every member entry by entry name.
|
|
89
|
+
|
|
90
|
+
initial_:
|
|
91
|
+
The initial value of every symbol that can be evaluated, for stability limits.
|
|
92
|
+
|
|
93
|
+
shifted_:
|
|
94
|
+
The symbol and offset every neighbour read reads.
|
|
95
|
+
|
|
96
|
+
derived_:
|
|
97
|
+
The field and the derived read of every spectral or finite element operator.
|
|
98
|
+
|
|
99
|
+
limits_:
|
|
100
|
+
The stable steps of the explicit Laplacians of finite-difference fields.
|
|
101
|
+
|
|
102
|
+
volume_limits_:
|
|
103
|
+
The stable steps of the Laplacians of finite-volume fields, as functions of the parameters.
|
|
104
|
+
|
|
105
|
+
written_:
|
|
106
|
+
The lowered value and the value as written of every law, by the entry name and column of its targets.
|
|
107
|
+
|
|
108
|
+
tables_:
|
|
109
|
+
The neighbour tables, by their axis, offset, boundary, and space.
|
|
110
|
+
|
|
111
|
+
solution_boundaries_:
|
|
112
|
+
The boundary condition given to an inversion, by the symbol of its solution.
|
|
113
|
+
|
|
114
|
+
cross_section_:
|
|
115
|
+
The cross-section of the collision law being lowered, or `None`.
|
|
116
|
+
|
|
117
|
+
applied_:
|
|
118
|
+
The lowered value of every operator call so far, by its name, its lowered operands, and the cross-section,
|
|
119
|
+
so an identical call shares one value.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
fields_: Mapping[str, FieldElement]
|
|
123
|
+
initial_: Mapping[Expression, float]
|
|
124
|
+
shifted_: dict[Expression, tuple[Expression, IntTuple | int]]
|
|
125
|
+
derived_: dict[Expression, tuple[FieldElement, FieldOperatorKernel]]
|
|
126
|
+
limits_: list[float]
|
|
127
|
+
volume_limits_: list[DiffusiveLimitSpec]
|
|
128
|
+
written_: dict[tuple[str, int], list[tuple[Expression, Expression]]]
|
|
129
|
+
tables_: dict[tuple[object, ...], tuple[Indices, float | None]]
|
|
130
|
+
solution_boundaries_: dict[Expression, tuple[str, object]]
|
|
131
|
+
cross_section_: Callable[..., object] | None
|
|
132
|
+
applied_: dict[tuple[object, ...], Expression]
|
|
133
|
+
|
|
134
|
+
def __init__(self, spec: KernelSpec) -> None:
|
|
135
|
+
self.spec = spec
|
|
136
|
+
|
|
137
|
+
def _prepare(self, context: Compilation | None) -> None:
|
|
138
|
+
"""Read the fields and the initial values of the compilation, with no stencil yet.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
context:
|
|
142
|
+
The compilation.
|
|
143
|
+
|
|
144
|
+
Raises:
|
|
145
|
+
ValidationError:
|
|
146
|
+
The compilation has no layout yet.
|
|
147
|
+
"""
|
|
148
|
+
super()._prepare(context)
|
|
149
|
+
declarations = self.compilation_.layout
|
|
150
|
+
if declarations is None:
|
|
151
|
+
error_msg = 'The compilation has no layout yet. Lower differential operators after the layout pass.'
|
|
152
|
+
raise ValidationError(error_msg)
|
|
153
|
+
self.fields_ = self._field_entries(declarations)
|
|
154
|
+
self.initial_ = self._initial_values(self.spec, declarations)
|
|
155
|
+
self.shifted_, self.derived_, self.tables_, self.solution_boundaries_, self.applied_ = {}, {}, {}, {}, {}
|
|
156
|
+
self.limits_, self.volume_limits_ = [], []
|
|
157
|
+
self.written_ = defaultdict(list)
|
|
158
|
+
self.cross_section_ = None
|
|
159
|
+
|
|
160
|
+
def _run(self, inputs: list[BaseLaw] | None) -> None:
|
|
161
|
+
"""Set laws whose differential operators are lowered, noting the stable steps of rate laws.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
inputs:
|
|
165
|
+
The laws of the component.
|
|
166
|
+
"""
|
|
167
|
+
result: list[BaseLaw] = []
|
|
168
|
+
for law in inputs or []:
|
|
169
|
+
if isinstance(law, FluxLaw) and self._law_has_operators(law):
|
|
170
|
+
result.append(BasePass._replaced(law, flux=[self._lower(SR(item)) for item in self._components(law)]))
|
|
171
|
+
continue
|
|
172
|
+
if not isinstance(law, RateLaw | NoiseLaw | UpdateLaw | BoundaryLaw) or not self._has_operators(law.value):
|
|
173
|
+
result.append(law)
|
|
174
|
+
continue
|
|
175
|
+
if isinstance(law, RateLaw):
|
|
176
|
+
self._note_limit(law.value)
|
|
177
|
+
self.cross_section_ = law.cross_section if isinstance(law, RateLaw) else None
|
|
178
|
+
lowered = self._lower(law.value)
|
|
179
|
+
if isinstance(law.value, Expression):
|
|
180
|
+
for reference in self.spec._target_references(law._get_targets()[0]):
|
|
181
|
+
self.written_[(reference.entry.name, reference.column)].append((lowered, law.value))
|
|
182
|
+
result.append(BasePass._replaced(law, value=lowered))
|
|
183
|
+
self.lowered_ = result
|
|
184
|
+
|
|
185
|
+
@staticmethod
|
|
186
|
+
def _field_entries(declarations: DeclarationsSpec) -> dict[str, FieldElement]:
|
|
187
|
+
"""Return the fields by the name of each of their entries."""
|
|
188
|
+
return {
|
|
189
|
+
entry.name: block.node.component
|
|
190
|
+
for block in declarations.blocks.values()
|
|
191
|
+
if isinstance(block.node.component, FieldElement)
|
|
192
|
+
for entry in block.entries.values()
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def _initial_values(spec: KernelSpec, declarations: DeclarationsSpec) -> dict[Expression, float]:
|
|
197
|
+
"""Return the initial value of every symbol of a component, the first member's for groups."""
|
|
198
|
+
states = np.concatenate([np.zeros(0), *declarations.initial_states])
|
|
199
|
+
parameters = np.concatenate([np.zeros(0), *declarations.initial_parameters])
|
|
200
|
+
return {
|
|
201
|
+
item: float((states if reference.is_state else parameters)[reference.entry.start + reference.column])
|
|
202
|
+
for item, reference in spec.references.items()
|
|
203
|
+
if reference.entry.start + reference.column < (states if reference.is_state else parameters).size
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
def _known_reference(self, item: Expression) -> ReferenceSpec:
|
|
207
|
+
"""Return the reference of a symbol of the spec, raising an error for a symbol the spec does not read.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
item:
|
|
211
|
+
The symbol.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
reference:
|
|
215
|
+
The reference of the symbol.
|
|
216
|
+
|
|
217
|
+
Raises:
|
|
218
|
+
ValidationError:
|
|
219
|
+
The spec does not read the symbol.
|
|
220
|
+
"""
|
|
221
|
+
reference = self._reference_of(item, self.spec)
|
|
222
|
+
if reference is None:
|
|
223
|
+
error_msg = f'A law of {self.spec.owner} reads {item}, which is not a state or parameter of its namespace.'
|
|
224
|
+
raise ValidationError(error_msg)
|
|
225
|
+
return reference
|
|
226
|
+
|
|
227
|
+
def _field_of(self, item: Expression) -> FieldElement | None:
|
|
228
|
+
"""Return the field whose member a symbol reads, or `None` for a single value."""
|
|
229
|
+
reference = self._known_reference(item)
|
|
230
|
+
if reference.source is not ReadKind.MEMBER:
|
|
231
|
+
return None
|
|
232
|
+
found = self.fields_.get(reference.entry.name)
|
|
233
|
+
if found is None:
|
|
234
|
+
error_msg = (
|
|
235
|
+
f'A law of {self.spec.owner} applies a differential operator to {item}, which is not a state or '
|
|
236
|
+
'parameter of a field. Create the group with `FieldElement`.'
|
|
237
|
+
)
|
|
238
|
+
raise ValidationError(error_msg)
|
|
239
|
+
return found
|
|
240
|
+
|
|
241
|
+
def _table(
|
|
242
|
+
self,
|
|
243
|
+
item: Expression,
|
|
244
|
+
place: FieldElement,
|
|
245
|
+
offset: IntTuple | int,
|
|
246
|
+
) -> tuple[Indices, float | None, int | None]:
|
|
247
|
+
"""Return the neighbour table, the fixed value, and the mode of a symbol at an offset."""
|
|
248
|
+
reference = self._known_reference(item)
|
|
249
|
+
variable = reference.entry.name.rpartition('.')[2]
|
|
250
|
+
if reference.is_state:
|
|
251
|
+
kind, value = place._get_boundary(variable, reference.column)
|
|
252
|
+
else:
|
|
253
|
+
kind, value = (
|
|
254
|
+
'periodic' if getattr(place.space, 'boundary', 'periodic') == 'periodic' else 'zero-flux',
|
|
255
|
+
0.0,
|
|
256
|
+
)
|
|
257
|
+
key = (id(place), kind, value, offset)
|
|
258
|
+
if key not in self.tables_:
|
|
259
|
+
space = place.space
|
|
260
|
+
if isinstance(space, NetworkSpace):
|
|
261
|
+
table = space._index_table(AdjacencyNeighborhood())
|
|
262
|
+
sites = np.arange(table.shape[0])[:, None]
|
|
263
|
+
self.tables_[key] = (np.where(table == table.shape[0], sites, table)[:, offset], None)
|
|
264
|
+
else:
|
|
265
|
+
if not isinstance(space, LatticeSpace) or isinstance(offset, int) or not isinstance(value, float):
|
|
266
|
+
error_msg = (
|
|
267
|
+
f'A law of {self.spec.owner} reads {item} at a lattice offset, which needs a field on a '
|
|
268
|
+
'lattice with a number outside fixed edges.'
|
|
269
|
+
)
|
|
270
|
+
raise ValidationError(error_msg)
|
|
271
|
+
lattice = space._with_edges(LATTICE_BOUNDARIES[kind], value)
|
|
272
|
+
table = lattice._index_table(LatticeNeighborhood((offset,)))[:, 0]
|
|
273
|
+
self.tables_[key] = (table, value if kind == 'fixed' else None)
|
|
274
|
+
table, ghost = self.tables_[key]
|
|
275
|
+
return table, ghost, self._read_mode(place.space, kind, offset)
|
|
276
|
+
|
|
277
|
+
def _shift(self, expression: Expression, offset: IntTuple | int) -> Expression:
|
|
278
|
+
"""Return an expression read at a neighbouring site of every member.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
expression:
|
|
282
|
+
The expression of member symbols, possibly already shifted.
|
|
283
|
+
|
|
284
|
+
offset:
|
|
285
|
+
The lattice offset, or the network neighbour slot.
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
shifted:
|
|
289
|
+
The expression in symbols that read the neighbour.
|
|
290
|
+
"""
|
|
291
|
+
expression = SR(expression)
|
|
292
|
+
replacements = {}
|
|
293
|
+
for item in expression.variables():
|
|
294
|
+
base, current = self.shifted_.get(item, (item, None))
|
|
295
|
+
if base in self.derived_:
|
|
296
|
+
replacements[item] = self._shifted_derived(base, self._total_offset(current, offset))
|
|
297
|
+
continue
|
|
298
|
+
reference = self._reference_of(base, self.spec)
|
|
299
|
+
if reference is None:
|
|
300
|
+
continue
|
|
301
|
+
if reference.source is ReadKind.NEIGHBOR and base == item and base not in self.shifted_:
|
|
302
|
+
error_msg = (
|
|
303
|
+
f'A law of {self.spec.owner} differentiates {base}, a field over position read on a phase space, '
|
|
304
|
+
'by a stencil. Use the finite-volume discretization, whose fluxes read it cell by cell.'
|
|
305
|
+
)
|
|
306
|
+
raise ValidationError(error_msg)
|
|
307
|
+
place = self._field_of(base)
|
|
308
|
+
if place is None:
|
|
309
|
+
continue
|
|
310
|
+
total = self._total_offset(current, offset)
|
|
311
|
+
if not isinstance(total, int) and not any(total):
|
|
312
|
+
replacements[item] = base
|
|
313
|
+
continue
|
|
314
|
+
name = f'{base}__{self._tag(total)}'
|
|
315
|
+
target = symbol(name, domain_of(base))
|
|
316
|
+
if self._reference_of(target, self.spec) is None:
|
|
317
|
+
reference = self._known_reference(base)
|
|
318
|
+
table, ghost, mode = self._table(base, place, total)
|
|
319
|
+
space = place.space
|
|
320
|
+
lattice = space if isinstance(space, LatticeSpace) and mode is not None else None
|
|
321
|
+
read = NeighborReadSpec(
|
|
322
|
+
table,
|
|
323
|
+
ghost,
|
|
324
|
+
None if lattice is None else lattice.shape_,
|
|
325
|
+
total if lattice is not None and not isinstance(total, int) else None,
|
|
326
|
+
mode or 0,
|
|
327
|
+
)
|
|
328
|
+
self._add_reference(
|
|
329
|
+
self.spec,
|
|
330
|
+
target,
|
|
331
|
+
ReferenceSpec(reference.entry, reference.is_state, reference.column, ReadKind.NEIGHBOR, read),
|
|
332
|
+
)
|
|
333
|
+
self.shifted_[target] = (base, total)
|
|
334
|
+
replacements[item] = target
|
|
335
|
+
return expression.subs(replacements)
|
|
336
|
+
|
|
337
|
+
def _read_mode(self, space: object, kind: str, offset: IntTuple | int) -> int | None:
|
|
338
|
+
"""Return the mode of the edges a read at an offset crosses, or `None` when it crosses edges of two kinds."""
|
|
339
|
+
if not isinstance(space, PhaseSpace) or isinstance(offset, int):
|
|
340
|
+
return MODES[kind]
|
|
341
|
+
kinds = {
|
|
342
|
+
kind if axis in space.position_axes_ else ('periodic' if space.axes_periodic_[axis] else 'zero-flux')
|
|
343
|
+
for axis in range(space.n_dim_)
|
|
344
|
+
if offset[axis]
|
|
345
|
+
}
|
|
346
|
+
return MODES[kinds.pop() if kinds else kind] if len(kinds) < PLANE else None
|
|
347
|
+
|
|
348
|
+
def _total_offset(self, current: IntTuple | int | None, offset: IntTuple | int) -> IntTuple | int:
|
|
349
|
+
"""Return the offset of a read at an offset from a read that is already shifted."""
|
|
350
|
+
if isinstance(offset, int) or isinstance(current, int):
|
|
351
|
+
if current is not None:
|
|
352
|
+
error_msg = f'A law of {self.spec.owner} nests operators on a network, which only take one step.'
|
|
353
|
+
raise ValidationError(error_msg)
|
|
354
|
+
return offset
|
|
355
|
+
return tuple(a + b for a, b in zip(current or (0,) * len(offset), offset, strict=True))
|
|
356
|
+
|
|
357
|
+
def _boundaries(self, expression: Expression) -> list[tuple[str, object]]:
|
|
358
|
+
"""Return the boundary conditions of the field states an expression reads, through derived values."""
|
|
359
|
+
found = []
|
|
360
|
+
for item in SR(expression).variables():
|
|
361
|
+
if item in self.solution_boundaries_:
|
|
362
|
+
found.append(self.solution_boundaries_[item])
|
|
363
|
+
continue
|
|
364
|
+
if item in self.derived_:
|
|
365
|
+
found += self._boundaries(self.derived_[item][1].operand)
|
|
366
|
+
continue
|
|
367
|
+
base = self.shifted_.get(item, (item, None))[0]
|
|
368
|
+
reference = self._reference_of(base, self.spec)
|
|
369
|
+
if reference is None or not reference.is_state or reference.source is not ReadKind.MEMBER:
|
|
370
|
+
continue
|
|
371
|
+
place = self._field_of(base)
|
|
372
|
+
if place is not None:
|
|
373
|
+
found.append(place._get_boundary(reference.entry.name.rpartition('.')[2], reference.column))
|
|
374
|
+
return found
|
|
375
|
+
|
|
376
|
+
def _boundary(self, expression: Expression, place: FieldElement) -> tuple[str, object]:
|
|
377
|
+
"""Return the one boundary condition of the field states an expression reads, or the edges of the space."""
|
|
378
|
+
found = set(self._boundaries(expression))
|
|
379
|
+
if len(found) > 1:
|
|
380
|
+
error_msg = (
|
|
381
|
+
f'A law of {self.spec.owner} applies a nonlocal operator to {expression}, whose states have different '
|
|
382
|
+
'boundary conditions. Give the states of the operand one boundary condition, or give an inversion '
|
|
383
|
+
'the boundary of its solution.'
|
|
384
|
+
)
|
|
385
|
+
raise ValidationError(error_msg)
|
|
386
|
+
return found.pop() if found else place._get_boundary('')
|
|
387
|
+
|
|
388
|
+
def _neighbor_table(self, place: FieldElement, kind: str, value: object, offset: IntTuple | int) -> Indices:
|
|
389
|
+
"""Return the neighbour of every site at an offset, with the number of sites for reads beyond fixed edges."""
|
|
390
|
+
space = place.space
|
|
391
|
+
if isinstance(space, NetworkSpace) and isinstance(offset, int):
|
|
392
|
+
table = space._index_table(AdjacencyNeighborhood())
|
|
393
|
+
sites = np.arange(table.shape[0])[:, None]
|
|
394
|
+
return np.asarray(np.where(table == table.shape[0], sites, table)[:, offset], dtype=np.intp)
|
|
395
|
+
if not isinstance(space, LatticeSpace) or isinstance(offset, int) or not isinstance(value, float):
|
|
396
|
+
error_msg = (
|
|
397
|
+
f'A law of {self.spec.owner} reads a nonlocal value at a neighbour, which needs a field on a lattice '
|
|
398
|
+
'or a network with a number outside fixed edges.'
|
|
399
|
+
)
|
|
400
|
+
raise ValidationError(error_msg)
|
|
401
|
+
lattice = space._with_edges(LATTICE_BOUNDARIES[kind], value)
|
|
402
|
+
return np.asarray(lattice._index_table(LatticeNeighborhood((offset,)))[:, 0], dtype=np.intp)
|
|
403
|
+
|
|
404
|
+
def _shifted_derived(self, base: Expression, total: IntTuple | int) -> Expression:
|
|
405
|
+
"""Return the symbol of a derived value read at a neighbouring site, indexing its values by the neighbour table.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
base:
|
|
409
|
+
The symbol of the derived value.
|
|
410
|
+
|
|
411
|
+
total:
|
|
412
|
+
The lattice offset, or the network neighbour slot.
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
shifted:
|
|
416
|
+
The symbol of the derived value at the neighbour.
|
|
417
|
+
"""
|
|
418
|
+
if not isinstance(total, int) and not any(total):
|
|
419
|
+
return base
|
|
420
|
+
target = symbol(f'{base}__{self._tag(total)}')
|
|
421
|
+
if target in self.derived_:
|
|
422
|
+
return target
|
|
423
|
+
place = self.derived_[base][0]
|
|
424
|
+
kind, value = self._boundary(base, place)
|
|
425
|
+
table = self._neighbor_table(place, kind, value, total)
|
|
426
|
+
size = table.shape[0]
|
|
427
|
+
inside = table < size
|
|
428
|
+
matrix = csr_matrix((np.ones(inside.sum()), (np.flatnonzero(inside), table[inside])), shape=(size, size))
|
|
429
|
+
ghost = float(value) if kind == 'fixed' and isinstance(value, float) else 0.0
|
|
430
|
+
|
|
431
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
432
|
+
return np.append(values, ghost)[table]
|
|
433
|
+
|
|
434
|
+
read = FieldOperatorKernel(operand=base, symbols=[base], apply=apply, matrix=matrix).check().prepare()
|
|
435
|
+
self.shifted_[target] = (base, total)
|
|
436
|
+
return self._derived(place, read, target)
|
|
437
|
+
|
|
438
|
+
def _places(self, expression: Expression) -> dict[int, FieldElement]:
|
|
439
|
+
"""Return the fields an expression reads, through member symbols, neighbour reads, and derived values."""
|
|
440
|
+
places: dict[int, FieldElement] = {}
|
|
441
|
+
place: FieldElement | None
|
|
442
|
+
for item in SR(expression).variables():
|
|
443
|
+
if item in self.derived_:
|
|
444
|
+
place = self.derived_[item][0]
|
|
445
|
+
else:
|
|
446
|
+
base = self.shifted_.get(item, (item, None))[0]
|
|
447
|
+
place = self._field_of(base) if self._reference_of(base, self.spec) is not None else None
|
|
448
|
+
if place is not None:
|
|
449
|
+
places[id(place)] = place
|
|
450
|
+
return places
|
|
451
|
+
|
|
452
|
+
def _place(self, expression: Expression) -> FieldElement:
|
|
453
|
+
"""Return the one field an expression reads, or raise an error."""
|
|
454
|
+
places = self._places(expression)
|
|
455
|
+
discretizations = {place.discretization for place in places.values()}
|
|
456
|
+
spaces = {id(place.space) for place in places.values()}
|
|
457
|
+
if len(spaces) != 1 or len(discretizations) != 1:
|
|
458
|
+
error_msg = (
|
|
459
|
+
f'A law of {self.spec.owner} applies an operator to {expression}, which reads {len(spaces)} fields. An '
|
|
460
|
+
'operator acts on the states of fields of one space and one discretization.'
|
|
461
|
+
)
|
|
462
|
+
raise ValidationError(error_msg)
|
|
463
|
+
return next(iter(places.values()))
|
|
464
|
+
|
|
465
|
+
def _space(self, expression: Expression) -> LatticeSpace | NetworkSpace:
|
|
466
|
+
"""Return the space of the fields an expression reads."""
|
|
467
|
+
spaces = {id(place.space): place.space for place in self._places(expression).values()}
|
|
468
|
+
if len(spaces) != 1:
|
|
469
|
+
error_msg = (
|
|
470
|
+
f'A law of {self.spec.owner} applies an operator to {expression}, which reads {len(spaces)} fields. An '
|
|
471
|
+
'operator acts on the states of fields of one space.'
|
|
472
|
+
)
|
|
473
|
+
raise ValidationError(error_msg)
|
|
474
|
+
space = next(iter(spaces.values()))
|
|
475
|
+
if not isinstance(space, LatticeSpace | NetworkSpace):
|
|
476
|
+
error_msg = (
|
|
477
|
+
f'A law of {self.spec.owner} applies a stencil to {expression}, which lives on a mesh. Use the '
|
|
478
|
+
'finite-element discretization.'
|
|
479
|
+
)
|
|
480
|
+
raise ValidationError(error_msg)
|
|
481
|
+
return space
|
|
482
|
+
|
|
483
|
+
def _laplacian(self, expression: Expression) -> Expression:
|
|
484
|
+
"""Return the stencil of the Laplacian of an expression."""
|
|
485
|
+
space = self._space(expression)
|
|
486
|
+
if isinstance(space, NetworkSpace):
|
|
487
|
+
width = space._index_table(AdjacencyNeighborhood()).shape[1]
|
|
488
|
+
return sum((self._shift(expression, slot) - expression for slot in range(width)), SR(0))
|
|
489
|
+
total = SR(0)
|
|
490
|
+
for axis in range(space.n_dim_):
|
|
491
|
+
step = tuple(int(axis == other) for other in range(space.n_dim_))
|
|
492
|
+
back = tuple(-item for item in step)
|
|
493
|
+
total += (self._shift(expression, step) + self._shift(expression, back) - 2 * expression) / (
|
|
494
|
+
space.spacings_[axis] ** 2
|
|
495
|
+
)
|
|
496
|
+
return total
|
|
497
|
+
|
|
498
|
+
def _lattice(self, expression: Expression, axis: int, name: str) -> tuple[LatticeSpace, IntTuple, IntTuple]:
|
|
499
|
+
"""Return the lattice of an expression and the unit offsets along an axis."""
|
|
500
|
+
space = self._space(expression)
|
|
501
|
+
if not isinstance(space, LatticeSpace) or not 0 <= axis < space.n_dim_:
|
|
502
|
+
error_msg = (
|
|
503
|
+
f'A law of {self.spec.owner} takes the {name} of {expression} along axis {axis}, which needs a lattice.'
|
|
504
|
+
)
|
|
505
|
+
raise ValidationError(error_msg)
|
|
506
|
+
step = tuple(int(axis == other) for other in range(space.n_dim_))
|
|
507
|
+
return space, step, tuple(-item for item in step)
|
|
508
|
+
|
|
509
|
+
def _lower(self, expression: object) -> object:
|
|
510
|
+
"""Return an expression with every operator replaced by its stencil, innermost first.
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
expression:
|
|
514
|
+
The value of a law.
|
|
515
|
+
|
|
516
|
+
Returns:
|
|
517
|
+
lowered:
|
|
518
|
+
The value with stencils.
|
|
519
|
+
"""
|
|
520
|
+
if not isinstance(expression, Expression) or not self._has_operators(expression):
|
|
521
|
+
return expression
|
|
522
|
+
call = expression
|
|
523
|
+
operator = call.operator()
|
|
524
|
+
operands = [self._lower(item) for item in call.operands()]
|
|
525
|
+
name = getattr(operator, 'name', lambda: '')()
|
|
526
|
+
if name not in OPERATOR_NAMES:
|
|
527
|
+
return operator(*operands)
|
|
528
|
+
key = (name, *operands, id(self.cross_section_))
|
|
529
|
+
if key not in self.applied_:
|
|
530
|
+
self.applied_[key] = self._lowered_call(name, operands)
|
|
531
|
+
return self.applied_[key]
|
|
532
|
+
|
|
533
|
+
def _lowered_call(self, name: str, operands: list[object]) -> Expression:
|
|
534
|
+
"""Return the value of one operator whose operands are lowered."""
|
|
535
|
+
if name == 'shifted':
|
|
536
|
+
return self._shifted(SR(operands[0]), [SR(item) for item in operands[1:]])
|
|
537
|
+
if name in {'laplacian', 'partial', 'upwind'} and not SR(operands[0]).variables():
|
|
538
|
+
return SR(0)
|
|
539
|
+
place = self._place(SR(operands[0]))
|
|
540
|
+
if name in PHASE_OPERATOR_NAMES:
|
|
541
|
+
return self._phase_operator(name, [SR(item) for item in operands], place)
|
|
542
|
+
if name == 'convolve':
|
|
543
|
+
return self._convolve(SR(operands[0]), SR(operands[1]), SR(operands[2]), place)
|
|
544
|
+
return self._discretized(name, operands, place)
|
|
545
|
+
|
|
546
|
+
def _phase_operator(self, name: str, operands: list[Expression], place: FieldElement) -> Expression:
|
|
547
|
+
"""Return the value of an operator over the class axes of a phase space."""
|
|
548
|
+
if name == 'reduce_axes':
|
|
549
|
+
return self._reduced(operands[0], operands[1:], place)
|
|
550
|
+
if name == 'maximum_entropy':
|
|
551
|
+
return self._equilibrium(operands[0], int(operands[1]), operands[2:], place)
|
|
552
|
+
return self._collision(operands[0], place)
|
|
553
|
+
|
|
554
|
+
def _phase_space(self, operand: Expression, place: FieldElement) -> PhaseSpace:
|
|
555
|
+
"""Return the phase space of a field whose class axes an operator reads, raising an error for another space."""
|
|
556
|
+
if not isinstance(place.space, PhaseSpace):
|
|
557
|
+
error_msg = (
|
|
558
|
+
f'A law of {self.spec.owner} reduces {operand} over class axes, but its field lives on '
|
|
559
|
+
f'{type(place.space).__name__}. Give the field a `PhaseSpace`.'
|
|
560
|
+
)
|
|
561
|
+
raise ValidationError(error_msg)
|
|
562
|
+
return place.space
|
|
563
|
+
|
|
564
|
+
def _axes_of(self, coordinates: list[Expression], space: PhaseSpace) -> tuple[int, ...]:
|
|
565
|
+
"""Return the indices of the class axes of their coordinates, raising an error for an axis the space lacks."""
|
|
566
|
+
names = [str(item).removeprefix(COORDINATE_PREFIX) for item in coordinates]
|
|
567
|
+
missing = [name for name in names if name not in space.class_axes_]
|
|
568
|
+
if missing:
|
|
569
|
+
error_msg = (
|
|
570
|
+
f'A law of {self.spec.owner} reads the class axes {missing}, but the phase space holds the axes '
|
|
571
|
+
f'{list(space.class_axes_)}.'
|
|
572
|
+
)
|
|
573
|
+
raise ValidationError(error_msg)
|
|
574
|
+
return tuple(space.class_axes_[name] for name in names)
|
|
575
|
+
|
|
576
|
+
def _reduced(self, operand: Expression, coordinates: list[Expression], place: FieldElement) -> Expression:
|
|
577
|
+
"""Return the symbol of the integral of an expression over class axes, broadcast back along them."""
|
|
578
|
+
space = self._phase_space(operand, place)
|
|
579
|
+
axes = self._axes_of(coordinates, space)
|
|
580
|
+
width = float(np.prod([space.spacings_[axis] for axis in axes]))
|
|
581
|
+
dimensions = space.shape_
|
|
582
|
+
|
|
583
|
+
over_positions = self.spec.rows == space.position_size_ != space.size_
|
|
584
|
+
|
|
585
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
586
|
+
reduced = np.reshape(values, dimensions).sum(axis=axes, keepdims=True) * width
|
|
587
|
+
return reduced.ravel() if over_positions else np.broadcast_to(reduced, dimensions).ravel()
|
|
588
|
+
|
|
589
|
+
read = FieldOperatorKernel(operand=operand, symbols=self._symbols(operand), apply=apply)
|
|
590
|
+
return self._derived(place, read.check().prepare())
|
|
591
|
+
|
|
592
|
+
def _equilibrium(
|
|
593
|
+
self,
|
|
594
|
+
operand: Expression,
|
|
595
|
+
order: int,
|
|
596
|
+
coordinates: list[Expression],
|
|
597
|
+
place: FieldElement,
|
|
598
|
+
) -> Expression:
|
|
599
|
+
"""Return the symbol of the density with the largest entropy and the moments of an expression."""
|
|
600
|
+
space = self._phase_space(operand, place)
|
|
601
|
+
apply = self._equilibrium_apply(space, self._axes_of(coordinates, space), order)
|
|
602
|
+
read = FieldOperatorKernel(operand=operand, symbols=self._symbols(operand), apply=apply)
|
|
603
|
+
return self._derived(place, read.check().prepare())
|
|
604
|
+
|
|
605
|
+
def _collision(self, operand: Expression, place: FieldElement) -> Expression:
|
|
606
|
+
"""Return the symbol of the binary collision integral of a density over the class axes of its phase space."""
|
|
607
|
+
space = self._phase_space(operand, place)
|
|
608
|
+
if self.cross_section_ is None:
|
|
609
|
+
error_msg = (
|
|
610
|
+
f'A law of {self.spec.owner} reads a collision integral, which only a `RateLaw` with a cross-section '
|
|
611
|
+
'declares.'
|
|
612
|
+
)
|
|
613
|
+
raise ValidationError(error_msg)
|
|
614
|
+
spacings = (space.spacings_[-PLANE], space.spacings_[-1])
|
|
615
|
+
kernel = CollisionKernel(space.shape_, spacings, self.cross_section_).check().prepare()
|
|
616
|
+
empty = np.zeros(0)
|
|
617
|
+
|
|
618
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
619
|
+
return kernel.run(RunStateSpec(0.0, values, empty)).values_
|
|
620
|
+
|
|
621
|
+
read = FieldOperatorKernel(operand=operand, symbols=self._symbols(operand), apply=apply)
|
|
622
|
+
return self._derived(place, read.check().prepare())
|
|
623
|
+
|
|
624
|
+
def _discretized(self, name: str, operands: list[object], place: FieldElement) -> Expression:
|
|
625
|
+
"""Return a local operator or an inversion lowered for the discretization of its field."""
|
|
626
|
+
if place.discretization == 'spectral':
|
|
627
|
+
return self._spectral(name, operands, place)
|
|
628
|
+
if name == 'inverse_helmholtz':
|
|
629
|
+
given = self._given_boundary(operands[2:])
|
|
630
|
+
return self._inverse(SR(operands[0]), self._screening(SR(operands[1])), place, given)
|
|
631
|
+
if place.discretization == 'finite-element':
|
|
632
|
+
return self._finite_element(name, SR(operands[0]), place)
|
|
633
|
+
return self._stencil(name, operands)
|
|
634
|
+
|
|
635
|
+
def _stencil(self, name: str, operands: list[object]) -> Expression:
|
|
636
|
+
"""Return the finite-difference stencil of an operator on a lattice or a network."""
|
|
637
|
+
if name == 'laplacian':
|
|
638
|
+
return self._laplacian(SR(operands[0]))
|
|
639
|
+
axis = int(SR(operands[1]))
|
|
640
|
+
value = SR(operands[0])
|
|
641
|
+
space, step, back = self._lattice(value, axis, 'derivative' if name == 'partial' else 'advection')
|
|
642
|
+
if name == 'partial':
|
|
643
|
+
return (self._shift(value, step) - self._shift(value, back)) / (2 * space.spacings_[axis])
|
|
644
|
+
velocity = SR(operands[2])
|
|
645
|
+
behind = (value - self._shift(value, back)) / space.spacings_[axis]
|
|
646
|
+
ahead = (self._shift(value, step) - value) / space.spacings_[axis]
|
|
647
|
+
return velocity * where(velocity > 0, behind, ahead)
|
|
648
|
+
|
|
649
|
+
def _derived(self, place: FieldElement, read: FieldOperatorKernel, target: Expression | None = None) -> Expression:
|
|
650
|
+
"""Return a symbol that stands for a derived value of a field, a new one by default, with its read."""
|
|
651
|
+
target = symbol(f'_derived_{place.label}_{len(self.derived_)}') if target is None else target
|
|
652
|
+
references = [self._known_reference(item) for item in read.symbols]
|
|
653
|
+
entry = next(
|
|
654
|
+
reference.entry
|
|
655
|
+
for reference in references
|
|
656
|
+
if reference.source in {ReadKind.MEMBER, ReadKind.NEIGHBOR, ReadKind.DERIVED}
|
|
657
|
+
)
|
|
658
|
+
self._add_reference(self.spec, target, ReferenceSpec(entry, True, 0, ReadKind.DERIVED, read))
|
|
659
|
+
self.derived_[target] = (place, read)
|
|
660
|
+
return target
|
|
661
|
+
|
|
662
|
+
def _spectral(self, name: str, operands: list[object], place: FieldElement) -> Expression:
|
|
663
|
+
"""Return the symbol of a spectral operator applied to an expression, composing chains of operators."""
|
|
664
|
+
space = place.space
|
|
665
|
+
if not isinstance(space, LatticeSpace) or space.boundary != 'periodic':
|
|
666
|
+
error_msg = f'A law of {self.spec.owner} uses a spectral field, which needs a periodic lattice.'
|
|
667
|
+
raise ValidationError(error_msg)
|
|
668
|
+
if name == 'upwind':
|
|
669
|
+
velocity = SR(operands[2])
|
|
670
|
+
return velocity * self._spectral('partial', [operands[0], operands[1]], place)
|
|
671
|
+
if name == 'inverse_helmholtz' and self._given_boundary(operands[2:]) not in {None, ('periodic', 0.0)}:
|
|
672
|
+
error_msg = (
|
|
673
|
+
f'A law of {self.spec.owner} inverts on a spectral field with a boundary that is not periodic. Give '
|
|
674
|
+
'the inversion no boundary, or use the finite-difference discretization.'
|
|
675
|
+
)
|
|
676
|
+
raise ValidationError(error_msg)
|
|
677
|
+
axis = int(SR(operands[1])) if name == 'partial' else 0
|
|
678
|
+
if name == 'partial' and not 0 <= axis < space.n_dim_:
|
|
679
|
+
error_msg = f'A law of {self.spec.owner} takes a derivative along axis {axis} of a {space.n_dim_}D lattice.'
|
|
680
|
+
raise ValidationError(error_msg)
|
|
681
|
+
screening = self._screening(SR(operands[1])) if name == 'inverse_helmholtz' else 0.0
|
|
682
|
+
if isinstance(space, PhaseSpace) and name == 'partial' and space._axis_boundary(axis) != 'periodic':
|
|
683
|
+
error_msg = (
|
|
684
|
+
f'A law of {self.spec.owner} takes a spectral derivative along axis {axis}, which is an interval. Use '
|
|
685
|
+
'a periodic class axis or the finite-volume discretization.'
|
|
686
|
+
)
|
|
687
|
+
raise ValidationError(error_msg)
|
|
688
|
+
multiplier = self._spectral_multiplier(
|
|
689
|
+
name,
|
|
690
|
+
axis,
|
|
691
|
+
space.shape_,
|
|
692
|
+
space.spacings_,
|
|
693
|
+
screening,
|
|
694
|
+
axes=self._transported_axes(space, name),
|
|
695
|
+
)
|
|
696
|
+
return self._multiplied(SR(operands[0]), multiplier, place)
|
|
697
|
+
|
|
698
|
+
def _multiplied(
|
|
699
|
+
self,
|
|
700
|
+
operand: Expression,
|
|
701
|
+
multiplier: npt.NDArray[np.complex128],
|
|
702
|
+
place: FieldElement,
|
|
703
|
+
) -> Expression:
|
|
704
|
+
"""Return the symbol of a Fourier multiplier applied to an expression, composing chains of multipliers."""
|
|
705
|
+
dimensions = place.space.shape_ if isinstance(place.space, LatticeSpace) else ()
|
|
706
|
+
inner = self.derived_.get(operand)
|
|
707
|
+
if inner is not None and inner[1].multiplier is not None:
|
|
708
|
+
operand, multiplier = inner[1].operand, multiplier * inner[1].multiplier
|
|
709
|
+
symbols = sorted(
|
|
710
|
+
(item for item in operand.variables() if self._reference_of(item, self.spec) is not None),
|
|
711
|
+
key=str,
|
|
712
|
+
)
|
|
713
|
+
read = (
|
|
714
|
+
FieldOperatorKernel(
|
|
715
|
+
operand=operand,
|
|
716
|
+
symbols=symbols,
|
|
717
|
+
apply=self._spectral_apply(multiplier, dimensions),
|
|
718
|
+
multiplier=multiplier,
|
|
719
|
+
dimensions=dimensions,
|
|
720
|
+
)
|
|
721
|
+
.check()
|
|
722
|
+
.prepare()
|
|
723
|
+
)
|
|
724
|
+
return self._derived(place, read)
|
|
725
|
+
|
|
726
|
+
def _symbols(self, expression: Expression) -> list[Expression]:
|
|
727
|
+
"""Return the symbols of an expression that the spec reads, sorted by name."""
|
|
728
|
+
return sorted(
|
|
729
|
+
(item for item in SR(expression).variables() if self._reference_of(item, self.spec) is not None),
|
|
730
|
+
key=str,
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
def _screening(self, screening: Expression) -> float:
|
|
734
|
+
"""Return the value of a screening at the current parameters, raising an error when it is not a real number."""
|
|
735
|
+
value = SR(screening).subs(self.initial_)
|
|
736
|
+
if value.variables() or not value.is_real() or float(value) < 0:
|
|
737
|
+
error_msg = (
|
|
738
|
+
f'A law of {self.spec.owner} inverts with the screening {screening}, which is not a non-negative '
|
|
739
|
+
'number of the parameters. Use a screening whose square is non-negative and that reads no state.'
|
|
740
|
+
)
|
|
741
|
+
raise ValidationError(error_msg)
|
|
742
|
+
return float(value)
|
|
743
|
+
|
|
744
|
+
def _given_boundary(self, operands: list[object]) -> tuple[str, float] | None:
|
|
745
|
+
"""Return the boundary condition given to an inversion by its code and value, or `None` when none is given."""
|
|
746
|
+
if not operands:
|
|
747
|
+
return None
|
|
748
|
+
code, value = SR(operands[0]), SR(operands[1])
|
|
749
|
+
if code.variables() or value.variables() or not 0 <= int(code) < len(INVERSION_BOUNDARIES):
|
|
750
|
+
error_msg = (
|
|
751
|
+
f'A law of {self.spec.owner} inverts with the boundary code {code} and value {value}. Give '
|
|
752
|
+
'`inverse_helmholtz` its boundary as `boundary=`, with a number as the fixed value.'
|
|
753
|
+
)
|
|
754
|
+
raise ValidationError(error_msg)
|
|
755
|
+
return INVERSION_BOUNDARIES[int(code)], float(value)
|
|
756
|
+
|
|
757
|
+
def _inverse(
|
|
758
|
+
self,
|
|
759
|
+
operand: Expression,
|
|
760
|
+
screening: float,
|
|
761
|
+
place: FieldElement,
|
|
762
|
+
given: tuple[str, float] | None = None,
|
|
763
|
+
) -> Expression:
|
|
764
|
+
"""Return the symbol of the solution of a modified-Helmholtz equation on a lattice, a network, or a mesh.
|
|
765
|
+
|
|
766
|
+
Args:
|
|
767
|
+
operand:
|
|
768
|
+
The right-hand side.
|
|
769
|
+
|
|
770
|
+
screening:
|
|
771
|
+
The screening, a non-negative number.
|
|
772
|
+
|
|
773
|
+
place:
|
|
774
|
+
The field.
|
|
775
|
+
|
|
776
|
+
given:
|
|
777
|
+
The boundary condition of the solution, or `None` for the boundary condition of the operand's states.
|
|
778
|
+
|
|
779
|
+
Returns:
|
|
780
|
+
solution:
|
|
781
|
+
The symbol of the solution.
|
|
782
|
+
|
|
783
|
+
Raises:
|
|
784
|
+
ValidationError:
|
|
785
|
+
The field's space or the boundary has no inversion, such as a boundary given on a network.
|
|
786
|
+
"""
|
|
787
|
+
space = place.space
|
|
788
|
+
kind, value = self._boundary(operand, place) if given is None else given
|
|
789
|
+
apply: Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]
|
|
790
|
+
if isinstance(space, NetworkSpace) and given is not None:
|
|
791
|
+
error_msg = f'A law of {self.spec.owner} inverts on a network with a boundary. Give the inversion none.'
|
|
792
|
+
raise ValidationError(error_msg)
|
|
793
|
+
if isinstance(space, MeshSpace):
|
|
794
|
+
apply = self._mesh_inverse(space, screening, kind, value)
|
|
795
|
+
elif isinstance(space, NetworkSpace):
|
|
796
|
+
apply = self._network_inverse(space, screening)
|
|
797
|
+
elif isinstance(space, PhaseSpace) and (kind != 'fixed' or isinstance(value, float)):
|
|
798
|
+
fill = float(value) if isinstance(value, float) else 0.0
|
|
799
|
+
apply = self._over_positions(space, self._lattice_inverse(space.position, screening, kind, fill))
|
|
800
|
+
elif isinstance(space, LatticeSpace) and (kind != 'fixed' or isinstance(value, float)):
|
|
801
|
+
apply = self._lattice_inverse(space, screening, kind, float(value) if isinstance(value, float) else 0.0)
|
|
802
|
+
else:
|
|
803
|
+
error_msg = (
|
|
804
|
+
f'A law of {self.spec.owner} inverts {operand} on a {type(space).__name__} with the boundary {kind}, '
|
|
805
|
+
'which needs a lattice, a network, or a mesh, with a number outside fixed lattice edges.'
|
|
806
|
+
)
|
|
807
|
+
raise ValidationError(error_msg)
|
|
808
|
+
read = FieldOperatorKernel(operand=operand, symbols=self._symbols(operand), apply=apply).check().prepare()
|
|
809
|
+
solution = self._derived(place, read)
|
|
810
|
+
if given is not None:
|
|
811
|
+
self.solution_boundaries_[solution] = (kind, value)
|
|
812
|
+
return solution
|
|
813
|
+
|
|
814
|
+
def _kernel_weights(
|
|
815
|
+
self,
|
|
816
|
+
kernel: Expression,
|
|
817
|
+
space: LatticeSpace,
|
|
818
|
+
radius: Expression,
|
|
819
|
+
*,
|
|
820
|
+
wrapped: bool,
|
|
821
|
+
) -> npt.NDArray[np.float64]:
|
|
822
|
+
"""Return a kernel sampled at the displacements of a lattice within a radius, times the cell volume.
|
|
823
|
+
|
|
824
|
+
Args:
|
|
825
|
+
kernel:
|
|
826
|
+
The kernel, an expression of the displacement and the parameters.
|
|
827
|
+
|
|
828
|
+
space:
|
|
829
|
+
The lattice.
|
|
830
|
+
|
|
831
|
+
radius:
|
|
832
|
+
The distance beyond which the kernel is zero, or infinity.
|
|
833
|
+
|
|
834
|
+
wrapped:
|
|
835
|
+
Whether to sample every displacement of a periodic lattice in FFT order, rather than a centred window.
|
|
836
|
+
|
|
837
|
+
Returns:
|
|
838
|
+
weights:
|
|
839
|
+
The sampled kernel.
|
|
840
|
+
|
|
841
|
+
Raises:
|
|
842
|
+
ValidationError:
|
|
843
|
+
The kernel reads a symbol that is not a displacement or a parameter.
|
|
844
|
+
"""
|
|
845
|
+
axes = [displacement(axis) for axis in range(space.n_dim_)]
|
|
846
|
+
parameters = {
|
|
847
|
+
key: item
|
|
848
|
+
for key, item in self.initial_.items()
|
|
849
|
+
if not getattr(self._reference_of(key, self.spec), 'is_state', True)
|
|
850
|
+
}
|
|
851
|
+
value = SR(kernel).subs(parameters)
|
|
852
|
+
unknown = sorted(set(value.variables()) - set(axes), key=str)
|
|
853
|
+
if unknown:
|
|
854
|
+
error_msg = (
|
|
855
|
+
f'A law of {self.spec.owner} convolves with the kernel {kernel}, which reads '
|
|
856
|
+
f'{", ".join(map(str, unknown))}. Write the kernel in the displacements and the parameters.'
|
|
857
|
+
)
|
|
858
|
+
raise ValidationError(error_msg)
|
|
859
|
+
distance = float('inf') if SR(radius).is_infinity() else float(SR(radius).subs(parameters))
|
|
860
|
+
if wrapped:
|
|
861
|
+
steps = [np.fft.fftfreq(size, d=1.0 / size) for size in space.shape_]
|
|
862
|
+
else:
|
|
863
|
+
reach = [
|
|
864
|
+
size - 1 if np.isinf(distance) else min(size - 1, int(np.ceil(distance / step - WHOLE_SITE)))
|
|
865
|
+
for size, step in zip(space.shape_, space.spacings_, strict=True)
|
|
866
|
+
]
|
|
867
|
+
steps = [np.arange(-item, item + 1, dtype=float) for item in reach]
|
|
868
|
+
grids = np.meshgrid(*[item * step for item, step in zip(steps, space.spacings_, strict=True)], indexing='ij')
|
|
869
|
+
printer = ExpressionPrinter(time=TIME, compiled=True).check().prepare(axes)
|
|
870
|
+
function = ExpressionPrinter._function_of(printer.run([value]).code_)
|
|
871
|
+
computed = ExpressionPrinter._values_of(function(0.0, *grids))[0]
|
|
872
|
+
sampled = np.broadcast_to(np.asarray(computed, dtype=float), grids[0].shape)
|
|
873
|
+
inside = np.sqrt(sum((grid**2 for grid in grids), np.zeros(grids[0].shape))) <= distance * (1 + WHOLE_SITE)
|
|
874
|
+
return np.where(inside, sampled, 0.0) * float(np.prod(space.spacings_))
|
|
875
|
+
|
|
876
|
+
def _convolve(self, operand: Expression, kernel: Expression, radius: Expression, place: FieldElement) -> Expression:
|
|
877
|
+
"""Return the symbol of the convolution of an expression with a kernel on a lattice."""
|
|
878
|
+
space = place.space
|
|
879
|
+
if not isinstance(space, LatticeSpace):
|
|
880
|
+
error_msg = (
|
|
881
|
+
f'A law of {self.spec.owner} convolves {operand} on a {type(space).__name__}, which needs a lattice '
|
|
882
|
+
'space. Give the field a lattice space.'
|
|
883
|
+
)
|
|
884
|
+
raise ValidationError(error_msg)
|
|
885
|
+
if place.discretization == 'spectral':
|
|
886
|
+
weights = self._kernel_weights(kernel, space, radius, wrapped=True)
|
|
887
|
+
return self._multiplied(operand, np.fft.rfftn(weights).astype(complex), place)
|
|
888
|
+
kind, value = self._boundary(operand, place)
|
|
889
|
+
if kind == 'fixed' and not isinstance(value, float):
|
|
890
|
+
error_msg = f'A law of {self.spec.owner} convolves {operand}, which needs a number outside fixed edges.'
|
|
891
|
+
raise ValidationError(error_msg)
|
|
892
|
+
window = self._kernel_weights(kernel, space, radius, wrapped=False)
|
|
893
|
+
if kind == 'periodic' and max(window.shape) > SMALL_KERNEL:
|
|
894
|
+
weights = self._kernel_weights(kernel, space, radius, wrapped=True)
|
|
895
|
+
apply = self._spectral_apply(np.fft.rfftn(weights).astype(complex), space.shape_)
|
|
896
|
+
else:
|
|
897
|
+
apply = self._window_apply(window, space.shape_, kind, float(value) if isinstance(value, float) else 0.0)
|
|
898
|
+
matrix = None if SR(radius).is_infinity() else self._window_matrix(window, place, kind, value)
|
|
899
|
+
read = FieldOperatorKernel(operand=operand, symbols=self._symbols(operand), apply=apply, matrix=matrix)
|
|
900
|
+
return self._derived(place, read.check().prepare())
|
|
901
|
+
|
|
902
|
+
def _window_matrix(
|
|
903
|
+
self,
|
|
904
|
+
window: npt.NDArray[np.float64],
|
|
905
|
+
place: FieldElement,
|
|
906
|
+
kind: str,
|
|
907
|
+
value: object,
|
|
908
|
+
) -> csr_matrix:
|
|
909
|
+
"""Return the sparse matrix of the linear part of a convolution with a window, the sites within its radius."""
|
|
910
|
+
size = place.size_
|
|
911
|
+
total = csr_matrix((size, size))
|
|
912
|
+
centre = np.asarray(window.shape) // 2
|
|
913
|
+
for index in zip(*np.nonzero(window), strict=True):
|
|
914
|
+
offset = tuple(int(item) for item in centre - np.asarray(index))
|
|
915
|
+
table = self._neighbor_table(place, kind, value, offset)
|
|
916
|
+
inside = table < size
|
|
917
|
+
selection = (np.full(inside.sum(), window[index]), (np.flatnonzero(inside), table[inside]))
|
|
918
|
+
total = total + csr_matrix(selection, shape=(size, size))
|
|
919
|
+
return csr_matrix(total)
|
|
920
|
+
|
|
921
|
+
def _shifted(self, operand: Expression, operands: list[Expression]) -> Expression:
|
|
922
|
+
"""Return an expression read at a physical displacement, a neighbour read for whole sites, else interpolated.
|
|
923
|
+
|
|
924
|
+
Args:
|
|
925
|
+
operand:
|
|
926
|
+
The expression.
|
|
927
|
+
|
|
928
|
+
operands:
|
|
929
|
+
The displacement along every axis, followed by the order of the interpolation when it is not 1.
|
|
930
|
+
|
|
931
|
+
Returns:
|
|
932
|
+
read:
|
|
933
|
+
The expression read at the displacement.
|
|
934
|
+
|
|
935
|
+
Raises:
|
|
936
|
+
ValidationError:
|
|
937
|
+
The field is not on a lattice, the displacement does not have one component per axis, or a fixed edge
|
|
938
|
+
has no number.
|
|
939
|
+
"""
|
|
940
|
+
place = self._place(operand)
|
|
941
|
+
space = place.space
|
|
942
|
+
dimensions = space.n_dim_ if isinstance(space, LatticeSpace) else 0
|
|
943
|
+
offset, orders = operands[:dimensions], operands[dimensions:]
|
|
944
|
+
if not isinstance(space, LatticeSpace) or len(offset) != space.n_dim_ or len(orders) > 1:
|
|
945
|
+
error_msg = (
|
|
946
|
+
f'A law of {self.spec.owner} reads {operand} at a shifted position, which needs a field on a lattice '
|
|
947
|
+
'space and one displacement per axis. Give the field a lattice space.'
|
|
948
|
+
)
|
|
949
|
+
raise ValidationError(error_msg)
|
|
950
|
+
sites = self._whole_sites(offset, space.spacings_)
|
|
951
|
+
if sites is not None:
|
|
952
|
+
return self._shift(operand, sites)
|
|
953
|
+
kind, value = self._boundary(operand, place)
|
|
954
|
+
if kind == 'fixed' and not isinstance(value, float):
|
|
955
|
+
error_msg = f'A law of {self.spec.owner} reads {operand} beyond fixed edges, which needs a number there.'
|
|
956
|
+
raise ValidationError(error_msg)
|
|
957
|
+
symbols = sorted(set(self._symbols(operand)).union(*[self._symbols(item) for item in offset]), key=str)
|
|
958
|
+
apply = self._interpolated_apply(
|
|
959
|
+
space.shape_,
|
|
960
|
+
space.spacings_,
|
|
961
|
+
kind,
|
|
962
|
+
float(value) if isinstance(value, float) else 0.0,
|
|
963
|
+
int(orders[0]) if orders else 1,
|
|
964
|
+
)
|
|
965
|
+
read = FieldOperatorKernel(
|
|
966
|
+
operand=operand,
|
|
967
|
+
symbols=symbols,
|
|
968
|
+
apply=apply,
|
|
969
|
+
displacement=offset,
|
|
970
|
+
)
|
|
971
|
+
return self._derived(place, read.check().prepare())
|
|
972
|
+
|
|
973
|
+
def _finite_element(self, name: str, operand: Expression, place: FieldElement) -> Expression:
|
|
974
|
+
"""Return the symbol of the finite element Laplacian of an expression."""
|
|
975
|
+
if name != 'laplacian':
|
|
976
|
+
error_msg = (
|
|
977
|
+
f'A law of {self.spec.owner} takes the {name} of a finite element field, which takes Laplacians only.'
|
|
978
|
+
)
|
|
979
|
+
raise ValidationError(error_msg)
|
|
980
|
+
if not isinstance(place.space, MeshSpace):
|
|
981
|
+
error_msg = f'A law of {self.spec.owner} uses a finite element field, which needs a mesh.'
|
|
982
|
+
raise ValidationError(error_msg)
|
|
983
|
+
matrix = self._mesh_laplacian(place.space)
|
|
984
|
+
symbols = sorted(
|
|
985
|
+
(item for item in operand.variables() if self._reference_of(item, self.spec) is not None),
|
|
986
|
+
key=str,
|
|
987
|
+
)
|
|
988
|
+
read = (
|
|
989
|
+
FieldOperatorKernel(
|
|
990
|
+
operand=operand,
|
|
991
|
+
symbols=symbols,
|
|
992
|
+
apply=lambda values: matrix @ values,
|
|
993
|
+
matrix=matrix,
|
|
994
|
+
)
|
|
995
|
+
.check()
|
|
996
|
+
.prepare()
|
|
997
|
+
)
|
|
998
|
+
return self._derived(place, read)
|
|
999
|
+
|
|
1000
|
+
def _note_volume_limit(self, coefficient: Expression, stiffness: float) -> None:
|
|
1001
|
+
"""Record the diffusive step limit of a finite-volume field as a function of the parameters it reads."""
|
|
1002
|
+
symbols = sorted(set(coefficient.variables()) - {TIME}, key=str)
|
|
1003
|
+
found = [self._reference_of(item, self.spec) for item in symbols]
|
|
1004
|
+
references = [reference for reference in found if reference is not None]
|
|
1005
|
+
if len(references) < len(symbols) or any(reference.is_state for reference in references):
|
|
1006
|
+
return
|
|
1007
|
+
function = ExpressionPrinter(time=TIME, compiled=True).check().prepare(symbols).run([coefficient]).code_
|
|
1008
|
+
if not callable(function):
|
|
1009
|
+
error_msg = f'A compiled printer returns a function, not a {type(function).__name__}.'
|
|
1010
|
+
raise TypeError(error_msg)
|
|
1011
|
+
self.volume_limits_.append(DiffusiveLimitSpec(function, tuple(references), stiffness))
|
|
1012
|
+
|
|
1013
|
+
def _note_limit(self, value: object) -> None:
|
|
1014
|
+
"""Record the diffusive step limit of the Laplacians in a law value.
|
|
1015
|
+
|
|
1016
|
+
A finite-difference field records the limit when the coefficient is a number at the initial values, and a
|
|
1017
|
+
finite-volume field records it as a function of the parameters the coefficient reads.
|
|
1018
|
+
|
|
1019
|
+
Args:
|
|
1020
|
+
value:
|
|
1021
|
+
The value of a rate law before lowering.
|
|
1022
|
+
"""
|
|
1023
|
+
if not isinstance(value, Expression):
|
|
1024
|
+
return
|
|
1025
|
+
for call in self._operator_calls(value, 'laplacian'):
|
|
1026
|
+
place = self._place(call.operands()[0])
|
|
1027
|
+
if place.discretization not in {'finite-difference', 'finite-volume'}:
|
|
1028
|
+
continue
|
|
1029
|
+
placeholder = symbol('_laplacian_')
|
|
1030
|
+
expression = SR(value.subs({call: placeholder})).diff(placeholder)
|
|
1031
|
+
space = place.space
|
|
1032
|
+
if isinstance(space, NetworkSpace):
|
|
1033
|
+
stiffness = max((item for _, item in space.graph.degree), default=1)
|
|
1034
|
+
elif isinstance(space, LatticeSpace):
|
|
1035
|
+
stiffness = sum(2 / step**2 for step in space.spacings_)
|
|
1036
|
+
else:
|
|
1037
|
+
continue
|
|
1038
|
+
if stiffness == 0:
|
|
1039
|
+
continue
|
|
1040
|
+
if place.discretization == 'finite-volume':
|
|
1041
|
+
self._note_volume_limit(expression, stiffness)
|
|
1042
|
+
continue
|
|
1043
|
+
coefficient = expression.subs(self.initial_)
|
|
1044
|
+
if coefficient.variables():
|
|
1045
|
+
continue
|
|
1046
|
+
magnitude = abs(float(coefficient))
|
|
1047
|
+
if magnitude == 0:
|
|
1048
|
+
continue
|
|
1049
|
+
self.limits_.append(1 / (stiffness * magnitude))
|
|
1050
|
+
|
|
1051
|
+
@staticmethod
|
|
1052
|
+
def _basis(space: PhaseSpace, axes: tuple[int, ...], order: int) -> npt.NDArray[np.float64]:
|
|
1053
|
+
"""Return the functions whose moments an equilibrium keeps at every class, one column per function.
|
|
1054
|
+
|
|
1055
|
+
Args:
|
|
1056
|
+
space:
|
|
1057
|
+
The phase space.
|
|
1058
|
+
|
|
1059
|
+
axes:
|
|
1060
|
+
The indices of the class axes of the equilibrium.
|
|
1061
|
+
|
|
1062
|
+
order:
|
|
1063
|
+
The highest order of the moments, 0, 1, or 2.
|
|
1064
|
+
|
|
1065
|
+
Returns:
|
|
1066
|
+
basis:
|
|
1067
|
+
The value 1, the coordinates for an order above 0, and their squared length for the order 2.
|
|
1068
|
+
"""
|
|
1069
|
+
names = {index: name for name, index in space.class_axes_.items()}
|
|
1070
|
+
grids = np.meshgrid(*(space.coordinates_[names[axis]] for axis in axes), indexing='ij')
|
|
1071
|
+
points = [grid.ravel() for grid in grids]
|
|
1072
|
+
columns = [np.ones(points[0].size)]
|
|
1073
|
+
if order >= 1:
|
|
1074
|
+
columns += points
|
|
1075
|
+
if order == PLANE:
|
|
1076
|
+
columns.append(sum(point**2 for point in points))
|
|
1077
|
+
return np.column_stack(columns)
|
|
1078
|
+
|
|
1079
|
+
@staticmethod
|
|
1080
|
+
def _newton(
|
|
1081
|
+
basis: npt.NDArray[np.float64],
|
|
1082
|
+
moments: npt.NDArray[np.float64],
|
|
1083
|
+
width: float,
|
|
1084
|
+
guess: npt.NDArray[np.float64],
|
|
1085
|
+
) -> npt.NDArray[np.float64]:
|
|
1086
|
+
"""Return the exponents of the densities `exp(basis @ a)` of the given discrete moments, by damped Newton steps.
|
|
1087
|
+
|
|
1088
|
+
Args:
|
|
1089
|
+
basis:
|
|
1090
|
+
The functions at every class, one column per function.
|
|
1091
|
+
|
|
1092
|
+
moments:
|
|
1093
|
+
The discrete moments of every density, one row per density.
|
|
1094
|
+
|
|
1095
|
+
width:
|
|
1096
|
+
The volume of a cell of the class axes.
|
|
1097
|
+
|
|
1098
|
+
guess:
|
|
1099
|
+
The exponents to start from, one row per density.
|
|
1100
|
+
|
|
1101
|
+
Returns:
|
|
1102
|
+
exponents:
|
|
1103
|
+
The exponents, one row per density.
|
|
1104
|
+
"""
|
|
1105
|
+
exponents = guess.copy()
|
|
1106
|
+
scale = np.maximum(np.abs(moments).max(axis=1, keepdims=True), 1.0)
|
|
1107
|
+
for _ in range(NEWTON_STEPS):
|
|
1108
|
+
density = np.exp(exponents @ basis.T)
|
|
1109
|
+
error = width * density @ basis - moments
|
|
1110
|
+
if np.abs(error / scale).max() <= NEWTON_TOLERANCE:
|
|
1111
|
+
break
|
|
1112
|
+
hessian = width * np.einsum('ij,jk,jl->ikl', density, basis, basis, optimize=True)
|
|
1113
|
+
step = np.linalg.solve(hessian, -error[..., None])[..., 0]
|
|
1114
|
+
largest = np.abs(step @ basis.T).max(axis=1, keepdims=True)
|
|
1115
|
+
exponents += step * np.minimum(1.0, LARGEST_EXPONENT_CHANGE / np.maximum(largest, 1e-300))
|
|
1116
|
+
return exponents
|
|
1117
|
+
|
|
1118
|
+
@staticmethod
|
|
1119
|
+
def _equilibrium_apply(
|
|
1120
|
+
space: PhaseSpace,
|
|
1121
|
+
axes: tuple[int, ...],
|
|
1122
|
+
order: int,
|
|
1123
|
+
) -> Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1124
|
+
"""Return the function of the values of a density to its maximum-entropy equilibrium at every position.
|
|
1125
|
+
|
|
1126
|
+
Args:
|
|
1127
|
+
space:
|
|
1128
|
+
The phase space.
|
|
1129
|
+
|
|
1130
|
+
axes:
|
|
1131
|
+
The indices of the class axes of the equilibrium.
|
|
1132
|
+
|
|
1133
|
+
order:
|
|
1134
|
+
The highest order of the moments that are kept.
|
|
1135
|
+
|
|
1136
|
+
Returns:
|
|
1137
|
+
apply:
|
|
1138
|
+
The function of the values at every site.
|
|
1139
|
+
"""
|
|
1140
|
+
basis = FieldLowering._basis(space, axes, order)
|
|
1141
|
+
width = float(np.prod([space.spacings_[axis] for axis in axes]))
|
|
1142
|
+
moved = tuple(range(space.n_dim_ - len(axes), space.n_dim_))
|
|
1143
|
+
dimension = len(axes)
|
|
1144
|
+
|
|
1145
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1146
|
+
grid = np.moveaxis(np.reshape(values, space.shape_), axes, moved)
|
|
1147
|
+
shape = grid.shape
|
|
1148
|
+
rows = grid.reshape(-1, basis.shape[0])
|
|
1149
|
+
moments = width * rows @ basis
|
|
1150
|
+
total = moments[:, 0]
|
|
1151
|
+
filled = total > 0
|
|
1152
|
+
result = np.zeros(rows.shape)
|
|
1153
|
+
if filled.any():
|
|
1154
|
+
guess = FieldLowering._equilibrium_guess(moments[filled], width, basis.shape[0], dimension)
|
|
1155
|
+
exponents = FieldLowering._newton(basis, moments[filled], width, guess)
|
|
1156
|
+
result[filled] = np.exp(exponents @ basis.T)
|
|
1157
|
+
return np.moveaxis(result.reshape(shape), moved, axes).ravel()
|
|
1158
|
+
|
|
1159
|
+
return apply
|
|
1160
|
+
|
|
1161
|
+
@staticmethod
|
|
1162
|
+
def _equilibrium_guess(
|
|
1163
|
+
moments: npt.NDArray[np.float64],
|
|
1164
|
+
width: float,
|
|
1165
|
+
classes: int,
|
|
1166
|
+
dimension: int,
|
|
1167
|
+
) -> npt.NDArray[np.float64]:
|
|
1168
|
+
"""Return the exponents of the continuous Maxwellian of given moments, or a uniform density below order 2."""
|
|
1169
|
+
guess = np.zeros(moments.shape)
|
|
1170
|
+
total = moments[:, 0]
|
|
1171
|
+
if moments.shape[1] == dimension + PLANE:
|
|
1172
|
+
mean = moments[:, 1:-1] / total[:, None]
|
|
1173
|
+
squared = np.sum(mean**2, axis=1)
|
|
1174
|
+
spread = np.maximum((moments[:, -1] / total - squared) / dimension, width ** (2 / dimension))
|
|
1175
|
+
guess[:, 0] = np.log(total) - dimension * np.log(2 * np.pi * spread) / 2 - squared / (2 * spread)
|
|
1176
|
+
guess[:, 1:-1] = mean / spread[:, None]
|
|
1177
|
+
guess[:, -1] = -1 / (2 * spread)
|
|
1178
|
+
return guess
|
|
1179
|
+
guess[:, 0] = np.log(total / (classes * width))
|
|
1180
|
+
return guess
|
|
1181
|
+
|
|
1182
|
+
@staticmethod
|
|
1183
|
+
def _components(law: FluxLaw) -> list[object]:
|
|
1184
|
+
"""Return the flux of every dimension of a flux law."""
|
|
1185
|
+
return list(law.flux) if isinstance(law.flux, FreeModuleElement | list | tuple) else [law.flux]
|
|
1186
|
+
|
|
1187
|
+
@staticmethod
|
|
1188
|
+
def _law_has_operators(law: BaseLaw) -> bool:
|
|
1189
|
+
"""Check whether the value of a law, or a flux of a flux law, applies a differential operator."""
|
|
1190
|
+
if isinstance(law, FluxLaw):
|
|
1191
|
+
return any(FieldLowering._has_operators(SR(item)) for item in FieldLowering._components(law))
|
|
1192
|
+
return FieldLowering._has_operators(getattr(law, 'value', None))
|
|
1193
|
+
|
|
1194
|
+
@staticmethod
|
|
1195
|
+
def _over_positions(
|
|
1196
|
+
space: PhaseSpace,
|
|
1197
|
+
apply: Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]],
|
|
1198
|
+
) -> Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1199
|
+
"""Return an operator of the position lattice on values over the phase space that do not vary with class."""
|
|
1200
|
+
classes = space.size_ // space.position_size_
|
|
1201
|
+
|
|
1202
|
+
def over(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1203
|
+
return np.repeat(apply(np.reshape(values, (space.position_size_, classes))[:, 0]), classes)
|
|
1204
|
+
|
|
1205
|
+
return over
|
|
1206
|
+
|
|
1207
|
+
@staticmethod
|
|
1208
|
+
def _transported_axes(space: LatticeSpace, name: str) -> tuple[int, ...] | None:
|
|
1209
|
+
"""Return the axes a spectral operator of a phase space acts along, or `None` for all of them on a lattice."""
|
|
1210
|
+
if not isinstance(space, PhaseSpace):
|
|
1211
|
+
return None
|
|
1212
|
+
if name == 'inverse_helmholtz':
|
|
1213
|
+
return space.position_axes_
|
|
1214
|
+
return tuple(axis for axis in range(space.n_dim_) if space._axis_boundary(axis) == 'periodic')
|
|
1215
|
+
|
|
1216
|
+
@staticmethod
|
|
1217
|
+
def _tag(offset: IntTuple | int) -> str:
|
|
1218
|
+
"""Return a name fragment for a lattice offset or a network neighbour slot."""
|
|
1219
|
+
if isinstance(offset, int):
|
|
1220
|
+
return f'k{offset}'
|
|
1221
|
+
return '_'.join(f'{"m" if step < 0 else "p"}{abs(step)}' for step in offset)
|
|
1222
|
+
|
|
1223
|
+
@staticmethod
|
|
1224
|
+
def _operator_calls(expression: Expression, name: str) -> list[Expression]:
|
|
1225
|
+
"""Return the calls of an operator by name inside an expression."""
|
|
1226
|
+
found, stack = [], [SR(expression)]
|
|
1227
|
+
while stack:
|
|
1228
|
+
item = stack.pop()
|
|
1229
|
+
if item.operator() is None:
|
|
1230
|
+
continue
|
|
1231
|
+
if getattr(item.operator(), 'name', lambda: '')() == name:
|
|
1232
|
+
found.append(item)
|
|
1233
|
+
stack.extend(item.operands())
|
|
1234
|
+
return found
|
|
1235
|
+
|
|
1236
|
+
@staticmethod
|
|
1237
|
+
def _spectral_apply(
|
|
1238
|
+
multiplier: npt.NDArray[np.complex128],
|
|
1239
|
+
dimensions: tuple[int, ...],
|
|
1240
|
+
) -> Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1241
|
+
"""Return the function that applies a Fourier multiplier to the values of a periodic lattice.
|
|
1242
|
+
|
|
1243
|
+
Args:
|
|
1244
|
+
multiplier:
|
|
1245
|
+
The factor of every real Fourier mode.
|
|
1246
|
+
|
|
1247
|
+
dimensions:
|
|
1248
|
+
The lattice shape.
|
|
1249
|
+
|
|
1250
|
+
Returns:
|
|
1251
|
+
apply:
|
|
1252
|
+
The function of the values at every site.
|
|
1253
|
+
"""
|
|
1254
|
+
|
|
1255
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1256
|
+
transformed = np.fft.rfftn(np.reshape(values, dimensions)) * multiplier
|
|
1257
|
+
return np.fft.irfftn(transformed, s=dimensions, axes=range(len(dimensions))).ravel()
|
|
1258
|
+
|
|
1259
|
+
return apply
|
|
1260
|
+
|
|
1261
|
+
@staticmethod
|
|
1262
|
+
def _whole_sites(offset: list[Expression], spacings: tuple[float, ...]) -> IntTuple | None:
|
|
1263
|
+
"""Return a displacement in whole sites when every component is a number of whole spacings, else `None`."""
|
|
1264
|
+
sites = []
|
|
1265
|
+
for item, step in zip(offset, spacings, strict=True):
|
|
1266
|
+
if SR(item).variables() or not SR(item).is_real():
|
|
1267
|
+
return None
|
|
1268
|
+
ratio = float(SR(item)) / step
|
|
1269
|
+
if abs(ratio - round(ratio)) > WHOLE_SITE:
|
|
1270
|
+
return None
|
|
1271
|
+
sites.append(round(ratio))
|
|
1272
|
+
return tuple(sites)
|
|
1273
|
+
|
|
1274
|
+
@staticmethod
|
|
1275
|
+
def _window_apply(
|
|
1276
|
+
window: npt.NDArray[np.float64],
|
|
1277
|
+
dimensions: tuple[int, ...],
|
|
1278
|
+
kind: str,
|
|
1279
|
+
fill: float,
|
|
1280
|
+
) -> Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1281
|
+
"""Return the function that convolves the values of a lattice with a centred window of weights.
|
|
1282
|
+
|
|
1283
|
+
Windows of at most `SMALL_KERNEL` sites per axis use a direct filter, and larger ones an overlap-add FFT of the
|
|
1284
|
+
values padded beyond the edges with the fixed value or their mirror image.
|
|
1285
|
+
|
|
1286
|
+
Args:
|
|
1287
|
+
window:
|
|
1288
|
+
The weights at the displacements from `-reach` to `reach` sites along every axis.
|
|
1289
|
+
|
|
1290
|
+
dimensions:
|
|
1291
|
+
The lattice shape.
|
|
1292
|
+
|
|
1293
|
+
kind:
|
|
1294
|
+
The boundary, `'periodic'`, `'zero-flux'`, or `'fixed'`.
|
|
1295
|
+
|
|
1296
|
+
fill:
|
|
1297
|
+
The value beyond fixed edges.
|
|
1298
|
+
|
|
1299
|
+
Returns:
|
|
1300
|
+
apply:
|
|
1301
|
+
The function of the values at every site.
|
|
1302
|
+
"""
|
|
1303
|
+
reach = [(size // 2, size // 2) for size in window.shape]
|
|
1304
|
+
|
|
1305
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1306
|
+
grid = np.reshape(values, dimensions)
|
|
1307
|
+
if max(window.shape) <= SMALL_KERNEL:
|
|
1308
|
+
return np.asarray(convolve(grid, window, mode=FILTER_MODES[kind], cval=fill)).ravel()
|
|
1309
|
+
if kind == 'fixed':
|
|
1310
|
+
padded = np.pad(grid, reach, mode='constant', constant_values=fill)
|
|
1311
|
+
else:
|
|
1312
|
+
padded = np.pad(grid, reach, mode='symmetric')
|
|
1313
|
+
return np.asarray(oaconvolve(padded, window, mode='valid')).ravel()
|
|
1314
|
+
|
|
1315
|
+
return apply
|
|
1316
|
+
|
|
1317
|
+
@staticmethod
|
|
1318
|
+
def _interpolated_apply(
|
|
1319
|
+
dimensions: tuple[int, ...],
|
|
1320
|
+
spacings: tuple[float, ...],
|
|
1321
|
+
kind: str,
|
|
1322
|
+
fill: float,
|
|
1323
|
+
order: int = 1,
|
|
1324
|
+
) -> Callable[[npt.NDArray[np.float64], npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1325
|
+
"""Return the function that reads the values of a lattice at displaced positions by spline interpolation.
|
|
1326
|
+
|
|
1327
|
+
Args:
|
|
1328
|
+
dimensions:
|
|
1329
|
+
The lattice shape.
|
|
1330
|
+
|
|
1331
|
+
spacings:
|
|
1332
|
+
The distance between sites along every axis.
|
|
1333
|
+
|
|
1334
|
+
kind:
|
|
1335
|
+
The boundary, `'periodic'`, `'zero-flux'`, or `'fixed'`.
|
|
1336
|
+
|
|
1337
|
+
fill:
|
|
1338
|
+
The value beyond fixed edges.
|
|
1339
|
+
|
|
1340
|
+
order:
|
|
1341
|
+
The order of the spline, 1 for linear or 3 for cubic.
|
|
1342
|
+
|
|
1343
|
+
Returns:
|
|
1344
|
+
apply:
|
|
1345
|
+
The function of the values and the displacement along every axis at every site.
|
|
1346
|
+
"""
|
|
1347
|
+
sites = np.indices(dimensions).reshape(len(dimensions), -1).astype(float)
|
|
1348
|
+
steps = np.asarray(spacings, dtype=float)[:, None]
|
|
1349
|
+
|
|
1350
|
+
def apply(values: npt.NDArray[np.float64], offset: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1351
|
+
grid = np.reshape(values, dimensions)
|
|
1352
|
+
positions = sites + np.reshape(offset, sites.shape) / steps
|
|
1353
|
+
return np.asarray(map_coordinates(grid, positions, order=order, mode=SHIFTED_MODES[kind], cval=fill))
|
|
1354
|
+
|
|
1355
|
+
return apply
|
|
1356
|
+
|
|
1357
|
+
@staticmethod
|
|
1358
|
+
def _lattice_inverse(
|
|
1359
|
+
space: LatticeSpace,
|
|
1360
|
+
screening: float,
|
|
1361
|
+
kind: str,
|
|
1362
|
+
fill: float,
|
|
1363
|
+
) -> Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1364
|
+
"""Return the function that inverts the lattice stencil of `laplacian - screening**2` by a fast transform.
|
|
1365
|
+
|
|
1366
|
+
Periodic edges use real FFTs, fixed edges the sine transform of type 1 with the fixed value lifted into the
|
|
1367
|
+
right-hand side, and zero-flux edges the cosine transform of type 2, each with the eigenvalues of the stencil.
|
|
1368
|
+
The mode of zero eigenvalue, the mean, is set to zero.
|
|
1369
|
+
|
|
1370
|
+
Args:
|
|
1371
|
+
space:
|
|
1372
|
+
The lattice.
|
|
1373
|
+
|
|
1374
|
+
screening:
|
|
1375
|
+
The screening, a non-negative number.
|
|
1376
|
+
|
|
1377
|
+
kind:
|
|
1378
|
+
The boundary, `'periodic'`, `'zero-flux'`, or `'fixed'`.
|
|
1379
|
+
|
|
1380
|
+
fill:
|
|
1381
|
+
The value beyond fixed edges.
|
|
1382
|
+
|
|
1383
|
+
Returns:
|
|
1384
|
+
apply:
|
|
1385
|
+
The function of the right-hand side at every site.
|
|
1386
|
+
"""
|
|
1387
|
+
dimensions, spacings = space.shape_, space.spacings_
|
|
1388
|
+
if kind == 'periodic':
|
|
1389
|
+
waves = FieldLowering._wavenumbers(dimensions, spacings)
|
|
1390
|
+
eigenvalues = sum(
|
|
1391
|
+
((2 * np.cos(wave * step) - 2) / step**2 for wave, step in zip(waves, spacings, strict=True)),
|
|
1392
|
+
np.zeros(waves[0].shape),
|
|
1393
|
+
)
|
|
1394
|
+
denominator = eigenvalues - screening**2
|
|
1395
|
+
nonzero = np.abs(denominator) > 0
|
|
1396
|
+
multiplier = np.where(nonzero, 1.0 / np.where(nonzero, denominator, 1.0), 0.0).astype(complex)
|
|
1397
|
+
return FieldLowering._spectral_apply(multiplier, dimensions)
|
|
1398
|
+
if kind == 'fixed':
|
|
1399
|
+
modes = [np.arange(1, size + 1) / (size + 1) for size in dimensions]
|
|
1400
|
+
else:
|
|
1401
|
+
modes = [np.arange(size) / size for size in dimensions]
|
|
1402
|
+
axes = [(2 * np.cos(np.pi * mode) - 2) / step**2 for mode, step in zip(modes, spacings, strict=True)]
|
|
1403
|
+
grids = np.meshgrid(*axes, indexing='ij')
|
|
1404
|
+
denominator = sum(grids, np.zeros(dimensions)) - screening**2
|
|
1405
|
+
nonzero = np.abs(denominator) > 0
|
|
1406
|
+
inverse = np.where(nonzero, 1.0 / np.where(nonzero, denominator, 1.0), 0.0)
|
|
1407
|
+
lift = np.zeros(dimensions)
|
|
1408
|
+
for axis, step in enumerate(spacings):
|
|
1409
|
+
edges = [slice(None)] * len(dimensions)
|
|
1410
|
+
for index in (0, -1):
|
|
1411
|
+
edges[axis] = slice(index, index + 1 if index == 0 else None)
|
|
1412
|
+
lift[tuple(edges)] += fill / step**2
|
|
1413
|
+
kind_number = 1 if kind == 'fixed' else 2
|
|
1414
|
+
transform = scipy.fft.dstn if kind == 'fixed' else scipy.fft.dctn
|
|
1415
|
+
backward = scipy.fft.idstn if kind == 'fixed' else scipy.fft.idctn
|
|
1416
|
+
|
|
1417
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1418
|
+
right = np.reshape(values, dimensions) - (lift if kind == 'fixed' else 0.0)
|
|
1419
|
+
spectrum = transform(right, type=kind_number, norm='ortho') * inverse
|
|
1420
|
+
return np.asarray(backward(spectrum, type=kind_number, norm='ortho')).ravel()
|
|
1421
|
+
|
|
1422
|
+
return apply
|
|
1423
|
+
|
|
1424
|
+
@staticmethod
|
|
1425
|
+
def _grounded_solver(
|
|
1426
|
+
matrix: csr_matrix,
|
|
1427
|
+
free: npt.NDArray[np.intp],
|
|
1428
|
+
) -> Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1429
|
+
"""Return the function that solves a sparse system on its free rows, factorised once, zero on the others."""
|
|
1430
|
+
solve = factorized(matrix[free][:, free].tocsc())
|
|
1431
|
+
size = matrix.shape[0]
|
|
1432
|
+
|
|
1433
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1434
|
+
solution = np.zeros(size)
|
|
1435
|
+
solution[free] = solve(np.asarray(values, dtype=float)[free])
|
|
1436
|
+
return solution
|
|
1437
|
+
|
|
1438
|
+
return apply
|
|
1439
|
+
|
|
1440
|
+
@staticmethod
|
|
1441
|
+
def _network_inverse(
|
|
1442
|
+
space: NetworkSpace,
|
|
1443
|
+
screening: float,
|
|
1444
|
+
) -> Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1445
|
+
"""Return the function that inverts the graph Laplacian minus `screening**2`, with zero mean when unscreened.
|
|
1446
|
+
|
|
1447
|
+
Args:
|
|
1448
|
+
space:
|
|
1449
|
+
The network.
|
|
1450
|
+
|
|
1451
|
+
screening:
|
|
1452
|
+
The screening, a non-negative number.
|
|
1453
|
+
|
|
1454
|
+
Returns:
|
|
1455
|
+
apply:
|
|
1456
|
+
The function of the right-hand side at every node.
|
|
1457
|
+
"""
|
|
1458
|
+
table = space._index_table(AdjacencyNeighborhood())
|
|
1459
|
+
size = table.shape[0]
|
|
1460
|
+
rows = np.repeat(np.arange(size), table.shape[1])
|
|
1461
|
+
columns = table.ravel()
|
|
1462
|
+
inside = columns < size
|
|
1463
|
+
adjacency = csr_matrix((np.ones(inside.sum()), (rows[inside], columns[inside])), shape=(size, size))
|
|
1464
|
+
degrees = np.asarray(adjacency.sum(axis=1)).ravel()
|
|
1465
|
+
matrix = csr_matrix(adjacency - diags(degrees) - screening**2 * identity(size))
|
|
1466
|
+
if screening > 0:
|
|
1467
|
+
return FieldLowering._grounded_solver(matrix, np.arange(size))
|
|
1468
|
+
solve = FieldLowering._grounded_solver(matrix, np.arange(1, size))
|
|
1469
|
+
|
|
1470
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1471
|
+
right = np.asarray(values, dtype=float)
|
|
1472
|
+
solution = solve(right - right.mean())
|
|
1473
|
+
return solution - solution.mean()
|
|
1474
|
+
|
|
1475
|
+
return apply
|
|
1476
|
+
|
|
1477
|
+
@staticmethod
|
|
1478
|
+
def _mesh_inverse(
|
|
1479
|
+
space: MeshSpace,
|
|
1480
|
+
screening: float,
|
|
1481
|
+
kind: str,
|
|
1482
|
+
fill: object,
|
|
1483
|
+
) -> Callable[[npt.NDArray[np.float64]], npt.NDArray[np.float64]]:
|
|
1484
|
+
"""Return the function that inverts the lumped finite element Laplacian minus `screening**2` on a mesh.
|
|
1485
|
+
|
|
1486
|
+
It solves `(K + screening**2 M) psi = -M f` with the stiffness matrix `K` and the lumped mass `M`, with the
|
|
1487
|
+
fixed value on the boundary nodes of fixed edges and zero mean for unscreened zero-flux edges.
|
|
1488
|
+
|
|
1489
|
+
Args:
|
|
1490
|
+
space:
|
|
1491
|
+
The mesh.
|
|
1492
|
+
|
|
1493
|
+
screening:
|
|
1494
|
+
The screening, a non-negative number.
|
|
1495
|
+
|
|
1496
|
+
kind:
|
|
1497
|
+
The boundary, `'zero-flux'` or `'fixed'`.
|
|
1498
|
+
|
|
1499
|
+
fill:
|
|
1500
|
+
The value on the boundary nodes of fixed edges, a number or a function of the node coordinates.
|
|
1501
|
+
|
|
1502
|
+
Returns:
|
|
1503
|
+
apply:
|
|
1504
|
+
The function of the right-hand side at every node.
|
|
1505
|
+
"""
|
|
1506
|
+
stiffness, lumped = FieldLowering._mesh_matrices(space)
|
|
1507
|
+
size = lumped.size
|
|
1508
|
+
matrix = csr_matrix(stiffness + screening**2 * diags(lumped))
|
|
1509
|
+
if kind == 'fixed':
|
|
1510
|
+
nodes = space.boundary_nodes_
|
|
1511
|
+
coordinates = space.positions_[nodes]
|
|
1512
|
+
fixed = np.zeros(size)
|
|
1513
|
+
fixed[nodes] = np.broadcast_to(fill(*coordinates.T) if callable(fill) else float(str(fill)), nodes.shape)
|
|
1514
|
+
free = np.setdiff1d(np.arange(size), nodes)
|
|
1515
|
+
solve = FieldLowering._grounded_solver(matrix, free)
|
|
1516
|
+
carried = matrix @ fixed
|
|
1517
|
+
|
|
1518
|
+
def apply(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1519
|
+
return solve(-lumped * np.asarray(values, dtype=float) - carried) + fixed
|
|
1520
|
+
|
|
1521
|
+
return apply
|
|
1522
|
+
if screening > 0:
|
|
1523
|
+
solve = FieldLowering._grounded_solver(matrix, np.arange(size))
|
|
1524
|
+
return lambda values: solve(-lumped * np.asarray(values, dtype=float))
|
|
1525
|
+
solve = FieldLowering._grounded_solver(matrix, np.arange(1, size))
|
|
1526
|
+
|
|
1527
|
+
def apply_mean(values: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
|
|
1528
|
+
right = np.asarray(values, dtype=float)
|
|
1529
|
+
solution = solve(-lumped * (right - np.average(right, weights=lumped)))
|
|
1530
|
+
return solution - np.average(solution, weights=lumped)
|
|
1531
|
+
|
|
1532
|
+
return apply_mean
|
|
1533
|
+
|
|
1534
|
+
@staticmethod
|
|
1535
|
+
def _has_operators(expression: object) -> bool:
|
|
1536
|
+
"""Check whether an expression applies a differential operator.
|
|
1537
|
+
|
|
1538
|
+
Args:
|
|
1539
|
+
expression:
|
|
1540
|
+
The expression.
|
|
1541
|
+
|
|
1542
|
+
Returns:
|
|
1543
|
+
found:
|
|
1544
|
+
Whether it calls one of `OPERATOR_NAMES`.
|
|
1545
|
+
"""
|
|
1546
|
+
if not isinstance(expression, Expression):
|
|
1547
|
+
return False
|
|
1548
|
+
names = '|'.join(OPERATOR_NAMES)
|
|
1549
|
+
return bool(re.search(rf'\b({names})\(', str(expression)))
|
|
1550
|
+
|
|
1551
|
+
@staticmethod
|
|
1552
|
+
@functools.cache
|
|
1553
|
+
def _cached_mesh_matrices(
|
|
1554
|
+
points: bytes,
|
|
1555
|
+
cells: bytes,
|
|
1556
|
+
shape: tuple[int, int],
|
|
1557
|
+
cell_shape: tuple[int, int],
|
|
1558
|
+
) -> tuple[csr_matrix, npt.NDArray[np.float64]]:
|
|
1559
|
+
"""Return the stiffness matrix and the lumped mass of a mesh, cached by its nodes and cells."""
|
|
1560
|
+
nodes = np.frombuffer(points).reshape(shape)
|
|
1561
|
+
elements = np.frombuffer(cells, dtype=np.int64).reshape(cell_shape)
|
|
1562
|
+
space = MeshSpace(nodes, elements)
|
|
1563
|
+
basis = Basis(space.check().prepare().mesh_, ElementTriP1() if shape[0] == PLANE else ElementTetP1())
|
|
1564
|
+
stiffness = asm(laplace, basis).tocsr()
|
|
1565
|
+
lumped = np.asarray(asm(mass, basis).sum(axis=1)).ravel()
|
|
1566
|
+
return stiffness, lumped
|
|
1567
|
+
|
|
1568
|
+
@staticmethod
|
|
1569
|
+
def _mesh_matrices(space: MeshSpace) -> tuple[csr_matrix, npt.NDArray[np.float64]]:
|
|
1570
|
+
"""Return the stiffness matrix and the lumped mass of the linear elements of a mesh.
|
|
1571
|
+
|
|
1572
|
+
Args:
|
|
1573
|
+
space:
|
|
1574
|
+
The mesh.
|
|
1575
|
+
|
|
1576
|
+
Returns:
|
|
1577
|
+
matrices:
|
|
1578
|
+
The stiffness matrix and the lumped mass of every node.
|
|
1579
|
+
"""
|
|
1580
|
+
points = np.ascontiguousarray(np.asarray(space.points, dtype=float))
|
|
1581
|
+
cells = np.ascontiguousarray(np.asarray(space.cells, dtype=np.int64))
|
|
1582
|
+
return FieldLowering._cached_mesh_matrices(points.tobytes(), cells.tobytes(), points.shape, cells.shape)
|
|
1583
|
+
|
|
1584
|
+
@staticmethod
|
|
1585
|
+
def _mesh_laplacian(space: MeshSpace) -> csr_matrix:
|
|
1586
|
+
"""Return the discrete Laplacian of linear elements with lumped mass, `-M^-1 K`, as a sparse matrix.
|
|
1587
|
+
|
|
1588
|
+
Args:
|
|
1589
|
+
space:
|
|
1590
|
+
The mesh.
|
|
1591
|
+
|
|
1592
|
+
Returns:
|
|
1593
|
+
laplacian:
|
|
1594
|
+
The sparse matrix that maps nodal values to the nodal Laplacian.
|
|
1595
|
+
"""
|
|
1596
|
+
stiffness, lumped = FieldLowering._mesh_matrices(space)
|
|
1597
|
+
return -diags(1.0 / lumped) @ stiffness
|
|
1598
|
+
|
|
1599
|
+
@staticmethod
|
|
1600
|
+
@functools.cache
|
|
1601
|
+
def _wavenumbers(dimensions: tuple[int, ...], spacings: tuple[float, ...]) -> tuple[npt.NDArray[np.float64], ...]:
|
|
1602
|
+
"""Return the angular wavenumbers of the real Fourier modes of a periodic lattice, broadcast along each axis."""
|
|
1603
|
+
axes = [2 * np.pi * np.fft.fftfreq(size, d=step) for size, step in zip(dimensions[:-1], spacings, strict=False)]
|
|
1604
|
+
axes.append(2 * np.pi * np.fft.rfftfreq(dimensions[-1], d=spacings[-1]))
|
|
1605
|
+
return tuple(np.meshgrid(*axes, indexing='ij'))
|
|
1606
|
+
|
|
1607
|
+
@staticmethod
|
|
1608
|
+
@functools.cache
|
|
1609
|
+
def _dealiasing_mask(dimensions: tuple[int, ...]) -> npt.NDArray[np.bool_]:
|
|
1610
|
+
"""Return the Fourier modes the two-thirds rule keeps, below two thirds of the largest along every axis."""
|
|
1611
|
+
axes = [np.abs(np.fft.fftfreq(size, d=1.0 / size)) < size / 3 for size in dimensions[:-1]]
|
|
1612
|
+
axes.append(np.fft.rfftfreq(dimensions[-1], d=1.0 / dimensions[-1]) < dimensions[-1] / 3)
|
|
1613
|
+
grids = np.meshgrid(*axes, indexing='ij')
|
|
1614
|
+
return np.logical_and.reduce(grids)
|
|
1615
|
+
|
|
1616
|
+
@staticmethod
|
|
1617
|
+
def _spectral_multiplier(
|
|
1618
|
+
name: str,
|
|
1619
|
+
axis: int,
|
|
1620
|
+
dimensions: tuple[int, ...],
|
|
1621
|
+
spacings: tuple[float, ...],
|
|
1622
|
+
screening: float = 0.0,
|
|
1623
|
+
*,
|
|
1624
|
+
axes: tuple[int, ...] | None = None,
|
|
1625
|
+
) -> npt.NDArray[np.complex128]:
|
|
1626
|
+
"""Return the Fourier multiplier of an operator on a periodic lattice.
|
|
1627
|
+
|
|
1628
|
+
The Laplacian and its inverse act on every mode, so the Laplacian damps the Nyquist mode by `-|k|^2` like any
|
|
1629
|
+
other. A first derivative is zero at the Nyquist mode of its axis, and keeps only the modes of the two-thirds
|
|
1630
|
+
rule, which dealiases the derivatives of products.
|
|
1631
|
+
|
|
1632
|
+
Args:
|
|
1633
|
+
name:
|
|
1634
|
+
`'laplacian'`, `'partial'`, or `'inverse_helmholtz'`.
|
|
1635
|
+
|
|
1636
|
+
axis:
|
|
1637
|
+
The axis of a derivative.
|
|
1638
|
+
|
|
1639
|
+
dimensions:
|
|
1640
|
+
The lattice shape.
|
|
1641
|
+
|
|
1642
|
+
spacings:
|
|
1643
|
+
The distance between sites along every axis.
|
|
1644
|
+
|
|
1645
|
+
screening:
|
|
1646
|
+
The screening of the inverse Helmholtz operator.
|
|
1647
|
+
|
|
1648
|
+
axes:
|
|
1649
|
+
The axes the operator acts along, whose modes the two-thirds rule alone cuts, or `None` for every axis.
|
|
1650
|
+
|
|
1651
|
+
Returns:
|
|
1652
|
+
multiplier:
|
|
1653
|
+
The factor of every real Fourier mode.
|
|
1654
|
+
"""
|
|
1655
|
+
waves = FieldLowering._wavenumbers(dimensions, spacings)
|
|
1656
|
+
squared = np.sum([waves[item] ** 2 for item in (range(len(waves)) if axes is None else axes)], axis=0)
|
|
1657
|
+
if name == 'laplacian':
|
|
1658
|
+
return -squared.astype(complex)
|
|
1659
|
+
if name == 'inverse_helmholtz':
|
|
1660
|
+
screened = squared + screening**2
|
|
1661
|
+
return np.where(screened > 0, -1.0 / np.where(screened > 0, screened, 1.0), 0.0).astype(complex)
|
|
1662
|
+
factor = 1j * waves[axis]
|
|
1663
|
+
if dimensions[axis] % 2 == 0:
|
|
1664
|
+
nyquist = np.isclose(np.abs(waves[axis]), np.pi / spacings[axis])
|
|
1665
|
+
factor = np.where(nyquist, 0.0, factor)
|
|
1666
|
+
if axes is None:
|
|
1667
|
+
return np.where(FieldLowering._dealiasing_mask(dimensions), factor, 0.0)
|
|
1668
|
+
return np.where(np.abs(waves[axis]) * spacings[axis] < 2 * np.pi / 3, factor, 0.0)
|