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,1534 @@
|
|
|
1
|
+
"""Compile a system through the passes of a compilation, after validating it against what they need."""
|
|
2
|
+
|
|
3
|
+
# Author: Georgios Douzas <gdouzas@icloud.com>
|
|
4
|
+
# License: MIT
|
|
5
|
+
|
|
6
|
+
import dataclasses
|
|
7
|
+
import heapq
|
|
8
|
+
from collections import defaultdict
|
|
9
|
+
from collections.abc import Collection, Iterable, Iterator, Mapping, Sequence
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from sage.all__sagemath_symbolics import SR, Expression
|
|
13
|
+
from sage.modules.free_module_element import FreeModuleElement
|
|
14
|
+
from sklearn.base import clone
|
|
15
|
+
|
|
16
|
+
from ...base import BaseConfig
|
|
17
|
+
from ...core.elements import FieldElement, GroupElement
|
|
18
|
+
from ...core.interactions import HyperedgeInteraction, NeighborInteraction, SatisfiabilityInteraction
|
|
19
|
+
from ...core.laws import BilinearLaw, EncounterLaw, EquationLaw, JumpLaw, NoiseLaw, RateLaw
|
|
20
|
+
from ...core.laws.utils import COORDINATE_PREFIX, hyperedges_in, neighborhoods_in, reductions_in
|
|
21
|
+
from ...core.spaces import (
|
|
22
|
+
AdjacencyNeighborhood,
|
|
23
|
+
BaseNeighborhood,
|
|
24
|
+
BaseSpace,
|
|
25
|
+
CayleySpace,
|
|
26
|
+
ConeNeighborhood,
|
|
27
|
+
ContinuousSpace,
|
|
28
|
+
ContinuousTime,
|
|
29
|
+
DiscreteTime,
|
|
30
|
+
LatticeSpace,
|
|
31
|
+
MeshSpace,
|
|
32
|
+
NetworkSpace,
|
|
33
|
+
PhaseSpace,
|
|
34
|
+
StaticTime,
|
|
35
|
+
)
|
|
36
|
+
from ...core.specs import CensusRecordSpec, CensusSpec, NodeSpec
|
|
37
|
+
from ...core.system import System
|
|
38
|
+
from ...errors import (
|
|
39
|
+
ParameterError,
|
|
40
|
+
PhaseSpaceTooLargeError,
|
|
41
|
+
PipelineError,
|
|
42
|
+
SkcomplexError,
|
|
43
|
+
SolverError,
|
|
44
|
+
SpaceError,
|
|
45
|
+
SpaceTooLargeError,
|
|
46
|
+
ValidationError,
|
|
47
|
+
)
|
|
48
|
+
from ...specs import (
|
|
49
|
+
EntrySpec,
|
|
50
|
+
IssueSpec,
|
|
51
|
+
NeighborReductionSpec,
|
|
52
|
+
ObservableSpec,
|
|
53
|
+
TopologyRequestSpec,
|
|
54
|
+
WienerProcessSpec,
|
|
55
|
+
)
|
|
56
|
+
from ...specs._held_reduction_spec import _HeldReductionSpec
|
|
57
|
+
from ...specs._issue_spec import _ERROR
|
|
58
|
+
from ...types import DomainKind, FormKind, NoiseKind, ProcessKey, VariableKind
|
|
59
|
+
from .._utils import declarations_of, default_of, symbol
|
|
60
|
+
from ..backends import BaseBackend
|
|
61
|
+
from ..problems import BaseProblemSpec, PartitionSpec, ProblemSpec
|
|
62
|
+
from ..problems._neighborhood_kernel import NeighborhoodKernel
|
|
63
|
+
from ..problems._topology_kernel import TopologyKernel
|
|
64
|
+
from ._base import _FIXES, BaseCompiler, BasePass
|
|
65
|
+
from ._compilation import Compilation
|
|
66
|
+
from ._field_lowering import FieldLowering
|
|
67
|
+
from ._learning_compiler import _LearningCompiler
|
|
68
|
+
from ._observables import _check_held_reads, _held_observables, _with_held_observables, _with_held_reductions
|
|
69
|
+
from .passes._compile_encounters import CompileEncountersPass
|
|
70
|
+
from .passes._conserved_noise import ConservedNoisePass
|
|
71
|
+
from .passes._core import _PASSES
|
|
72
|
+
from .passes._fractional_form import FractionalFormPass
|
|
73
|
+
from .passes._lattices import LatticeProblemPass
|
|
74
|
+
from .passes._layout import LayoutPass
|
|
75
|
+
from .passes._noise import NoisePass
|
|
76
|
+
from .passes._operator_compiler import OperatorCompiler
|
|
77
|
+
from .passes._reduction_lowering import ReductionLowering
|
|
78
|
+
|
|
79
|
+
_COVARIANCE_TOLERANCE = 1e-12
|
|
80
|
+
_PROBABILITY_TOLERANCE = 1e-9
|
|
81
|
+
_LISTED_ENCOUNTERS = 3
|
|
82
|
+
_COLLISION_AXES = 2
|
|
83
|
+
_TIME_CLASSES: dict[type, str] = {
|
|
84
|
+
ContinuousTime: 'ContinuousTime()',
|
|
85
|
+
DiscreteTime: 'DiscreteTime()',
|
|
86
|
+
StaticTime: 'StaticTime()',
|
|
87
|
+
}
|
|
88
|
+
_OWN_NEIGHBORHOOD = (LatticeSpace, NetworkSpace, CayleySpace, MeshSpace)
|
|
89
|
+
_REPLACEMENTS = {
|
|
90
|
+
DomainKind.CATEGORICAL: 'a jump, transition, or update law',
|
|
91
|
+
DomainKind.INTEGER: 'a jump or update law',
|
|
92
|
+
DomainKind.BOOLEAN: 'a jump or update law',
|
|
93
|
+
DomainKind.HILBERT: 'a generator or dissipator law',
|
|
94
|
+
}
|
|
95
|
+
_PARTITIONS = ('plan', 'subsystems')
|
|
96
|
+
_PLANNING = frozenset({'nodes', 'census', 'plan'})
|
|
97
|
+
_FIELDS = (
|
|
98
|
+
'system',
|
|
99
|
+
'backend',
|
|
100
|
+
'solver',
|
|
101
|
+
'owners',
|
|
102
|
+
'held',
|
|
103
|
+
*(name for name in Compilation.__annotations__ if name != 'done'),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class PassCompiler(BaseCompiler):
|
|
108
|
+
"""General compiler of a system, which runs passes over a compilation in the order of the fields they share.
|
|
109
|
+
|
|
110
|
+
`prepare(system)` validates the system: it compares the requirements every law declares with the states it
|
|
111
|
+
targets, the space it lives on, and the system's time, checks that one solver runs the laws of every partition,
|
|
112
|
+
and checks the solver and the backend against their declared support. A state of a fractional order needs an order
|
|
113
|
+
in `(0, 1)`, continuous time, and a solver and a backend that integrate fractional orders. It reports every issue
|
|
114
|
+
at once in `report_`, each with its path and fix, and keeps the compilation planned so far in `compilation_`, which
|
|
115
|
+
`run` continues from. Elements and groups are compiled once each, whatever the size of a group. Laws written for one
|
|
116
|
+
member are evaluated for every member, and pair interactions are evaluated for every pair within their cutoff.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
passes:
|
|
120
|
+
The passes, in the order they are registered, or `None` for every pass of the library. The compiler runs
|
|
121
|
+
copies of them.
|
|
122
|
+
|
|
123
|
+
backend:
|
|
124
|
+
The backend instance, or `None` for `NumbaBackend` on systems whose groups hold at least 1000 members in
|
|
125
|
+
total and `NumpyBackend` on the others.
|
|
126
|
+
|
|
127
|
+
solver:
|
|
128
|
+
The solver the problem runs on, or `None` for the default solver of its form.
|
|
129
|
+
|
|
130
|
+
observables:
|
|
131
|
+
The observables to compute at every frame, labelled by their path from the root.
|
|
132
|
+
|
|
133
|
+
partition:
|
|
134
|
+
`'plan'` to compile one problem, or one partition per planned subsystem when no single form runs the
|
|
135
|
+
system, or `'subsystems'` to compile one partition for the elements of the root and one per child
|
|
136
|
+
system, so a co-simulation can advance them with separate solvers.
|
|
137
|
+
|
|
138
|
+
Attributes:
|
|
139
|
+
passes_:
|
|
140
|
+
The copies of the passes the compiler runs.
|
|
141
|
+
|
|
142
|
+
compilation_:
|
|
143
|
+
The compilation planned so far, or `None` when the system tree cannot be flattened or trains a nested
|
|
144
|
+
system.
|
|
145
|
+
|
|
146
|
+
learning_:
|
|
147
|
+
The compiler of a system that holds a `TrainingInteraction`, which compiles its nested system into the
|
|
148
|
+
inner problem of a `LearningProblemSpec`, or `None` for other systems.
|
|
149
|
+
|
|
150
|
+
Examples:
|
|
151
|
+
>>> from skcomplex.core.system import System
|
|
152
|
+
>>> from skcomplex.engine.compile import PassCompiler
|
|
153
|
+
>>> from skcomplex.models.biology.common.populations import ExponentialGrowthInteraction, PopulationElement
|
|
154
|
+
>>> system = System(
|
|
155
|
+
... elements=[PopulationElement('rabbits', n=10)],
|
|
156
|
+
... interactions=[ExponentialGrowthInteraction('growth', target='rabbits', r=0.5)],
|
|
157
|
+
... )
|
|
158
|
+
>>> compiler = PassCompiler().check().prepare(system)
|
|
159
|
+
>>> compiler.report_.ok
|
|
160
|
+
True
|
|
161
|
+
>>> compiler.run().problem_.equations
|
|
162
|
+
{'rabbits.n': n_rabbits*r_growth}
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
passes_: tuple[BasePass, ...]
|
|
166
|
+
compilation_: Compilation | None
|
|
167
|
+
learning_: _LearningCompiler | None
|
|
168
|
+
|
|
169
|
+
def __init__(
|
|
170
|
+
self,
|
|
171
|
+
passes: Sequence[BasePass] | None = None,
|
|
172
|
+
backend: BaseBackend | None = None,
|
|
173
|
+
solver: object = None,
|
|
174
|
+
observables: Sequence[ObservableSpec] = (),
|
|
175
|
+
partition: str = 'plan',
|
|
176
|
+
) -> None:
|
|
177
|
+
super().__init__(backend, solver, observables)
|
|
178
|
+
self.passes = passes
|
|
179
|
+
self.partition = partition
|
|
180
|
+
|
|
181
|
+
def _check(self) -> None:
|
|
182
|
+
"""Raise an error for passes that are not passes or a partition that is not one of the choices.
|
|
183
|
+
|
|
184
|
+
Raises:
|
|
185
|
+
ValidationError:
|
|
186
|
+
A setting is invalid.
|
|
187
|
+
"""
|
|
188
|
+
super()._check()
|
|
189
|
+
if self.passes is not None and not all(isinstance(item, BasePass) for item in self.passes):
|
|
190
|
+
error_msg = 'The passes hold an object that is not a pass. Pass instances of BasePass.'
|
|
191
|
+
raise ValidationError(error_msg)
|
|
192
|
+
if self.partition not in _PARTITIONS:
|
|
193
|
+
error_msg = f'The partition is {self.partition!r}. Choose one of {", ".join(map(repr, _PARTITIONS))}.'
|
|
194
|
+
raise ValidationError(error_msg)
|
|
195
|
+
|
|
196
|
+
def _issues(self, system: System) -> list[IssueSpec]:
|
|
197
|
+
"""Return every issue of a system, of its solver, and of its backend, planning the compilation as it goes.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
system:
|
|
201
|
+
The system, with the observables of the run.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
issues:
|
|
205
|
+
The issues, in the order they were found.
|
|
206
|
+
"""
|
|
207
|
+
passes = self.passes if self.passes is not None else [item() for item in _PASSES]
|
|
208
|
+
self.passes_ = tuple(clone(item) for item in passes)
|
|
209
|
+
self.learning_ = None
|
|
210
|
+
if _LearningCompiler._find_training(system) is not None:
|
|
211
|
+
inner = PassCompiler(passes=self.passes)
|
|
212
|
+
self.learning_ = _LearningCompiler(inner, self.backend, self.solver).check().prepare(system)
|
|
213
|
+
self.compilation_ = None
|
|
214
|
+
return list(self.learning_.report_.issues)
|
|
215
|
+
self.compilation_, issues = self._counted(system)
|
|
216
|
+
if self.compilation_ is None or self.compilation_.census is None:
|
|
217
|
+
return issues
|
|
218
|
+
issues = self._issues_of(self.compilation_)
|
|
219
|
+
if not any(issue.severity == _ERROR for issue in issues):
|
|
220
|
+
issues += self._plan_issues(self.compilation_)
|
|
221
|
+
return issues
|
|
222
|
+
|
|
223
|
+
def _compile(self, initial_state: Mapping[str, object]) -> BaseProblemSpec:
|
|
224
|
+
"""Compile the prepared system into one problem, or one partition per planned subsystem or per child system.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
initial_state:
|
|
228
|
+
Initial values that replace those of the components, by the dotted name of the state.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
problem:
|
|
232
|
+
The compiled problem.
|
|
233
|
+
"""
|
|
234
|
+
if self.learning_ is not None:
|
|
235
|
+
return self.learning_.run(initial_state).problem_
|
|
236
|
+
compilation = self.compilation_
|
|
237
|
+
if compilation is None:
|
|
238
|
+
error_msg = 'The system stopped compiling before its census. Prepare the compiler on a valid system.'
|
|
239
|
+
raise PipelineError(error_msg)
|
|
240
|
+
if self.partition == 'subsystems':
|
|
241
|
+
return self._with_initial_state(self._subsystem_problem(compilation), initial_state)
|
|
242
|
+
problem = self._planned_problem(compilation)
|
|
243
|
+
_check_held_reads(problem, list(compilation.held))
|
|
244
|
+
return self._with_initial_state(problem, initial_state)
|
|
245
|
+
|
|
246
|
+
@staticmethod
|
|
247
|
+
def _with_initial_state(problem: BaseProblemSpec, initial_state: Mapping[str, object]) -> BaseProblemSpec:
|
|
248
|
+
"""Return a problem whose initial state takes given values of some states.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
problem:
|
|
252
|
+
The compiled problem.
|
|
253
|
+
|
|
254
|
+
initial_state:
|
|
255
|
+
The initial values by dotted state name.
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
problem:
|
|
259
|
+
The problem with the new initial state, or the same problem when no value is given.
|
|
260
|
+
|
|
261
|
+
Raises:
|
|
262
|
+
ValidationError:
|
|
263
|
+
A name is not a state of the problem, or a value has the wrong shape.
|
|
264
|
+
"""
|
|
265
|
+
if not initial_state:
|
|
266
|
+
return problem
|
|
267
|
+
names = problem.states.names
|
|
268
|
+
unknown = set(initial_state) - set(names)
|
|
269
|
+
if unknown:
|
|
270
|
+
error_msg = (
|
|
271
|
+
f'The initial state names {", ".join(sorted(unknown))}, which are not states of the system. Use the '
|
|
272
|
+
f'dotted names of states, such as {", ".join(list(names)[:3])}.'
|
|
273
|
+
)
|
|
274
|
+
raise ValidationError(error_msg)
|
|
275
|
+
state = problem.initial_state.copy()
|
|
276
|
+
for name, value in initial_state.items():
|
|
277
|
+
entry = problem.states.entry(name)
|
|
278
|
+
try:
|
|
279
|
+
state[entry.indices] = entry.encode(value)
|
|
280
|
+
except ValueError as error:
|
|
281
|
+
error_msg = f'The initial value of {name} does not fit its shape {entry.shape}: {error}'
|
|
282
|
+
raise ValidationError(error_msg) from error
|
|
283
|
+
return dataclasses.replace(problem, initial_state=state)
|
|
284
|
+
|
|
285
|
+
def _new_compilation(self, system: System, held: tuple[str, ...] = ()) -> Compilation:
|
|
286
|
+
"""Return a new compilation of a system, with no pass run yet."""
|
|
287
|
+
compilation = Compilation(system, self.backend, self.solver, held=held)
|
|
288
|
+
compilation.done = set()
|
|
289
|
+
return compilation
|
|
290
|
+
|
|
291
|
+
@staticmethod
|
|
292
|
+
def _present(compilation: Compilation) -> set[str]:
|
|
293
|
+
"""Return the fields a compilation holds: its inputs and the fields set so far."""
|
|
294
|
+
return {name for name in _FIELDS if getattr(compilation, name) is not None}
|
|
295
|
+
|
|
296
|
+
@staticmethod
|
|
297
|
+
def _fork(compilation: Compilation, owners: frozenset[str]) -> Compilation:
|
|
298
|
+
"""Return the compilation of a partition, which shares the nodes, the census, and the plan."""
|
|
299
|
+
fork = Compilation(compilation.system, compilation.backend, compilation.solver, owners, compilation.held)
|
|
300
|
+
fork.nodes, fork.census, fork.plan = compilation.nodes, compilation.census, compilation.plan
|
|
301
|
+
fork.done = {
|
|
302
|
+
item
|
|
303
|
+
for item in Compilation._required(compilation.done, 'done')
|
|
304
|
+
if isinstance(item, BasePass) and set(item._get_writes()) <= _PLANNING
|
|
305
|
+
}
|
|
306
|
+
return fork
|
|
307
|
+
|
|
308
|
+
def _run_passes(self, compilation: Compilation, until: str = 'problem') -> Compilation:
|
|
309
|
+
"""Run the passes a field needs that the compilation has not run yet, in the order of their fields.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
compilation:
|
|
313
|
+
The compilation, which the passes change in place.
|
|
314
|
+
|
|
315
|
+
until:
|
|
316
|
+
The field to produce. The passes that neither write it nor write a field that those passes read do not
|
|
317
|
+
run.
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
compilation:
|
|
321
|
+
The same compilation, holding the field.
|
|
322
|
+
|
|
323
|
+
Raises:
|
|
324
|
+
PipelineError:
|
|
325
|
+
The passes cannot be ordered.
|
|
326
|
+
"""
|
|
327
|
+
needed = self._needed(self.passes_, until)
|
|
328
|
+
done = Compilation._required(compilation.done, 'done')
|
|
329
|
+
for item in self._ordered(self.passes_, self._present(compilation)):
|
|
330
|
+
if item in needed and item not in done:
|
|
331
|
+
item.check().prepare(compilation).run()
|
|
332
|
+
done.add(item)
|
|
333
|
+
return compilation
|
|
334
|
+
|
|
335
|
+
def _compiled(self, compilation: Compilation) -> ProblemSpec:
|
|
336
|
+
"""Return the problem of a compilation, running every pass it has not run yet."""
|
|
337
|
+
return Compilation._required(self._run_passes(compilation).problem, 'problem')
|
|
338
|
+
|
|
339
|
+
def _partitioned(self, compilation: Compilation, plan: list[tuple[str, frozenset[str]]]) -> ProblemSpec:
|
|
340
|
+
"""Return the problem of a system split into partitions, each compiled with the laws of its owners."""
|
|
341
|
+
partitions = []
|
|
342
|
+
for name, owners in plan:
|
|
343
|
+
problem = self._compiled(self._fork(compilation, owners))
|
|
344
|
+
owned = [entry.indices for entry in problem.states.entries if entry.name.rpartition('.')[0] in owners]
|
|
345
|
+
indices = np.concatenate([np.arange(item.start, item.stop) for item in owned]) if owned else np.zeros(0)
|
|
346
|
+
partitions.append(PartitionSpec(name, problem, indices.astype(np.intp), owners))
|
|
347
|
+
first = partitions[0].problem
|
|
348
|
+
equations = {
|
|
349
|
+
key: value
|
|
350
|
+
for item in partitions
|
|
351
|
+
for key, value in item.problem.equations.items()
|
|
352
|
+
if key.partition('.')[0] in item.owners
|
|
353
|
+
}
|
|
354
|
+
symbols = {
|
|
355
|
+
key: item.problem.equation_symbols[key]
|
|
356
|
+
for item in partitions
|
|
357
|
+
for key in item.problem.equations
|
|
358
|
+
if key in equations
|
|
359
|
+
}
|
|
360
|
+
return ProblemSpec(
|
|
361
|
+
form=FormKind.COUPLED,
|
|
362
|
+
states=first.states,
|
|
363
|
+
parameters=first.parameters,
|
|
364
|
+
initial_state=first.initial_state,
|
|
365
|
+
initial_parameters=first.initial_parameters,
|
|
366
|
+
time=first.time,
|
|
367
|
+
symbols=first.symbols,
|
|
368
|
+
equations=equations,
|
|
369
|
+
equation_symbols=symbols,
|
|
370
|
+
has_callables=any(item.problem.has_callables for item in partitions),
|
|
371
|
+
has_group_sums=any(item.problem.has_group_sums for item in partitions),
|
|
372
|
+
elements=first.elements,
|
|
373
|
+
interactions=first.interactions,
|
|
374
|
+
system=compilation.system,
|
|
375
|
+
agents=tuple(agents for item in partitions for agents in item.problem.agents),
|
|
376
|
+
agent_space=next((item.problem.agent_space for item in partitions if item.problem.agents), None),
|
|
377
|
+
partitions=tuple(partitions),
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
def _planned_problem(self, compilation: Compilation) -> ProblemSpec:
|
|
381
|
+
"""Return the problem of a validated compilation, one problem or one partition per planned subsystem.
|
|
382
|
+
|
|
383
|
+
The owners of a partition are the elements and groups of its subsystem whose lowered laws it holds.
|
|
384
|
+
"""
|
|
385
|
+
plan = Compilation._required(compilation.plan, 'plan')
|
|
386
|
+
if len(plan.partitions) <= 1:
|
|
387
|
+
return self._compiled(compilation)
|
|
388
|
+
kinds = Compilation._required(self._run_passes(compilation, until='kinds').kinds, 'kinds')
|
|
389
|
+
owners = [(item.name, frozenset(owner for owner in kinds if item.holds(owner))) for item in plan.partitions]
|
|
390
|
+
return self._partitioned(compilation, owners)
|
|
391
|
+
|
|
392
|
+
def _subsystem_problem(self, compilation: Compilation) -> ProblemSpec:
|
|
393
|
+
"""Return the problem of a system as one partition for the elements of its root and one per child system."""
|
|
394
|
+
system = compilation.system
|
|
395
|
+
elements = {node.path for node in Compilation._required(compilation.nodes, 'nodes') if not node.interaction}
|
|
396
|
+
own = frozenset(path for path in elements if '/' not in path)
|
|
397
|
+
plan = [(system.label, own)] if own else []
|
|
398
|
+
for child in system.systems:
|
|
399
|
+
plan.append((child.label, frozenset(path for path in elements if path.startswith(f'{child.label}/'))))
|
|
400
|
+
return self._partitioned(compilation, plan)
|
|
401
|
+
|
|
402
|
+
@staticmethod
|
|
403
|
+
def _compiler_issue(system: System, compiler: str) -> IssueSpec:
|
|
404
|
+
"""Return the issue of a system that another compiler compiles, naming that compiler."""
|
|
405
|
+
message = f'The system {system.label} is compiled by {compiler}, not by PassCompiler.'
|
|
406
|
+
return IssueSpec('compiler', system.label, message, f'Pass `compiler={compiler}()`.')
|
|
407
|
+
|
|
408
|
+
def _counted(self, system: System) -> tuple[Compilation | None, list[IssueSpec]]:
|
|
409
|
+
"""Return the compilation of a system through the census of its laws, or the issues that stop it before.
|
|
410
|
+
|
|
411
|
+
The compilation stops after flattening for a system that another compiler compiles. When laws read reductions of
|
|
412
|
+
agents, the compilation starts again from a system tree that holds each of them in an element.
|
|
413
|
+
"""
|
|
414
|
+
compilation = self._new_compilation(system)
|
|
415
|
+
try:
|
|
416
|
+
self._run_passes(compilation, until='nodes')
|
|
417
|
+
except PhaseSpaceTooLargeError as error:
|
|
418
|
+
fix = 'Use fewer points on the axes of the phase space, or raise its limit.'
|
|
419
|
+
return None, [IssueSpec('space-size', system.label, str(error), fix, error=PhaseSpaceTooLargeError)]
|
|
420
|
+
except SkcomplexError as error:
|
|
421
|
+
fix = 'Pass elements, groups, interactions, and systems as children.'
|
|
422
|
+
return None, [self._issue_of(error, system.label, 'structure', fix)]
|
|
423
|
+
if OperatorCompiler._contains_operator(system):
|
|
424
|
+
return compilation, [self._compiler_issue(system, 'OperatorCompiler')]
|
|
425
|
+
held = _held_observables(system, Compilation._required(compilation.nodes, 'nodes'))
|
|
426
|
+
if held:
|
|
427
|
+
tree, paths = _with_held_observables(system, held)
|
|
428
|
+
compilation = self._new_compilation(tree, held=tuple(paths))
|
|
429
|
+
self._run_passes(compilation, until='census')
|
|
430
|
+
try:
|
|
431
|
+
reductions = self._held_reductions(Compilation._required(compilation.census, 'census'), symbol('t'))
|
|
432
|
+
except ValidationError as error:
|
|
433
|
+
fix = 'Reduce an expression of the agents of one group.'
|
|
434
|
+
return None, [self._issue_of(error, system.label, 'reduction', fix)]
|
|
435
|
+
if not reductions:
|
|
436
|
+
return compilation, []
|
|
437
|
+
tree = _with_held_reductions(compilation.system, reductions)
|
|
438
|
+
compilation = self._new_compilation(tree, held=compilation.held)
|
|
439
|
+
return self._run_passes(compilation, until='census'), []
|
|
440
|
+
|
|
441
|
+
def _plan_issues(self, compilation: Compilation) -> list[IssueSpec]:
|
|
442
|
+
"""Return the issues of the partitions of a system, lowering its laws as far as their classes decide."""
|
|
443
|
+
try:
|
|
444
|
+
self._run_passes(compilation, until='plan')
|
|
445
|
+
except SkcomplexError as error:
|
|
446
|
+
fix = 'Correct the component as the message describes.'
|
|
447
|
+
return [self._issue_of(error, compilation.system.label, 'value', fix)]
|
|
448
|
+
return list(Compilation._required(compilation.plan, 'plan').issues)
|
|
449
|
+
|
|
450
|
+
@staticmethod
|
|
451
|
+
def _issues_of(compilation: Compilation) -> list[IssueSpec]:
|
|
452
|
+
"""Return the issues of a compilation planned past the census."""
|
|
453
|
+
system, solver = compilation.system, compilation.solver
|
|
454
|
+
nodes = Compilation._required(compilation.nodes, 'nodes')
|
|
455
|
+
census = Compilation._required(compilation.census, 'census')
|
|
456
|
+
records = census.records
|
|
457
|
+
issues = PassCompiler._census_issues(compilation)
|
|
458
|
+
issues += PassCompiler._bound_issues(nodes)
|
|
459
|
+
issues += PassCompiler._law_issues(records, FractionalFormPass._declared_times(system))
|
|
460
|
+
issues += PassCompiler._equation_issues(compilation)
|
|
461
|
+
issues += PassCompiler._satisfiability_issues(nodes)
|
|
462
|
+
issues += PassCompiler._neighborhood_issues(records, nodes)
|
|
463
|
+
issues += PassCompiler._around_issues(records)
|
|
464
|
+
issues += PassCompiler._nonlocal_issues(records, nodes)
|
|
465
|
+
issues += PassCompiler._coordinate_issues(records, nodes)
|
|
466
|
+
issues += PassCompiler._space_issues(system, nodes)
|
|
467
|
+
issues += LatticeProblemPass._schedule_issues(compilation)
|
|
468
|
+
issues += ConservedNoisePass._conserved_issues(compilation)
|
|
469
|
+
issues += FractionalFormPass._order_issues(compilation)
|
|
470
|
+
issues += PassCompiler._probability_issues(compilation)
|
|
471
|
+
issues += PassCompiler._request_issues(compilation)
|
|
472
|
+
if solver is not None:
|
|
473
|
+
issues += PassCompiler._solver_issues(solver, census, system)
|
|
474
|
+
issues += PassCompiler._noise_issues(compilation, records)
|
|
475
|
+
return issues
|
|
476
|
+
|
|
477
|
+
@staticmethod
|
|
478
|
+
def _roles(passes: Sequence['BasePass']) -> dict[str, tuple[list[int], list[int], list[int]]]:
|
|
479
|
+
"""Return the producers, refiners, and readers of every field by the positions of their passes.
|
|
480
|
+
|
|
481
|
+
A producer writes a field without reading it, a refiner reads and writes it, and a reader only reads it.
|
|
482
|
+
"""
|
|
483
|
+
roles: dict[str, tuple[list[int], list[int], list[int]]] = defaultdict(lambda: ([], [], []))
|
|
484
|
+
for index, item in enumerate(passes):
|
|
485
|
+
for name in item._get_writes():
|
|
486
|
+
roles[name][1 if name in item._get_reads() else 0].append(index)
|
|
487
|
+
for name in item._get_reads():
|
|
488
|
+
if name not in item._get_writes():
|
|
489
|
+
roles[name][2].append(index)
|
|
490
|
+
return roles
|
|
491
|
+
|
|
492
|
+
@staticmethod
|
|
493
|
+
def _check_inputs(
|
|
494
|
+
passes: Sequence['BasePass'],
|
|
495
|
+
roles: dict[str, tuple[list[int], list[int], list[int]]],
|
|
496
|
+
present: Collection[str],
|
|
497
|
+
) -> None:
|
|
498
|
+
"""Raise an error for a field read but neither present nor produced, or produced by two passes."""
|
|
499
|
+
for name, (producers, refiners, readers) in roles.items():
|
|
500
|
+
if len(producers) > 1:
|
|
501
|
+
names = ' and '.join(type(passes[index]).__name__ for index in producers)
|
|
502
|
+
error_msg = (
|
|
503
|
+
f'The passes {names} both produce the field {name!r}. Let one produce it and the others refine it.'
|
|
504
|
+
)
|
|
505
|
+
raise PipelineError(error_msg)
|
|
506
|
+
if not producers and name not in present and (refiners or readers):
|
|
507
|
+
index = (refiners or readers)[0]
|
|
508
|
+
error_msg = (
|
|
509
|
+
f'The pass {type(passes[index]).__name__} reads the field {name!r}, which no pass produces and the '
|
|
510
|
+
'compilation does not hold. Add the pass that produces it.'
|
|
511
|
+
)
|
|
512
|
+
raise PipelineError(error_msg)
|
|
513
|
+
|
|
514
|
+
@staticmethod
|
|
515
|
+
def _edges(roles: dict[str, tuple[list[int], list[int], list[int]]]) -> dict[int, set[int]]:
|
|
516
|
+
"""Return the passes that must run after every pass: refiners after producers, readers after both."""
|
|
517
|
+
edges: dict[int, set[int]] = defaultdict(set)
|
|
518
|
+
for producers, refiners, readers in roles.values():
|
|
519
|
+
for first in producers:
|
|
520
|
+
edges[first] |= {*refiners, *readers}
|
|
521
|
+
for first in refiners:
|
|
522
|
+
edges[first] |= set(readers)
|
|
523
|
+
return edges
|
|
524
|
+
|
|
525
|
+
@staticmethod
|
|
526
|
+
def _needed(passes: Sequence['BasePass'], field: str) -> set['BasePass']:
|
|
527
|
+
"""Return the passes that write a field and, in turn, the passes that write the fields they read."""
|
|
528
|
+
writers: dict[str, list[BasePass]] = defaultdict(list)
|
|
529
|
+
for item in passes:
|
|
530
|
+
for name in item._get_writes():
|
|
531
|
+
writers[name].append(item)
|
|
532
|
+
needed: set[BasePass] = set()
|
|
533
|
+
pending = [field]
|
|
534
|
+
seen: set[str] = set()
|
|
535
|
+
while pending:
|
|
536
|
+
name = pending.pop()
|
|
537
|
+
if name in seen:
|
|
538
|
+
continue
|
|
539
|
+
seen.add(name)
|
|
540
|
+
for item in writers[name]:
|
|
541
|
+
needed.add(item)
|
|
542
|
+
pending += item._get_reads()
|
|
543
|
+
return needed
|
|
544
|
+
|
|
545
|
+
@staticmethod
|
|
546
|
+
def _ordered(passes: Sequence['BasePass'], present: Collection[str] = ()) -> list['BasePass']:
|
|
547
|
+
"""Return passes in an order where every field is produced, then refined, then read.
|
|
548
|
+
|
|
549
|
+
A pass that writes a field without reading it produces the field, and runs before the passes that refine it,
|
|
550
|
+
which read and write it, and those run before the passes that only read it. Passes that the fields leave
|
|
551
|
+
unordered run in the order they are given, so refiners of one field run in the order they are given.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
passes:
|
|
555
|
+
The passes, in the order they are registered.
|
|
556
|
+
|
|
557
|
+
present:
|
|
558
|
+
The fields the compilation already holds, which no pass needs to produce.
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
passes:
|
|
562
|
+
The passes in the order they run.
|
|
563
|
+
|
|
564
|
+
Raises:
|
|
565
|
+
PipelineError:
|
|
566
|
+
A pass reads a field that no pass produces and the compilation does not hold, two passes produce one
|
|
567
|
+
field, or the passes read each other's fields in a cycle.
|
|
568
|
+
|
|
569
|
+
Examples:
|
|
570
|
+
>>> from skcomplex.engine.compile import BasePass, PassCompiler
|
|
571
|
+
>>> class LowerPass(BasePass):
|
|
572
|
+
... def _get_reads(self):
|
|
573
|
+
... return ('layout',)
|
|
574
|
+
... def _get_writes(self):
|
|
575
|
+
... return ('lowered',)
|
|
576
|
+
>>> class DeclarePass(BasePass):
|
|
577
|
+
... def _get_reads(self):
|
|
578
|
+
... return ('nodes',)
|
|
579
|
+
... def _get_writes(self):
|
|
580
|
+
... return ('layout',)
|
|
581
|
+
>>> ordered = PassCompiler._ordered([LowerPass(), DeclarePass()], present=['nodes'])
|
|
582
|
+
>>> [type(item).__name__ for item in ordered]
|
|
583
|
+
['DeclarePass', 'LowerPass']
|
|
584
|
+
"""
|
|
585
|
+
roles = PassCompiler._roles(passes)
|
|
586
|
+
PassCompiler._check_inputs(passes, roles, present)
|
|
587
|
+
edges = PassCompiler._edges(roles)
|
|
588
|
+
waiting = [0] * len(passes)
|
|
589
|
+
for targets in edges.values():
|
|
590
|
+
for target in targets:
|
|
591
|
+
waiting[target] += 1
|
|
592
|
+
ready = [index for index, count in enumerate(waiting) if not count]
|
|
593
|
+
heapq.heapify(ready)
|
|
594
|
+
ordered: list[int] = []
|
|
595
|
+
while ready:
|
|
596
|
+
index = heapq.heappop(ready)
|
|
597
|
+
ordered.append(index)
|
|
598
|
+
for target in edges[index]:
|
|
599
|
+
waiting[target] -= 1
|
|
600
|
+
if not waiting[target]:
|
|
601
|
+
heapq.heappush(ready, target)
|
|
602
|
+
if len(ordered) < len(passes):
|
|
603
|
+
names = ', '.join(type(item).__name__ for index, item in enumerate(passes) if index not in set(ordered))
|
|
604
|
+
error_msg = f'The passes {names} read each other\'s fields in a cycle. Split one of them.'
|
|
605
|
+
raise PipelineError(error_msg)
|
|
606
|
+
return [passes[index] for index in ordered]
|
|
607
|
+
|
|
608
|
+
@staticmethod
|
|
609
|
+
def _names(classes: tuple[type | None, ...]) -> str:
|
|
610
|
+
"""Return the names of classes joined by `or`, with `no space` for `None`."""
|
|
611
|
+
return ' or '.join('no space' if item is None else item.__name__ for item in classes)
|
|
612
|
+
|
|
613
|
+
@staticmethod
|
|
614
|
+
def _layer_issues(node: NodeSpec, space: BaseSpace | None) -> list[IssueSpec]:
|
|
615
|
+
"""Return the issue of an interaction over neighbours that names a layer its network does not have."""
|
|
616
|
+
layer = getattr(node.component, 'layer', None)
|
|
617
|
+
labels = tuple(getattr(space, 'graphs_', (None,)))
|
|
618
|
+
if layer is None or layer in labels:
|
|
619
|
+
return []
|
|
620
|
+
known = ', '.join(repr(label) for label in labels)
|
|
621
|
+
message = (
|
|
622
|
+
f'The interaction runs on the layer {layer!r}, which the network does not have. Its layers are {known}.'
|
|
623
|
+
)
|
|
624
|
+
fix = (
|
|
625
|
+
f'Name one of the layers {known}, or add the layer with '
|
|
626
|
+
f'`NetworkSpace(graph, layers=[LayerSpec({layer!r}, ...)])`.'
|
|
627
|
+
)
|
|
628
|
+
return [IssueSpec('binding', node.path, message, fix)]
|
|
629
|
+
|
|
630
|
+
@staticmethod
|
|
631
|
+
def _hyperedge_issues(node: NodeSpec, space: NetworkSpace, edges: NodeSpec | None) -> list[IssueSpec]:
|
|
632
|
+
"""Return the issues of a hyperedge interaction whose size, or whose edge group, its hyperedges do not fit.
|
|
633
|
+
|
|
634
|
+
Args:
|
|
635
|
+
node:
|
|
636
|
+
The hyperedge interaction.
|
|
637
|
+
|
|
638
|
+
space:
|
|
639
|
+
The network of its nodes.
|
|
640
|
+
|
|
641
|
+
edges:
|
|
642
|
+
The group on edges its second role binds, or `None`.
|
|
643
|
+
|
|
644
|
+
Returns:
|
|
645
|
+
issues:
|
|
646
|
+
The issue of a size no hyperedge has, or of the first two members of a hyperedge joined by no edge.
|
|
647
|
+
"""
|
|
648
|
+
size = getattr(node.component, 'size', None)
|
|
649
|
+
sizes = sorted({len(hyperedge) for hyperedge in space.hyperedges_})
|
|
650
|
+
if size is not None and size not in sizes:
|
|
651
|
+
known = ', '.join(map(str, sizes))
|
|
652
|
+
message = (
|
|
653
|
+
f'The interaction runs on hyperedges of size {size}, but the network has hyperedges of size {known}.'
|
|
654
|
+
)
|
|
655
|
+
fix = f'Give the interaction one of the sizes {known}, or add hyperedges of size {size}.'
|
|
656
|
+
return [IssueSpec('binding', node.path, message, fix)]
|
|
657
|
+
if edges is None:
|
|
658
|
+
return []
|
|
659
|
+
layer = getattr(edges.component, 'layer', None)
|
|
660
|
+
graph = space.graphs_.get(layer)
|
|
661
|
+
if graph is None:
|
|
662
|
+
return []
|
|
663
|
+
missing = [
|
|
664
|
+
hyperedge[:2]
|
|
665
|
+
for hyperedge in space.hyperedges_
|
|
666
|
+
if (size is None or len(hyperedge) == size)
|
|
667
|
+
and not graph.has_edge(*(list(space.graph.nodes)[index] for index in hyperedge[:2]))
|
|
668
|
+
]
|
|
669
|
+
if not missing:
|
|
670
|
+
return []
|
|
671
|
+
message = (
|
|
672
|
+
f'The edge group {edges.path} has no edge between the first two members of the hyperedges at the nodes '
|
|
673
|
+
f'{missing[:3]}.'
|
|
674
|
+
)
|
|
675
|
+
fix = 'Order every hyperedge so an edge of the layer of the edge group joins its first two members.'
|
|
676
|
+
return [IssueSpec('binding', node.path, message, fix)]
|
|
677
|
+
|
|
678
|
+
@staticmethod
|
|
679
|
+
def _binding_issues(nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
680
|
+
"""Return the interactions over hyperedges, or over neighbours with an edge group, on a space without them.
|
|
681
|
+
|
|
682
|
+
An interaction over neighbours of members of a space without edges runs only the laws of the members.
|
|
683
|
+
"""
|
|
684
|
+
by_path = {node.path: node for node in nodes}
|
|
685
|
+
issues = []
|
|
686
|
+
for node in nodes:
|
|
687
|
+
interaction = node.component
|
|
688
|
+
if isinstance(interaction, NeighborInteraction):
|
|
689
|
+
over = 'neighbors'
|
|
690
|
+
elif isinstance(interaction, HyperedgeInteraction):
|
|
691
|
+
over = 'hyperedges'
|
|
692
|
+
else:
|
|
693
|
+
continue
|
|
694
|
+
roles = declarations_of(type(interaction), VariableKind.ROLE)
|
|
695
|
+
labels = [getattr(interaction, name, None) for name in roles]
|
|
696
|
+
bound = [
|
|
697
|
+
by_path.get(f'{node.scope}{label}')
|
|
698
|
+
for value in labels
|
|
699
|
+
if value is not None
|
|
700
|
+
for label in (value if isinstance(value, list | tuple) else [value])
|
|
701
|
+
]
|
|
702
|
+
members = [item for item in bound if item is not None and getattr(item.component, 'on', None) != 'edges']
|
|
703
|
+
target = next(iter(members), None)
|
|
704
|
+
space = target.space if target is not None else node.space
|
|
705
|
+
offered = (
|
|
706
|
+
isinstance(space, LatticeSpace | NetworkSpace | CayleySpace)
|
|
707
|
+
if over == 'neighbors'
|
|
708
|
+
else bool(getattr(space, 'hyperedges_', ()))
|
|
709
|
+
)
|
|
710
|
+
if not offered and over == 'neighbors' and len(members) == len(bound):
|
|
711
|
+
continue
|
|
712
|
+
if not offered:
|
|
713
|
+
needs = 'a lattice or network space' if over == 'neighbors' else 'a network space with hyperedges'
|
|
714
|
+
message = f'The binding over {over} needs {needs}, but the bound members live on {space!r}.'
|
|
715
|
+
issues.append(IssueSpec('binding', node.path, message, f'Give the bound group {needs}.'))
|
|
716
|
+
continue
|
|
717
|
+
if over == 'hyperedges' and isinstance(space, NetworkSpace):
|
|
718
|
+
edges = next((item for item in bound if item is not None and item not in members), None)
|
|
719
|
+
issues += PassCompiler._hyperedge_issues(node, space, edges)
|
|
720
|
+
continue
|
|
721
|
+
issues += PassCompiler._layer_issues(node, space)
|
|
722
|
+
return issues
|
|
723
|
+
|
|
724
|
+
@staticmethod
|
|
725
|
+
def _shape_issues(nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
726
|
+
"""Return the shaped parameters whose roles are not bound to groups."""
|
|
727
|
+
groups = LayoutPass._group_sizes(nodes)
|
|
728
|
+
issues = []
|
|
729
|
+
for node in nodes:
|
|
730
|
+
declarations = {
|
|
731
|
+
**declarations_of(node.component_type, VariableKind.STATE),
|
|
732
|
+
**declarations_of(node.component_type, VariableKind.PARAMETER),
|
|
733
|
+
}
|
|
734
|
+
for name, declaration in declarations.items():
|
|
735
|
+
if declaration.shape is None:
|
|
736
|
+
continue
|
|
737
|
+
try:
|
|
738
|
+
LayoutPass._role_shape(node, name, declaration, groups)
|
|
739
|
+
except ValidationError as error:
|
|
740
|
+
path = f'{node.path}.{name}'
|
|
741
|
+
fix = f'Bind every role of the shape {declaration.shape} of {path} to a group.'
|
|
742
|
+
issues.append(IssueSpec('parameter-shape', path, str(error), fix, error=ParameterError))
|
|
743
|
+
return issues
|
|
744
|
+
|
|
745
|
+
@staticmethod
|
|
746
|
+
def _bound_issues(nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
747
|
+
"""Return the adaptive parameters whose initial values lie outside their bounds."""
|
|
748
|
+
issues = []
|
|
749
|
+
for node in nodes:
|
|
750
|
+
for name, declaration in declarations_of(node.component_type, VariableKind.STATE).items():
|
|
751
|
+
if declaration.bounds is None:
|
|
752
|
+
continue
|
|
753
|
+
lower, upper = declaration.bounds
|
|
754
|
+
value = np.asarray(LayoutPass._value_of(node, name), dtype=float)
|
|
755
|
+
if np.all((value >= lower) & (value <= upper)):
|
|
756
|
+
continue
|
|
757
|
+
path = f'{node.path}.{name}'
|
|
758
|
+
message = (
|
|
759
|
+
f'The adaptive parameter {path} starts at {value.tolist()}, outside its bounds ({lower}, {upper}).'
|
|
760
|
+
)
|
|
761
|
+
fix = f'Give {path} an initial value inside its bounds ({lower}, {upper}).'
|
|
762
|
+
issues.append(IssueSpec('parameter-bounds', path, message, fix, error=ParameterError))
|
|
763
|
+
return issues
|
|
764
|
+
|
|
765
|
+
@staticmethod
|
|
766
|
+
def _space_issues(system: System, nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
767
|
+
"""Return the visuals that need options their space lacks, and the spaces whose own check fails."""
|
|
768
|
+
issues = []
|
|
769
|
+
spaces: dict[int, tuple[str, BaseSpace]] = {}
|
|
770
|
+
for node in nodes:
|
|
771
|
+
space = getattr(node.component, 'space', None) or node.space
|
|
772
|
+
visual = getattr(node.component, 'visual', None)
|
|
773
|
+
if space is not None:
|
|
774
|
+
spaces.setdefault(id(space), (node.path, space))
|
|
775
|
+
if space is not None and 'image' in space._get_lacks() and getattr(visual, 'kind', None) == 'image':
|
|
776
|
+
message = (
|
|
777
|
+
f'The image visual of {node.path} needs a regular lattice, but its space is {type(space).__name__}.'
|
|
778
|
+
)
|
|
779
|
+
default = getattr(space, 'default_visual_', None)
|
|
780
|
+
fix = f'Use the {default!r} visual.' if default is not None else 'Use another visual.'
|
|
781
|
+
issues.append(IssueSpec('visual-unsupported', node.path, message, fix))
|
|
782
|
+
if system.space is not None:
|
|
783
|
+
spaces.setdefault(id(system.space), (system.label, system.space))
|
|
784
|
+
for path, space in spaces.values():
|
|
785
|
+
try:
|
|
786
|
+
space.check().prepare()
|
|
787
|
+
except SpaceTooLargeError as error:
|
|
788
|
+
fix = 'Ask for a smaller ball, or raise max_sites.'
|
|
789
|
+
issues.append(IssueSpec('space-too-large', path, str(error), fix, error=SpaceTooLargeError))
|
|
790
|
+
except ValidationError as error:
|
|
791
|
+
fix = f'Give the {type(space).__name__} a shape, a boundary, and a geometry that it supports.'
|
|
792
|
+
holder = path.rpartition('/')[0] or system.label
|
|
793
|
+
issues.append(IssueSpec('space-invalid', holder, str(error), fix, error=SpaceError))
|
|
794
|
+
return issues
|
|
795
|
+
|
|
796
|
+
@staticmethod
|
|
797
|
+
def _law_issues(records: list[CensusRecordSpec], times: dict[str, type | None]) -> list[IssueSpec]:
|
|
798
|
+
"""Return the laws whose space or time their requirements do not accept."""
|
|
799
|
+
issues = []
|
|
800
|
+
for record in records:
|
|
801
|
+
time = times.get(record.path.rpartition('/')[0])
|
|
802
|
+
law = record.law
|
|
803
|
+
requires = law._get_requirements()
|
|
804
|
+
name = f'{type(law).__name__} of {record.path}'
|
|
805
|
+
if requires.space and not isinstance(record.space, requires.space):
|
|
806
|
+
lives = type(record.space).__name__ if record.space is not None else 'no space'
|
|
807
|
+
needs = PassCompiler._names(requires.space)
|
|
808
|
+
message = f'The {name} needs a {needs}, but the component lives on {lives}.'
|
|
809
|
+
issues.append(
|
|
810
|
+
IssueSpec('law-space', record.path, message, 'Give the system a space of a supported class.'),
|
|
811
|
+
)
|
|
812
|
+
if time is not None and requires.time and not issubclass(time, requires.time):
|
|
813
|
+
needs = PassCompiler._names(requires.time)
|
|
814
|
+
message = f'The {name} needs {needs}, but its system declares {time.__name__}.'
|
|
815
|
+
classes = ' or '.join(f'`{_TIME_CLASSES[item]}`' for item in requires.time)
|
|
816
|
+
fix = f'Declare {classes} for its system, or use laws that run in {time.__name__}.'
|
|
817
|
+
issues.append(IssueSpec('law-time', record.path, message, fix))
|
|
818
|
+
return issues
|
|
819
|
+
|
|
820
|
+
@staticmethod
|
|
821
|
+
def _equation_issues(compilation: Compilation) -> list[IssueSpec]:
|
|
822
|
+
"""Return the equations under static time with no target or with a target that is not a state."""
|
|
823
|
+
if not isinstance(compilation.system.time, StaticTime):
|
|
824
|
+
return []
|
|
825
|
+
issues = []
|
|
826
|
+
for record in Compilation._required(compilation.census, 'census').records:
|
|
827
|
+
law = record.law
|
|
828
|
+
if not isinstance(law, EquationLaw) or record.targets:
|
|
829
|
+
continue
|
|
830
|
+
problem = 'names no target' if law.target is None else f'names the target {law.target}, which is no state'
|
|
831
|
+
message = f'The EquationLaw of {record.path} {problem}. An equation under static time solves for one state.'
|
|
832
|
+
fix = 'Pass the symbol of a state of the system as `target`.'
|
|
833
|
+
issues.append(IssueSpec('equation-target', record.path, message, fix))
|
|
834
|
+
return issues
|
|
835
|
+
|
|
836
|
+
@staticmethod
|
|
837
|
+
def _satisfiability_issues(nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
838
|
+
"""Return the satisfiability interactions that bind a state that is not Boolean."""
|
|
839
|
+
by_path = {node.path: node for node in nodes}
|
|
840
|
+
issues = []
|
|
841
|
+
for node in nodes:
|
|
842
|
+
component = node.component
|
|
843
|
+
if not isinstance(component, SatisfiabilityInteraction):
|
|
844
|
+
continue
|
|
845
|
+
scope = node.path.rpartition('/')[0]
|
|
846
|
+
role = getattr(component, component._get_role('target'))
|
|
847
|
+
group = by_path.get(f'{scope}/{role}' if scope else role)
|
|
848
|
+
declaration = (
|
|
849
|
+
None
|
|
850
|
+
if group is None
|
|
851
|
+
else declarations_of(group.component_type, VariableKind.STATE).get(component.state)
|
|
852
|
+
)
|
|
853
|
+
if declaration is None or EntrySpec._domain_kind(declaration.domain) == DomainKind.BOOLEAN:
|
|
854
|
+
continue
|
|
855
|
+
message = (
|
|
856
|
+
f'The SatisfiabilityInteraction {node.path} decides the state {component.state} of {role}, which is '
|
|
857
|
+
'not Boolean.'
|
|
858
|
+
)
|
|
859
|
+
fix = 'Declare the state with `StateSpec(domain=FiniteEnumeratedSet([0, 1]))`.'
|
|
860
|
+
issues.append(IssueSpec('law-domain', node.path, message, fix))
|
|
861
|
+
return issues
|
|
862
|
+
|
|
863
|
+
@staticmethod
|
|
864
|
+
def _reductions_of(value: object) -> list[NeighborReductionSpec]:
|
|
865
|
+
"""Return every neighbourhood reduction of a law value, nested ones included."""
|
|
866
|
+
found = []
|
|
867
|
+
stack = neighborhoods_in(value)
|
|
868
|
+
while stack:
|
|
869
|
+
reduction = stack.pop()
|
|
870
|
+
found.append(reduction)
|
|
871
|
+
stack += neighborhoods_in(reduction.argument)
|
|
872
|
+
stack += neighborhoods_in(reduction.weight) if reduction.weight is not None else []
|
|
873
|
+
return found
|
|
874
|
+
|
|
875
|
+
@staticmethod
|
|
876
|
+
def _around_issues(records: list[CensusRecordSpec]) -> list[IssueSpec]:
|
|
877
|
+
"""Return the reductions over hyperedges of a component outside a network with hyperedges of their size."""
|
|
878
|
+
issues = []
|
|
879
|
+
for record in records:
|
|
880
|
+
name = f'{type(record.law).__name__} of {record.path}'
|
|
881
|
+
include = ('rate',) if isinstance(record.law, JumpLaw) else ('value',)
|
|
882
|
+
values = record.law._get_values(include=include)
|
|
883
|
+
reductions = {str(item.call): item for value in values for item in hyperedges_in(value)}
|
|
884
|
+
space = record.space
|
|
885
|
+
sizes = sorted({len(item) for item in getattr(space, 'hyperedges_', ())})
|
|
886
|
+
for reduction in reductions.values():
|
|
887
|
+
if not isinstance(space, NetworkSpace) or not sizes:
|
|
888
|
+
lives = type(space).__name__ if space is not None else 'no space'
|
|
889
|
+
message = (
|
|
890
|
+
f'The {name} reduces over hyperedges, which needs a network space with hyperedges, but the '
|
|
891
|
+
f'component lives on {lives}.'
|
|
892
|
+
)
|
|
893
|
+
fix = 'Give the group a network space with hyperedges, as `NetworkSpace(graph, hyperedges=...)`.'
|
|
894
|
+
issues.append(IssueSpec('law-space', record.path, message, fix))
|
|
895
|
+
break
|
|
896
|
+
if reduction.size is not None and reduction.size not in sizes:
|
|
897
|
+
message = (
|
|
898
|
+
f'The {name} reduces over hyperedges of size {reduction.size}, but the hyperedges of its '
|
|
899
|
+
f'network have the sizes {", ".join(map(str, sizes))}.'
|
|
900
|
+
)
|
|
901
|
+
fix = f'Reduce over hyperedges of one of the sizes {", ".join(map(str, sizes))}.'
|
|
902
|
+
issues.append(IssueSpec('binding', record.path, message, fix))
|
|
903
|
+
return issues
|
|
904
|
+
|
|
905
|
+
@staticmethod
|
|
906
|
+
def _field_symbols(nodes: list[NodeSpec]) -> tuple[dict[str, FieldElement], dict[str, float]]:
|
|
907
|
+
"""Return the field of every state symbol of a field, and the number of every parameter symbol that has one."""
|
|
908
|
+
fields: dict[str, FieldElement] = {}
|
|
909
|
+
numbers: dict[str, float] = {}
|
|
910
|
+
for node in nodes:
|
|
911
|
+
component = node.component
|
|
912
|
+
label = getattr(component, 'label', '')
|
|
913
|
+
if isinstance(component, FieldElement):
|
|
914
|
+
for name in declarations_of(node.component_type, VariableKind.STATE):
|
|
915
|
+
fields[f'{name}_{label}'] = component
|
|
916
|
+
values = component.values or {} if isinstance(component, FieldElement) else {}
|
|
917
|
+
for name in declarations_of(node.component_type, VariableKind.PARAMETER):
|
|
918
|
+
value = values.get(name, getattr(component, name, default_of(node.component_type, name)))
|
|
919
|
+
if isinstance(value, int | float) and not isinstance(value, bool):
|
|
920
|
+
numbers[f'{name}_{label}'] = float(value)
|
|
921
|
+
return fields, numbers
|
|
922
|
+
|
|
923
|
+
@staticmethod
|
|
924
|
+
def _is_negative(screening: Expression, fields: Mapping[str, FieldElement], numbers: Mapping[str, float]) -> bool:
|
|
925
|
+
"""Check whether a screening reads a state or has a negative square at the numbers of its parameters."""
|
|
926
|
+
if any(str(item) in fields for item in screening.variables()):
|
|
927
|
+
return True
|
|
928
|
+
known = {item: numbers[str(item)] for item in screening.variables() if str(item) in numbers}
|
|
929
|
+
squared = (screening**2).subs(known)
|
|
930
|
+
return not squared.variables() and (not squared.is_real() or float(squared) < 0)
|
|
931
|
+
|
|
932
|
+
@staticmethod
|
|
933
|
+
def _operator_issue(
|
|
934
|
+
record: CensusRecordSpec,
|
|
935
|
+
call: Expression,
|
|
936
|
+
fields: Mapping[str, FieldElement],
|
|
937
|
+
numbers: Mapping[str, float],
|
|
938
|
+
) -> IssueSpec | None:
|
|
939
|
+
"""Return the issue of one call of a nonlocal operator in a law of a field, or `None`."""
|
|
940
|
+
name = getattr(call.operator(), 'name', lambda: '')()
|
|
941
|
+
law = PassCompiler._law_name(record)
|
|
942
|
+
operands = call.operands()
|
|
943
|
+
places = {id(fields[str(item)]): fields[str(item)] for item in operands[0].variables() if str(item) in fields}
|
|
944
|
+
if len({id(place.space) for place in places.values()}) > 1:
|
|
945
|
+
message = f'The {law} applies {name} to {operands[0]}, which reads fields of more than one space.'
|
|
946
|
+
return IssueSpec('operator-spaces', record.path, message, 'Apply the operator to the states of one field.')
|
|
947
|
+
if name == 'convolve':
|
|
948
|
+
states = sorted(str(item) for item in operands[1].variables() if str(item) in fields)
|
|
949
|
+
if states:
|
|
950
|
+
message = f'The {law} convolves with a kernel that reads the state {", ".join(states)}.'
|
|
951
|
+
fix = 'Write the kernel in the displacements and the parameters only.'
|
|
952
|
+
return IssueSpec('kernel-state', record.path, message, fix)
|
|
953
|
+
if name == 'inverse_helmholtz' and PassCompiler._is_negative(SR(operands[1]), fields, numbers):
|
|
954
|
+
message = (
|
|
955
|
+
f'The {law} inverts with the screening {operands[1]}, whose square can be negative or that reads a '
|
|
956
|
+
'state.'
|
|
957
|
+
)
|
|
958
|
+
fix = 'Use a screening of parameters whose square is non-negative.'
|
|
959
|
+
return IssueSpec('screening', record.path, message, fix)
|
|
960
|
+
return PassCompiler._place_issue(record, name, next(iter(places.values()))) if places else None
|
|
961
|
+
|
|
962
|
+
@staticmethod
|
|
963
|
+
def _place_issue(record: CensusRecordSpec, name: str, place: FieldElement) -> IssueSpec | None:
|
|
964
|
+
"""Return the issue of a nonlocal operator that the space or discretization of its field lacks, or `None`."""
|
|
965
|
+
law = PassCompiler._law_name(record)
|
|
966
|
+
space = place.space
|
|
967
|
+
if name in {'convolve', 'shifted'} and not isinstance(space, LatticeSpace):
|
|
968
|
+
verb = 'convolution' if name == 'convolve' else 'shifted read'
|
|
969
|
+
message = (
|
|
970
|
+
f'The {law} uses a {verb}, which needs a lattice space, but the field lives on {type(space).__name__}.'
|
|
971
|
+
)
|
|
972
|
+
return IssueSpec('law-space', record.path, message, 'Give the field a lattice space.')
|
|
973
|
+
periodic = isinstance(space, LatticeSpace) and space.boundary == 'periodic'
|
|
974
|
+
if place.discretization == 'spectral' and name in {'convolve', 'inverse_helmholtz'} and not periodic:
|
|
975
|
+
message = f'The {law} applies the spectral {name} on a lattice without periodic edges.'
|
|
976
|
+
fix = "Give the lattice periodic edges, or use the 'finite-difference' discretization."
|
|
977
|
+
return IssueSpec('law-space', record.path, message, fix)
|
|
978
|
+
return None
|
|
979
|
+
|
|
980
|
+
@staticmethod
|
|
981
|
+
def _nonlocal_issues(records: list[CensusRecordSpec], nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
982
|
+
"""Return the convolutions, shifted reads, and inversions of laws whose space, kernel, or screening is wrong."""
|
|
983
|
+
fields, numbers = PassCompiler._field_symbols(nodes)
|
|
984
|
+
issues = []
|
|
985
|
+
for record in records:
|
|
986
|
+
include = ('rate',) if isinstance(record.law, JumpLaw) else ('value',)
|
|
987
|
+
for value in record.law._get_values(include=include):
|
|
988
|
+
if not FieldLowering._has_operators(value):
|
|
989
|
+
continue
|
|
990
|
+
calls = [
|
|
991
|
+
call
|
|
992
|
+
for name in ('convolve', 'shifted', 'inverse_helmholtz')
|
|
993
|
+
for call in FieldLowering._operator_calls(SR(value), name)
|
|
994
|
+
]
|
|
995
|
+
found = [PassCompiler._operator_issue(record, call, fields, numbers) for call in calls]
|
|
996
|
+
issues += [issue for issue in found if issue is not None]
|
|
997
|
+
return issues
|
|
998
|
+
|
|
999
|
+
@staticmethod
|
|
1000
|
+
def _held_axes(record: CensusRecordSpec, nodes: Mapping[str, NodeSpec]) -> list[str]:
|
|
1001
|
+
"""Return the class axes of the space of the group of a law and of the fields its interaction reads."""
|
|
1002
|
+
spaces = [record.space]
|
|
1003
|
+
node = nodes.get(record.path.rpartition('/')[0]) or nodes.get(record.path)
|
|
1004
|
+
sources = getattr(node.component, 'sources', ()) if node is not None else ()
|
|
1005
|
+
if node is not None and isinstance(sources, list | tuple):
|
|
1006
|
+
found = [nodes.get(f'{node.scope}{label}') for label in sources]
|
|
1007
|
+
spaces += [getattr(item.component, 'space', None) for item in found if item is not None]
|
|
1008
|
+
return [axis.name for space in spaces if isinstance(space, PhaseSpace) for axis in space.axes]
|
|
1009
|
+
|
|
1010
|
+
@staticmethod
|
|
1011
|
+
def _collision_issue(record: CensusRecordSpec) -> IssueSpec | None:
|
|
1012
|
+
"""Return the issue of a collision law on a phase space without two interval class axes, or `None`."""
|
|
1013
|
+
space = record.space
|
|
1014
|
+
if not (isinstance(record.law, RateLaw) and record.law.cross_section is not None):
|
|
1015
|
+
return None
|
|
1016
|
+
axes = space.axes if isinstance(space, PhaseSpace) else []
|
|
1017
|
+
if len(axes) == _COLLISION_AXES and not any(axis.periodic for axis in axes):
|
|
1018
|
+
return None
|
|
1019
|
+
lives = type(space).__name__ if space is not None else 'no space'
|
|
1020
|
+
message = f'The {PassCompiler._law_name(record)} needs two interval class axes, but the field lives on {lives}.'
|
|
1021
|
+
fix = "Declare two interval axes, each an `AxisSpec(name, size, low, high)`, such as 'vx' and 'vy'."
|
|
1022
|
+
return IssueSpec('law-space', record.path, message, fix)
|
|
1023
|
+
|
|
1024
|
+
@staticmethod
|
|
1025
|
+
def _coordinate_issues(records: list[CensusRecordSpec], nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
1026
|
+
"""Return the coordinates and the reductions over axes of laws whose group is not on a phase space with them."""
|
|
1027
|
+
by_path = {node.path: node for node in nodes}
|
|
1028
|
+
issues = [issue for record in records if (issue := PassCompiler._collision_issue(record)) is not None]
|
|
1029
|
+
for record in records:
|
|
1030
|
+
names = {
|
|
1031
|
+
str(item).removeprefix(COORDINATE_PREFIX)
|
|
1032
|
+
for value in record.law._get_values(include=('value', 'flux', 'rate', 'transition', 'outcomes'))
|
|
1033
|
+
if isinstance(value, Expression)
|
|
1034
|
+
for item in value.variables()
|
|
1035
|
+
if str(item).startswith(COORDINATE_PREFIX)
|
|
1036
|
+
}
|
|
1037
|
+
held = PassCompiler._held_axes(record, by_path)
|
|
1038
|
+
missing = sorted(names - set(held))
|
|
1039
|
+
if missing:
|
|
1040
|
+
law = PassCompiler._law_name(record)
|
|
1041
|
+
lives = type(record.space).__name__ if record.space is not None else 'no space'
|
|
1042
|
+
message = (
|
|
1043
|
+
f'The {law} reads the class axes {", ".join(missing)}, but the component lives on {lives}, '
|
|
1044
|
+
f'whose class axes are {held}.'
|
|
1045
|
+
)
|
|
1046
|
+
fix = f'Give the field a `PhaseSpace` with the axes {", ".join(missing)}, or read one of its axes.'
|
|
1047
|
+
issues.append(IssueSpec('law-space', record.path, message, fix))
|
|
1048
|
+
return issues
|
|
1049
|
+
|
|
1050
|
+
@staticmethod
|
|
1051
|
+
def _space_fix(spaces: tuple[type, ...]) -> str:
|
|
1052
|
+
"""Return the fix of a neighbourhood that the space does not offer."""
|
|
1053
|
+
if ContinuousSpace in spaces:
|
|
1054
|
+
return (
|
|
1055
|
+
'Give the group a continuous space, such as `ContinuousSpace(extent=(10.0, 10.0))`, or reduce over the '
|
|
1056
|
+
'neighbours of its network or lattice with `over=None`, or over a layer with '
|
|
1057
|
+
'`AdjacencyNeighborhood(layer)`.'
|
|
1058
|
+
)
|
|
1059
|
+
return (
|
|
1060
|
+
'Give the group a network or lattice space, or reduce over a `RadiusNeighborhood`, a '
|
|
1061
|
+
'`NearestNeighborhood`, or a `ConeNeighborhood` in a continuous space, or over a layer of a network with '
|
|
1062
|
+
'`AdjacencyNeighborhood(layer)`.'
|
|
1063
|
+
)
|
|
1064
|
+
|
|
1065
|
+
@staticmethod
|
|
1066
|
+
def _layer_reduction_issue(name: str, path: str, over: object, space: object) -> IssueSpec | None:
|
|
1067
|
+
"""Return the issue of a reduction over a layer that its network does not have, or `None`."""
|
|
1068
|
+
if (
|
|
1069
|
+
not isinstance(over, AdjacencyNeighborhood)
|
|
1070
|
+
or not isinstance(space, NetworkSpace)
|
|
1071
|
+
or over.layer in space.graphs_
|
|
1072
|
+
):
|
|
1073
|
+
return None
|
|
1074
|
+
known = ', '.join(repr(label) for label in space.graphs_)
|
|
1075
|
+
message = (
|
|
1076
|
+
f'The {name} reduces over the layer {over.layer!r}, which the network does not have. Its layers are '
|
|
1077
|
+
f'{known}.'
|
|
1078
|
+
)
|
|
1079
|
+
fix = f'Reduce over one of the layers {known}, or add the layer to the network space.'
|
|
1080
|
+
return IssueSpec('binding', path, message, fix)
|
|
1081
|
+
|
|
1082
|
+
@staticmethod
|
|
1083
|
+
def _neighborhood_issues(records: list[CensusRecordSpec], nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
1084
|
+
"""Return the neighbourhood reductions whose space does not offer them, and the cones without a direction."""
|
|
1085
|
+
by_path = {node.path: node for node in nodes}
|
|
1086
|
+
issues = []
|
|
1087
|
+
for record in records:
|
|
1088
|
+
name = f'{type(record.law).__name__} of {record.path}'
|
|
1089
|
+
include = ('rate',) if isinstance(record.law, JumpLaw) else ('value',)
|
|
1090
|
+
values = record.law._get_values(include=include)
|
|
1091
|
+
reductions = {str(item.call): item for value in values for item in PassCompiler._reductions_of(value)}
|
|
1092
|
+
for reduction in reductions.values():
|
|
1093
|
+
over = reduction.over
|
|
1094
|
+
if over is not None and not isinstance(over, BaseNeighborhood):
|
|
1095
|
+
error_msg = f'The {name} reduces over {over!r}, which is not a neighbourhood.'
|
|
1096
|
+
raise ValidationError(error_msg)
|
|
1097
|
+
spaces = _OWN_NEIGHBORHOOD if over is None else NeighborhoodKernel._spaces_of(over)
|
|
1098
|
+
described = 'the neighbours of its space' if over is None else repr(over)
|
|
1099
|
+
if not isinstance(record.space, spaces):
|
|
1100
|
+
lives = type(record.space).__name__ if record.space is not None else 'no space'
|
|
1101
|
+
message = (
|
|
1102
|
+
f'The {name} reduces over {described}, which needs a {PassCompiler._names(spaces)}, but the '
|
|
1103
|
+
f'component lives on {lives}.'
|
|
1104
|
+
)
|
|
1105
|
+
issues.append(IssueSpec('law-space', record.path, message, PassCompiler._space_fix(spaces)))
|
|
1106
|
+
continue
|
|
1107
|
+
layered = PassCompiler._layer_reduction_issue(name, record.path, over, record.space)
|
|
1108
|
+
if layered is not None:
|
|
1109
|
+
issues.append(layered)
|
|
1110
|
+
continue
|
|
1111
|
+
node = by_path.get(record.owner)
|
|
1112
|
+
if node is None or not isinstance(record.space, ContinuousSpace) or over is None:
|
|
1113
|
+
continue
|
|
1114
|
+
states = declarations_of(node.component_type, VariableKind.STATE)
|
|
1115
|
+
if NeighborhoodKernel._position_state(states) is None:
|
|
1116
|
+
message = (
|
|
1117
|
+
f'The {name} reduces over {over!r}, which measures distances between positions, but '
|
|
1118
|
+
f'{record.owner} declares no vector position state.'
|
|
1119
|
+
)
|
|
1120
|
+
fix = "Declare the position with `StateSpec(vector=True, role='position')`."
|
|
1121
|
+
issues.append(IssueSpec('law-domain', record.path, message, fix))
|
|
1122
|
+
continue
|
|
1123
|
+
if isinstance(over, ConeNeighborhood):
|
|
1124
|
+
try:
|
|
1125
|
+
NeighborhoodKernel._cone_direction(over, states, getattr(record.space, 'n_dim_', 0))
|
|
1126
|
+
except ValidationError as error:
|
|
1127
|
+
fix = (
|
|
1128
|
+
"Declare the position of order 2, `StateSpec(vector=True, order=2, role='position')`, or "
|
|
1129
|
+
"name a direction state, such as `ConeNeighborhood(r, angle, direction='theta')`."
|
|
1130
|
+
)
|
|
1131
|
+
issues.append(IssueSpec('law-domain', record.path, f'The {name}: {error}', fix))
|
|
1132
|
+
return issues
|
|
1133
|
+
|
|
1134
|
+
@staticmethod
|
|
1135
|
+
def _solver_issues(solver: object, census: CensusSpec, system: System) -> list[IssueSpec]:
|
|
1136
|
+
"""Return the arguments the solver passed rejects and the requirements of a system it does not support."""
|
|
1137
|
+
records = census.records
|
|
1138
|
+
stepper = type(solver)
|
|
1139
|
+
needs: dict[str, Iterable[object]] = {
|
|
1140
|
+
'time': {kind for kind in FractionalFormPass._declared_times(system).values() if kind is not None},
|
|
1141
|
+
'laws': {type(record.law) for record in records},
|
|
1142
|
+
'space': {None if record.space is None else type(record.space) for record in records},
|
|
1143
|
+
}
|
|
1144
|
+
issues = []
|
|
1145
|
+
try:
|
|
1146
|
+
if isinstance(solver, BaseConfig):
|
|
1147
|
+
solver.check()
|
|
1148
|
+
except SkcomplexError as error:
|
|
1149
|
+
fix = f'Correct the arguments of {stepper.__name__} as the message describes.'
|
|
1150
|
+
issues.append(IssueSpec('solver-argument', system.label, str(error), fix, error=type(error)))
|
|
1151
|
+
support = BaseCompiler._support_of(stepper)
|
|
1152
|
+
for category, terms in needs.items():
|
|
1153
|
+
missing = support.missing(category, terms)
|
|
1154
|
+
if missing:
|
|
1155
|
+
message = f'The solver {stepper.__name__} does not support the {category} {", ".join(missing)}.'
|
|
1156
|
+
fix = f'Pass a solver that supports the {category} {", ".join(missing)}.'
|
|
1157
|
+
issues.append(IssueSpec('solver-unsupported', system.label, message, fix, error=SolverError))
|
|
1158
|
+
return issues
|
|
1159
|
+
|
|
1160
|
+
@staticmethod
|
|
1161
|
+
def _matrix_problem(matrix: np.ndarray) -> str | None:
|
|
1162
|
+
"""Return why a square covariance matrix is not symmetric positive semidefinite, or `None` when it is."""
|
|
1163
|
+
asymmetry = np.abs(matrix - matrix.T)
|
|
1164
|
+
if np.max(asymmetry) > _COVARIANCE_TOLERANCE * max(1.0, float(np.max(np.abs(matrix)))):
|
|
1165
|
+
row, column = np.unravel_index(int(np.argmax(asymmetry)), matrix.shape)
|
|
1166
|
+
return f'Its covariance is not symmetric: entry ({row}, {column}) is {matrix[row, column]}.'
|
|
1167
|
+
values = np.linalg.eigvalsh(matrix)
|
|
1168
|
+
if values[0] < -_COVARIANCE_TOLERANCE * max(1.0, float(np.max(np.abs(values)))):
|
|
1169
|
+
return f'Its covariance is not positive semidefinite: it has the negative eigenvalue {values[0]:.6g}.'
|
|
1170
|
+
return None
|
|
1171
|
+
|
|
1172
|
+
@staticmethod
|
|
1173
|
+
def _covariance_problem(wiener: WienerProcessSpec) -> str | None:
|
|
1174
|
+
"""Return why the dimension or the covariance of a `WienerProcessSpec` is invalid, or `None` when valid."""
|
|
1175
|
+
dimension = wiener.dimension
|
|
1176
|
+
if not isinstance(dimension, int) or isinstance(dimension, bool) or dimension < 1:
|
|
1177
|
+
return f'Its dimension {dimension!r} is not a positive integer.'
|
|
1178
|
+
if wiener.covariance is None:
|
|
1179
|
+
return None
|
|
1180
|
+
try:
|
|
1181
|
+
matrix = np.asarray(wiener.covariance, dtype=float)
|
|
1182
|
+
except (TypeError, ValueError):
|
|
1183
|
+
return f'Its covariance {wiener.covariance!r} is not a matrix of numbers.'
|
|
1184
|
+
if matrix.shape != (dimension, dimension):
|
|
1185
|
+
return f'Its covariance has the shape {matrix.shape}, not ({dimension}, {dimension}).'
|
|
1186
|
+
return PassCompiler._matrix_problem(matrix)
|
|
1187
|
+
|
|
1188
|
+
@staticmethod
|
|
1189
|
+
def _wiener_issues(system: System, nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
1190
|
+
"""Return the Wiener processes outside continuous time or with an invalid covariance."""
|
|
1191
|
+
times = FractionalFormPass._declared_times(system)
|
|
1192
|
+
issues = []
|
|
1193
|
+
for path, wiener in LayoutPass._noise_processes(nodes).items():
|
|
1194
|
+
time = times.get(path.rpartition('/')[0])
|
|
1195
|
+
if time is not None and not issubclass(time, ContinuousTime):
|
|
1196
|
+
message = f'The Wiener processes {path} exist only in continuous time.'
|
|
1197
|
+
issues.append(IssueSpec('wiener-time', path, message, 'Declare continuous time for its system.'))
|
|
1198
|
+
problem = PassCompiler._covariance_problem(wiener)
|
|
1199
|
+
if problem is not None:
|
|
1200
|
+
message = f'The Wiener processes {path} are invalid. {problem}'
|
|
1201
|
+
fix = 'Give a symmetric positive semidefinite covariance with one row and column per process.'
|
|
1202
|
+
issues.append(IssueSpec('wiener-covariance', path, message, fix))
|
|
1203
|
+
return issues
|
|
1204
|
+
|
|
1205
|
+
@staticmethod
|
|
1206
|
+
def _law_name(record: CensusRecordSpec) -> str:
|
|
1207
|
+
"""Return the name of the law of a census record."""
|
|
1208
|
+
return f'{type(record.law).__name__} of {record.path}'
|
|
1209
|
+
|
|
1210
|
+
@staticmethod
|
|
1211
|
+
def _process_name(key: ProcessKey) -> str:
|
|
1212
|
+
"""Return the name of a process key."""
|
|
1213
|
+
kind, path, item = key
|
|
1214
|
+
return (
|
|
1215
|
+
f'the local process {item!r} of {path}'
|
|
1216
|
+
if kind == 'local'
|
|
1217
|
+
else f'process {item} of the Wiener processes {path}'
|
|
1218
|
+
)
|
|
1219
|
+
|
|
1220
|
+
@staticmethod
|
|
1221
|
+
def _noise_records(records: list[CensusRecordSpec]) -> list[CensusRecordSpec]:
|
|
1222
|
+
"""Return the records of noise laws."""
|
|
1223
|
+
return [record for record in records if isinstance(record.law, NoiseLaw)]
|
|
1224
|
+
|
|
1225
|
+
@staticmethod
|
|
1226
|
+
def _handle_issues(records: list[CensusRecordSpec]) -> list[IssueSpec]:
|
|
1227
|
+
"""Return the laws that use the handle of a Wiener process outside the process of a noise law."""
|
|
1228
|
+
issues = []
|
|
1229
|
+
for record in records:
|
|
1230
|
+
if record.handles:
|
|
1231
|
+
message = (
|
|
1232
|
+
f'The {PassCompiler._law_name(record)} uses the Wiener handle {", ".join(record.handles)} in a '
|
|
1233
|
+
'value, but a handle is only the process of a noise law.'
|
|
1234
|
+
)
|
|
1235
|
+
fix = 'Name the handle as the process of a noise law, `NoiseLaw(target, value, process=s.<role>.dW)`.'
|
|
1236
|
+
issues.append(IssueSpec('wiener-handle', record.path, message, fix))
|
|
1237
|
+
return issues
|
|
1238
|
+
|
|
1239
|
+
@staticmethod
|
|
1240
|
+
def _convention_issues(records: list[CensusRecordSpec]) -> list[IssueSpec]:
|
|
1241
|
+
"""Return the processes that noise laws of different conventions share."""
|
|
1242
|
+
sharing: dict[ProcessKey, list[CensusRecordSpec]] = {}
|
|
1243
|
+
for record in PassCompiler._noise_records(records):
|
|
1244
|
+
for key in dict.fromkeys(record.processes):
|
|
1245
|
+
if key is not None:
|
|
1246
|
+
sharing.setdefault(key, []).append(record)
|
|
1247
|
+
issues = []
|
|
1248
|
+
for process, sharers in sharing.items():
|
|
1249
|
+
conventions = {record.law.convention for record in sharers if isinstance(record.law, NoiseLaw)}
|
|
1250
|
+
if len(conventions) > 1:
|
|
1251
|
+
laws = ' and '.join(
|
|
1252
|
+
f'the {item.law.convention} {PassCompiler._law_name(item)}'
|
|
1253
|
+
for item in sharers
|
|
1254
|
+
if isinstance(item.law, NoiseLaw)
|
|
1255
|
+
)
|
|
1256
|
+
shared = PassCompiler._process_name(process)
|
|
1257
|
+
message = f'{laws[0].upper()}{laws[1:]} share {shared} with different conventions.'
|
|
1258
|
+
fix = 'Declare one convention for every noise law of the process.'
|
|
1259
|
+
issues.append(IssueSpec('noise-convention-mixed', sharers[0].path, message, fix))
|
|
1260
|
+
return issues
|
|
1261
|
+
|
|
1262
|
+
@staticmethod
|
|
1263
|
+
def _sharer(
|
|
1264
|
+
record: CensusRecordSpec,
|
|
1265
|
+
noisy: list[CensusRecordSpec],
|
|
1266
|
+
wieners: dict[str, WienerProcessSpec],
|
|
1267
|
+
) -> CensusRecordSpec | None:
|
|
1268
|
+
"""Return a noise law of another component that drives a state a law's amplitude reads through its process."""
|
|
1269
|
+
for key, reads in zip(record.processes, record.reads, strict=True):
|
|
1270
|
+
if key is None:
|
|
1271
|
+
continue
|
|
1272
|
+
for item in noisy:
|
|
1273
|
+
if item.path == record.path:
|
|
1274
|
+
continue
|
|
1275
|
+
for state, process in zip(item.driven, item.processes, strict=True):
|
|
1276
|
+
if process is not None and state in reads and NoisePass._process_covariance(key, process, wieners):
|
|
1277
|
+
return item
|
|
1278
|
+
return None
|
|
1279
|
+
|
|
1280
|
+
@staticmethod
|
|
1281
|
+
def _scope_issues(records: list[CensusRecordSpec], wieners: dict[str, WienerProcessSpec]) -> list[IssueSpec]:
|
|
1282
|
+
"""Return the noise laws of a convention whose drift correction needs an amplitude of another component."""
|
|
1283
|
+
noisy = PassCompiler._noise_records(records)
|
|
1284
|
+
issues = []
|
|
1285
|
+
for record in noisy:
|
|
1286
|
+
if not isinstance(record.law, NoiseLaw) or record.law.convention == 'ito':
|
|
1287
|
+
continue
|
|
1288
|
+
other = PassCompiler._sharer(record, noisy, wieners)
|
|
1289
|
+
if other is not None:
|
|
1290
|
+
message = (
|
|
1291
|
+
f'The {PassCompiler._law_name(record)} depends on a state that the {PassCompiler._law_name(other)} '
|
|
1292
|
+
'drives through a shared process, so its drift correction needs an amplitude outside its component.'
|
|
1293
|
+
)
|
|
1294
|
+
fix = 'Use the Itô convention, or write both laws in one component.'
|
|
1295
|
+
issues.append(IssueSpec('noise-correction-scope', record.path, message, fix))
|
|
1296
|
+
return issues
|
|
1297
|
+
|
|
1298
|
+
@staticmethod
|
|
1299
|
+
def _noise_needs(
|
|
1300
|
+
records: list[CensusRecordSpec],
|
|
1301
|
+
wieners: dict[str, WienerProcessSpec],
|
|
1302
|
+
) -> dict[NoiseKind, CensusRecordSpec]:
|
|
1303
|
+
"""Return the noise structures a system uses, each with the first law that needs it."""
|
|
1304
|
+
needs: dict[NoiseKind, CensusRecordSpec] = {}
|
|
1305
|
+
states: dict[object, set[tuple[str, int]]] = {}
|
|
1306
|
+
first: dict[object, CensusRecordSpec] = {}
|
|
1307
|
+
spread: set[object] = set()
|
|
1308
|
+
for record in PassCompiler._noise_records(records):
|
|
1309
|
+
if isinstance(record.law, NoiseLaw) and record.law.conserved:
|
|
1310
|
+
needs.setdefault(NoiseKind.CONSERVED, record)
|
|
1311
|
+
continue
|
|
1312
|
+
for key, state in zip(record.processes, record.driven, strict=True):
|
|
1313
|
+
if key is None:
|
|
1314
|
+
needs.setdefault(NoiseKind.DIAGONAL, record)
|
|
1315
|
+
continue
|
|
1316
|
+
states.setdefault(key, set()).add(state)
|
|
1317
|
+
first.setdefault(key, record)
|
|
1318
|
+
if key[0] == 'wiener' and record.members > 1:
|
|
1319
|
+
spread.add(key)
|
|
1320
|
+
if key[0] == 'wiener' and wieners[key[1]].covariance is not None:
|
|
1321
|
+
needs.setdefault(NoiseKind.CORRELATED, record)
|
|
1322
|
+
for process, driven in states.items():
|
|
1323
|
+
shared = len(driven) > 1 or process in spread
|
|
1324
|
+
needs.setdefault(NoiseKind.SHARED if shared else NoiseKind.DIAGONAL, first[process])
|
|
1325
|
+
return needs
|
|
1326
|
+
|
|
1327
|
+
@staticmethod
|
|
1328
|
+
def _noise_runners(solver: object, backend: object) -> list[tuple[str, type]]:
|
|
1329
|
+
"""Return the classes of the solver and the backend passed that run the noise of a system."""
|
|
1330
|
+
runners: list[tuple[str, type]] = []
|
|
1331
|
+
if solver is not None:
|
|
1332
|
+
runners.append(('solver', type(solver)))
|
|
1333
|
+
if backend is not None:
|
|
1334
|
+
runners.append(('backend', type(backend)))
|
|
1335
|
+
return runners
|
|
1336
|
+
|
|
1337
|
+
@staticmethod
|
|
1338
|
+
def _noise_fix(term: NoiseKind) -> str:
|
|
1339
|
+
"""Return the fix of a noise structure that the solver or the backend passed does not support."""
|
|
1340
|
+
return f'Pass a solver and a backend that support {term} noise.'
|
|
1341
|
+
|
|
1342
|
+
@staticmethod
|
|
1343
|
+
def _noise_support_issues(
|
|
1344
|
+
records: list[CensusRecordSpec],
|
|
1345
|
+
wieners: dict[str, WienerProcessSpec],
|
|
1346
|
+
solver: object,
|
|
1347
|
+
backend: object,
|
|
1348
|
+
) -> list[IssueSpec]:
|
|
1349
|
+
"""Return the noise structures of a system that the chosen solver or backend does not support."""
|
|
1350
|
+
needs = PassCompiler._noise_needs(records, wieners)
|
|
1351
|
+
if not needs:
|
|
1352
|
+
return []
|
|
1353
|
+
issues = []
|
|
1354
|
+
for role, runner in PassCompiler._noise_runners(solver, backend):
|
|
1355
|
+
supported = BaseCompiler._support_of(runner).noise
|
|
1356
|
+
for term, record in needs.items():
|
|
1357
|
+
if term not in supported:
|
|
1358
|
+
name = PassCompiler._law_name(record)
|
|
1359
|
+
message = f'The {name} needs {term} noise, which the {role} {runner.__name__} lacks.'
|
|
1360
|
+
fix = PassCompiler._noise_fix(term)
|
|
1361
|
+
issues.append(IssueSpec('noise-unsupported', record.path, message, fix, error=SolverError))
|
|
1362
|
+
return issues
|
|
1363
|
+
|
|
1364
|
+
@staticmethod
|
|
1365
|
+
def _noise_issues(compilation: Compilation, records: list[CensusRecordSpec]) -> list[IssueSpec]:
|
|
1366
|
+
"""Return the problems of the Wiener processes and the noise laws of a system."""
|
|
1367
|
+
nodes = Compilation._required(compilation.nodes, 'nodes')
|
|
1368
|
+
solver, backend = compilation.solver, compilation.backend
|
|
1369
|
+
wieners = LayoutPass._noise_processes(nodes)
|
|
1370
|
+
issues = PassCompiler._wiener_issues(compilation.system, nodes) + PassCompiler._handle_issues(records)
|
|
1371
|
+
if any(issue.code == 'wiener-covariance' for issue in issues):
|
|
1372
|
+
return issues
|
|
1373
|
+
issues += PassCompiler._convention_issues(records)
|
|
1374
|
+
issues += PassCompiler._scope_issues(records, wieners)
|
|
1375
|
+
return issues + PassCompiler._noise_support_issues(records, wieners, solver, backend)
|
|
1376
|
+
|
|
1377
|
+
@staticmethod
|
|
1378
|
+
def _law_values(record: CensusRecordSpec) -> Iterator[object]:
|
|
1379
|
+
"""Yield the symbolic values of the law of a census record, with the items of vectors."""
|
|
1380
|
+
for value in record.law._get_values():
|
|
1381
|
+
if isinstance(value, FreeModuleElement):
|
|
1382
|
+
yield from value
|
|
1383
|
+
elif isinstance(value, Expression):
|
|
1384
|
+
yield value
|
|
1385
|
+
|
|
1386
|
+
@staticmethod
|
|
1387
|
+
def _held_reductions(census: CensusSpec, time: Expression) -> list[_HeldReductionSpec]:
|
|
1388
|
+
"""Return the reductions of agents that the laws of a census read, each once, in the order they are read."""
|
|
1389
|
+
found: dict[tuple[str, ...], _HeldReductionSpec] = {}
|
|
1390
|
+
for record in census.records:
|
|
1391
|
+
for value in PassCompiler._law_values(record):
|
|
1392
|
+
for reduction in reductions_in(value):
|
|
1393
|
+
held = ReductionLowering._held_reduction(reduction, census.agents, time, record.path)
|
|
1394
|
+
if held is not None:
|
|
1395
|
+
found.setdefault(held.key, held)
|
|
1396
|
+
return list(found.values())
|
|
1397
|
+
|
|
1398
|
+
@staticmethod
|
|
1399
|
+
def _census_issues(compilation: Compilation) -> list[IssueSpec]:
|
|
1400
|
+
"""Return the issues of the components that fail to declare or collect, unless their binding is the problem."""
|
|
1401
|
+
census = Compilation._required(compilation.census, 'census')
|
|
1402
|
+
nodes = Compilation._required(compilation.nodes, 'nodes')
|
|
1403
|
+
bindings = PassCompiler._binding_issues(nodes)
|
|
1404
|
+
shapes = PassCompiler._shape_issues(nodes)
|
|
1405
|
+
unbound = {issue.path for issue in bindings} | {issue.path.rpartition('.')[0] for issue in shapes}
|
|
1406
|
+
issues = []
|
|
1407
|
+
for path, failure in census.errors:
|
|
1408
|
+
if path in unbound:
|
|
1409
|
+
continue
|
|
1410
|
+
code, fix = _FIXES.get(type(failure), ('value', 'Correct the component as the message describes.'))
|
|
1411
|
+
issues.append(IssueSpec(code, path, str(failure), fix, error=type(failure)))
|
|
1412
|
+
return issues + bindings + shapes
|
|
1413
|
+
|
|
1414
|
+
@staticmethod
|
|
1415
|
+
def _probability_sum(total: object) -> float | None:
|
|
1416
|
+
"""Return the sum of the outcome probabilities of one encounter as a number, or `None` for a symbol."""
|
|
1417
|
+
value = SR(total).simplify_full() if isinstance(total, Expression) else SR(total)
|
|
1418
|
+
return float(value) if value.is_numeric() else None
|
|
1419
|
+
|
|
1420
|
+
@staticmethod
|
|
1421
|
+
def _unnormalized(law: EncounterLaw | BilinearLaw) -> list[tuple[int, int, float]]:
|
|
1422
|
+
"""Return the candidate and field activities of the encounters whose outcome probabilities do not sum to one."""
|
|
1423
|
+
value = law.transition if isinstance(law, EncounterLaw) else law.outcomes
|
|
1424
|
+
if value is None:
|
|
1425
|
+
return []
|
|
1426
|
+
sums = CompileEncountersPass._kinetic_table(value).sum(axis=2)
|
|
1427
|
+
rates = np.broadcast_to(CompileEncountersPass._kinetic_table(law.rate), sums.shape)
|
|
1428
|
+
found = []
|
|
1429
|
+
for (candidate, field_activity), total in np.ndenumerate(sums):
|
|
1430
|
+
rate = rates[candidate, field_activity]
|
|
1431
|
+
if SR(rate).is_numeric() and float(SR(rate)) == 0:
|
|
1432
|
+
continue
|
|
1433
|
+
value = PassCompiler._probability_sum(total)
|
|
1434
|
+
if value is not None and abs(value - 1) > _PROBABILITY_TOLERANCE:
|
|
1435
|
+
found.append((candidate, field_activity, value))
|
|
1436
|
+
return found
|
|
1437
|
+
|
|
1438
|
+
@staticmethod
|
|
1439
|
+
def _probability_issues(compilation: Compilation) -> list[IssueSpec]:
|
|
1440
|
+
"""Return the encounter laws whose outcome probabilities do not sum to one over the outcomes of an encounter.
|
|
1441
|
+
|
|
1442
|
+
Args:
|
|
1443
|
+
compilation:
|
|
1444
|
+
The compilation state after planning.
|
|
1445
|
+
|
|
1446
|
+
Returns:
|
|
1447
|
+
issues:
|
|
1448
|
+
The issues.
|
|
1449
|
+
"""
|
|
1450
|
+
issues = []
|
|
1451
|
+
for record in Compilation._required(compilation.census, 'census').records:
|
|
1452
|
+
law = record.law
|
|
1453
|
+
if not isinstance(law, EncounterLaw | BilinearLaw):
|
|
1454
|
+
continue
|
|
1455
|
+
found = PassCompiler._unnormalized(law)
|
|
1456
|
+
if not found:
|
|
1457
|
+
continue
|
|
1458
|
+
listed = '; '.join(
|
|
1459
|
+
f'candidate activity {candidate} with field activity {field_activity} sums to {value:.6g}'
|
|
1460
|
+
for candidate, field_activity, value in found[:_LISTED_ENCOUNTERS]
|
|
1461
|
+
)
|
|
1462
|
+
more = f', and {len(found) - _LISTED_ENCOUNTERS} more' if len(found) > _LISTED_ENCOUNTERS else ''
|
|
1463
|
+
message = (
|
|
1464
|
+
f'The {type(law).__name__} of {record.path} has outcome probabilities that do not sum to one over the '
|
|
1465
|
+
f'outcomes of an encounter: {listed}{more}.'
|
|
1466
|
+
)
|
|
1467
|
+
fix = 'Give outcome probabilities that sum to one over the outcomes of every encounter with a nonzero rate.'
|
|
1468
|
+
issues.append(IssueSpec('encounter-probabilities', record.path, message, fix))
|
|
1469
|
+
return issues
|
|
1470
|
+
|
|
1471
|
+
@staticmethod
|
|
1472
|
+
def _fixed_groups(
|
|
1473
|
+
request: TopologyRequestSpec,
|
|
1474
|
+
owner: NodeSpec | None,
|
|
1475
|
+
groups: list[NodeSpec],
|
|
1476
|
+
) -> tuple[list[str], bool]:
|
|
1477
|
+
"""Return the fixed groups a request changes, and whether its layer lacks an edge group."""
|
|
1478
|
+
edges = [node for node in groups if node.component.on == 'edges' and node.component.layer == request.layer]
|
|
1479
|
+
sites = [node for node in groups if node.component.on == 'sites']
|
|
1480
|
+
changed = []
|
|
1481
|
+
if TopologyKernel._changes_edges(request):
|
|
1482
|
+
changed += edges
|
|
1483
|
+
if request.kind in {'add-node', 'remove-node'}:
|
|
1484
|
+
changed += sites
|
|
1485
|
+
if owner is not None:
|
|
1486
|
+
changed.append(owner)
|
|
1487
|
+
fixed = list(dict.fromkeys(node.path for node in changed if not node.component.variable))
|
|
1488
|
+
return fixed, TopologyKernel._changes_edges(request) and not edges
|
|
1489
|
+
|
|
1490
|
+
@staticmethod
|
|
1491
|
+
def _fixed_group_issues(records: list[CensusRecordSpec], nodes: list[NodeSpec]) -> list[IssueSpec]:
|
|
1492
|
+
"""Return the topology requests that change fixed groups, or edges of a layer without a variable edge group."""
|
|
1493
|
+
by_path = {node.path: node for node in nodes}
|
|
1494
|
+
issues = []
|
|
1495
|
+
for record in records:
|
|
1496
|
+
try:
|
|
1497
|
+
request = TopologyKernel._request_of(record.law)
|
|
1498
|
+
except ValidationError as error:
|
|
1499
|
+
issues.append(
|
|
1500
|
+
IssueSpec('value', record.path, str(error), 'Fire one request per jump, with increment 1.'),
|
|
1501
|
+
)
|
|
1502
|
+
continue
|
|
1503
|
+
if request is None:
|
|
1504
|
+
continue
|
|
1505
|
+
space = record.space
|
|
1506
|
+
if not isinstance(space, NetworkSpace):
|
|
1507
|
+
spaces = {id(node.space): node.space for node in nodes if isinstance(node.space, NetworkSpace)}
|
|
1508
|
+
space = next(iter(spaces.values())) if len(spaces) == 1 else space
|
|
1509
|
+
groups = [node for node in nodes if isinstance(node.component, GroupElement) and node.space is space]
|
|
1510
|
+
owner = by_path.get(record.owner)
|
|
1511
|
+
owner = owner if owner is not None and isinstance(owner.component, GroupElement) else None
|
|
1512
|
+
fixed, missing = PassCompiler._fixed_groups(request, owner, [node for node in groups if node.component.on])
|
|
1513
|
+
if not fixed and not missing:
|
|
1514
|
+
continue
|
|
1515
|
+
listed = ', '.join(fixed) or 'none'
|
|
1516
|
+
where = f'the layer {request.layer!r}' if request.layer is not None else 'the network'
|
|
1517
|
+
message = (
|
|
1518
|
+
f'The {type(record.law).__name__} of {record.path} requests {request!r}, which changes the fixed '
|
|
1519
|
+
f'groups {listed}.'
|
|
1520
|
+
)
|
|
1521
|
+
if missing:
|
|
1522
|
+
message += f' {where[0].upper()}{where[1:]} has no group on its edges.'
|
|
1523
|
+
fix = (
|
|
1524
|
+
'Give the groups on the nodes and the edges of the network `variable=True`, with a group on the edges '
|
|
1525
|
+
'of every layer the request changes, `GroupElement(..., on="edges", variable=True)`.'
|
|
1526
|
+
)
|
|
1527
|
+
issues.append(IssueSpec('group-fixed', record.path, message, fix))
|
|
1528
|
+
return issues
|
|
1529
|
+
|
|
1530
|
+
@staticmethod
|
|
1531
|
+
def _request_issues(compilation: Compilation) -> list[IssueSpec]:
|
|
1532
|
+
"""Return the topology requests of a compilation that change fixed groups or a layer without an edge group."""
|
|
1533
|
+
records = Compilation._required(compilation.census, 'census').records
|
|
1534
|
+
return PassCompiler._fixed_group_issues(records, Compilation._required(compilation.nodes, 'nodes'))
|