gridstate 2.5.0__tar.gz → 2.6.0__tar.gz
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.
- {gridstate-2.5.0 → gridstate-2.6.0}/CHANGELOG.md +18 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/PKG-INFO +1 -1
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/_version.py +3 -3
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/api.py +5 -6
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/ipm_hints.py +1 -1
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/config.py +32 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/passes.py +3 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/ipm_setup.py +55 -10
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/PKG-INFO +1 -1
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/scm_version.json +2 -2
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_balance_modes.py +67 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/.github/workflows/ci.yml +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/.github/workflows/release.yml +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/.gitignore +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/.pre-commit-config.yaml +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/LICENSE +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/Makefile +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/README.md +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/build_cython.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/__pyinstaller/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/__pyinstaller/hook-gridstate.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/_arrays.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/adapters/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/adapters/from_pandapower.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/_selinv_kernels.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/base.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/estimators.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/jacobian_pattern.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algebra/normalized_residuals.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/_gram_numba.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/ipm.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/ipm_pd.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/kkt_solver.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/status.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/algorithms/wls.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/bad_data_repass.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/bounds.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/constants.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/_legacy.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/containers.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/derived.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/derived_tables.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/serialize.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/tables.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/validate.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/contract/version.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/load_characteristics.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/losses.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/measurement_ids.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/context.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/manifest.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/orchestration.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/preparation.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/runner.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/pipeline/steps.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/post_processing.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/_scan.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/meas_rows.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/mirror_voltage.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/node_props.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/preprocessing/pseudo_measurements.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/py.typed +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/quality_summary.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/resolve_pass.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/result.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/runtime.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/shunt_sanity.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/solution_hints.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/state.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/_filters.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/apply_resolved.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/generators.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/kinds.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/load_only_injection.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/loss_filter.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/measurements.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/noise.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/on_line.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/quality.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/rpn.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/shunts.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/sigma_floor.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/units.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/voltage_filter.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/telemetry/voltage_nominal.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/topology.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/units.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/utils.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/v_mirror.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/v_refine.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/_diagnostics.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/bad_data.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/chi2_test.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/validation/observability.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/working.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/ybus.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate/z_vector.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/SOURCES.txt +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/dependency_links.txt +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/entry_points.txt +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/requires.txt +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/scm_file_list.json +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/gridstate.egg-info/top_level.txt +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/pyproject.toml +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/setup.cfg +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/__init__.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/_golden.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/conftest.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_adapters_lazy_import.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_aggregate_generators.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_algebra_base.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_anti_overshoot.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_arrays_helpers.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_bad_data.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_bad_data_repass.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_bounds.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_boxed_balance.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_breaker_reactance.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_chain_mirror.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_contract.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_contract_edge_cases.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_contract_runtime.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case118.json +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case118.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case118_degraded.json +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case118_degraded.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case14.json +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case14.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case14_degraded.json +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case14_degraded.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case30.json +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case30.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case30_degraded.json +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/case30_degraded.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/golden/manifest.json +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case118.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case118_truth.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case14.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case14_truth.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case30.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_data/ieee/case30_truth.npz +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_derived_tables.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_enum_codes.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_flow_sigma_floor.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_from_pandapower.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_generator_shunt_kernels.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_golden.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_gram_numba.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ieee_cases.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_hints.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_injection_roles.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_integration.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ipm_pd.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_jacobian_pattern.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_kkt_solver.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_load_characteristic_segments.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_load_only_injection.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_losses_breakdown.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_losses_q_convention.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_losses_trafo_classification.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_materialize_kernel.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_measurement_filter_kernels.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_measurement_ids.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_mirror_voltage_kernel.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_near_critical_ranking.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_neutral_wording.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_noise_model.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_normalized_residuals.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_numpy_only_runtime.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_observability.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_on_line_kernel.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_perf_synthetic_network.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_config_validation.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_idempotent.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_invariant_errors.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_step_order.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_warm_start.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pipeline_working_layer.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_post_processing.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_preparation_steps.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_prepare_network.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pseudo_unknown_load.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_pseudo_v_unobservable.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_quality_summary_paths.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_reconcile_balance.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_refine_merge.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_resolve_pass.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_result_quality_summary.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_rn_selected_inversion.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_serialize_npz.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_shunt_sanity.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_solution_hints.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_solve_status.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_state.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_state_range.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_telemetry_apply_kernel.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_telemetry_bounds.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_telemetry_physics_kernels.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_tm_code_quality.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_topology_kernels.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_topology_port.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_transformer_from_shunt.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_units.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_units_array_kernels.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_v_mirror.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_v_refine.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_variance_charging.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_version.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_voltage_calibration_gen_nodes.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_voltage_range_filter_fallback.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_wls.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_wls_robustness.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_working_container.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_ybus.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tests/test_z_vector.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tools/gen_ieee_fixtures.py +0 -0
- {gridstate-2.5.0 → gridstate-2.6.0}/tools/golden.py +0 -0
|
@@ -9,6 +9,24 @@ types of the merged pull requests; breaking and behavior-changing items are
|
|
|
9
9
|
listed separately under "Breaking changes" and "Behavior changes". A release is
|
|
10
10
|
cut by tagging the merged main commit; the version is derived from that tag.
|
|
11
11
|
|
|
12
|
+
## v2.6.0 (2026-10-18)
|
|
13
|
+
|
|
14
|
+
### Behavior changes
|
|
15
|
+
|
|
16
|
+
- `ipm_pd` gets the 300-iteration budget with equality rows too (it was 100
|
|
17
|
+
before the primal fallback), including the global `ipm_balance_mode="hard"`:
|
|
18
|
+
with the adaptive box damping and the measurement-space stopping test of
|
|
19
|
+
v2.4.1 the long budget converges where the short one fell back.
|
|
20
|
+
|
|
21
|
+
### Feat
|
|
22
|
+
|
|
23
|
+
- `ipm_transit_balance_mode` (new, default `soft`): `hard` makes the P and Q
|
|
24
|
+
balance rows of transit nodes (no `exist_gen` / `exist_load`) equality
|
|
25
|
+
constraints of the solver, to `ipm_transit_balance_tol_p_mw` (new, default
|
|
26
|
+
0.01) / `ipm_transit_balance_tol_q_mvar` (new, default 0.1); the other
|
|
27
|
+
balance rows stay soft. The global hard balance overrides it. `IPMSetup`
|
|
28
|
+
gains `eq_rows` / `eq_tol`.
|
|
29
|
+
|
|
12
30
|
## v2.5.0 (2026-10-18)
|
|
13
31
|
|
|
14
32
|
### Behavior changes
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.
|
|
22
|
-
__version_tuple__ = version_tuple = (2,
|
|
21
|
+
__version__ = version = '2.6.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 6, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'ge81a73f8f'
|
|
@@ -826,7 +826,7 @@ def _run_ipm(
|
|
|
826
826
|
delta, v, _pg, _qg, _pn, _qn = unpack_full(x, layout_ipm)
|
|
827
827
|
return algebra.evaluate_jacobian(v, delta)
|
|
828
828
|
|
|
829
|
-
eq_idx = setup.
|
|
829
|
+
eq_idx = setup.eq_rows
|
|
830
830
|
pd_result: IPMResult | None = None
|
|
831
831
|
if solver == "ipm_pd":
|
|
832
832
|
mb_rows = mb_lo = mb_hi = None
|
|
@@ -852,13 +852,12 @@ def _run_ipm(
|
|
|
852
852
|
meas_box_lo=mb_lo,
|
|
853
853
|
meas_box_hi=mb_hi,
|
|
854
854
|
eq_idx=eq_idx,
|
|
855
|
-
eq_tol=setup.
|
|
855
|
+
eq_tol=setup.eq_tol,
|
|
856
856
|
mu_init=1.0,
|
|
857
857
|
step_tol=max(tolerance, 1e-4),
|
|
858
858
|
# Weakly determined units need up to ~260 iterations with separate
|
|
859
|
-
# injection parts
|
|
860
|
-
|
|
861
|
-
max_iter=max(max_iterations, 100 if eq_idx is not None else 300),
|
|
859
|
+
# injection parts, with or without equality rows.
|
|
860
|
+
max_iter=max(max_iterations, 300),
|
|
862
861
|
tr_radius=0.5,
|
|
863
862
|
huber_c=huber_c,
|
|
864
863
|
huber_mask=huber_mask,
|
|
@@ -910,7 +909,7 @@ def _run_ipm(
|
|
|
910
909
|
huber_adaptive_k=2.0,
|
|
911
910
|
kkt_solver=kkt,
|
|
912
911
|
eq_idx=eq_idx,
|
|
913
|
-
eq_tol=setup.
|
|
912
|
+
eq_tol=setup.eq_tol,
|
|
914
913
|
)
|
|
915
914
|
if solver == "ipm_pd":
|
|
916
915
|
result.message = f"ipm_pd fallback to ipm ({pd_message}): {result.message}"
|
|
@@ -219,7 +219,7 @@ def ipm_convergence_hints(
|
|
|
219
219
|
meas_index=setup.meas_index,
|
|
220
220
|
network_pu=network_pu,
|
|
221
221
|
# Equality rows: their σ is a penalty, not a measurement error.
|
|
222
|
-
skip=setup.
|
|
222
|
+
skip=setup.eq_rows,
|
|
223
223
|
part_rows=setup.role_rows,
|
|
224
224
|
top=top,
|
|
225
225
|
)
|
|
@@ -610,6 +610,38 @@ class PipelineConfig:
|
|
|
610
610
|
"median(σ²_data) / factor. Their injection is known to be zero; a loose balance "
|
|
611
611
|
"turns data conflicts into a fictitious injection. 0 — off.",
|
|
612
612
|
)
|
|
613
|
+
ipm_transit_balance_mode: str = _param(
|
|
614
|
+
"soft",
|
|
615
|
+
group=_G_IPM,
|
|
616
|
+
label="Balance mode of transit nodes",
|
|
617
|
+
control="select",
|
|
618
|
+
choices=["soft", "hard"],
|
|
619
|
+
depends={"algorithm": "ipm"},
|
|
620
|
+
help="soft — the balance of a transit node (no exist_gen/exist_load) is a "
|
|
621
|
+
"weighted row like the others (ipm_transit_balance_weight_factor); hard — an "
|
|
622
|
+
"equality constraint to ipm_transit_balance_tol_p_mw / _q_mvar, the other "
|
|
623
|
+
"balance rows stay soft. No effect when ipm_balance_mode=hard.",
|
|
624
|
+
)
|
|
625
|
+
ipm_transit_balance_tol_p_mw: float = _param(
|
|
626
|
+
0.01,
|
|
627
|
+
group=_G_IPM,
|
|
628
|
+
label="Transit balance tolerance P, MW",
|
|
629
|
+
control="number",
|
|
630
|
+
min=1e-6,
|
|
631
|
+
max=1e3,
|
|
632
|
+
depends={"ipm_transit_balance_mode": "hard"},
|
|
633
|
+
help="Admissible |P injection| of a transit node under the hard transit balance.",
|
|
634
|
+
)
|
|
635
|
+
ipm_transit_balance_tol_q_mvar: float = _param(
|
|
636
|
+
0.1,
|
|
637
|
+
group=_G_IPM,
|
|
638
|
+
label="Transit balance tolerance Q, MVAr",
|
|
639
|
+
control="number",
|
|
640
|
+
min=1e-6,
|
|
641
|
+
max=1e3,
|
|
642
|
+
depends={"ipm_transit_balance_mode": "hard"},
|
|
643
|
+
help="Admissible |Q injection| of a transit node under the hard transit balance.",
|
|
644
|
+
)
|
|
613
645
|
ipm_prior_sigma2_bus_equiv_pu: float = _param(
|
|
614
646
|
0.01,
|
|
615
647
|
group=_G_IPM,
|
|
@@ -52,6 +52,9 @@ def _ipm_kwargs(cfg: PipelineConfig) -> dict:
|
|
|
52
52
|
"prior_sigma2_bus_equiv_pu": cfg.ipm_prior_sigma2_bus_equiv_pu,
|
|
53
53
|
"boxed_balance_weight_factor": cfg.ipm_boxed_balance_weight_factor,
|
|
54
54
|
"transit_balance_weight_factor": cfg.ipm_transit_balance_weight_factor,
|
|
55
|
+
"transit_balance_mode": cfg.ipm_transit_balance_mode,
|
|
56
|
+
"transit_balance_tol_p_mw": cfg.ipm_transit_balance_tol_p_mw,
|
|
57
|
+
"transit_balance_tol_q_mvar": cfg.ipm_transit_balance_tol_q_mvar,
|
|
55
58
|
"trust_region_scope": cfg.ipm_trust_region_scope,
|
|
56
59
|
"balance_mode": cfg.ipm_balance_mode,
|
|
57
60
|
"balance_tol_p_mw": cfg.ipm_balance_tol_p_mw,
|
|
@@ -282,6 +282,11 @@ class IPMSetup:
|
|
|
282
282
|
# ``balance_tol`` holds the admissible |imbalance| per balance row in p.u.
|
|
283
283
|
# ``None`` in the soft mode.
|
|
284
284
|
balance_tol: np.ndarray | None = None
|
|
285
|
+
# Rows the solver enforces as equalities and their admissible |c| (p.u.):
|
|
286
|
+
# every balance row in the hard mode, the transit balance rows with
|
|
287
|
+
# ``transit_balance_mode="hard"``; ``None`` — no equality rows.
|
|
288
|
+
eq_rows: np.ndarray | None = None
|
|
289
|
+
eq_tol: np.ndarray | None = None
|
|
285
290
|
# ``injection_roles``: rows of ``z`` that measure a box variable directly
|
|
286
291
|
# (a generation / load part of a node injection) and their measurement ids;
|
|
287
292
|
# ``role_dropped_ids`` — part rows folded back into a net injection row.
|
|
@@ -556,6 +561,9 @@ def build_ipm_setup(
|
|
|
556
561
|
hard_balance_rho_factor: float = 1e3,
|
|
557
562
|
balance_tol_p_mw: float = 1.0,
|
|
558
563
|
balance_tol_q_mvar: float = 10.0,
|
|
564
|
+
transit_balance_mode: str = "soft",
|
|
565
|
+
transit_balance_tol_p_mw: float = 0.01,
|
|
566
|
+
transit_balance_tol_q_mvar: float = 0.1,
|
|
559
567
|
fixed_injection_from_input: bool = False,
|
|
560
568
|
injection_roles: bool = False,
|
|
561
569
|
measurements: _ArrayCollection | None = None,
|
|
@@ -628,6 +636,14 @@ def build_ipm_setup(
|
|
|
628
636
|
hard_balance_rho_factor: see ``balance_mode``.
|
|
629
637
|
balance_tol_p_mw, balance_tol_q_mvar: admissible |imbalance| of a hard
|
|
630
638
|
P / Q balance row (MW / MVAr).
|
|
639
|
+
transit_balance_mode: ``"soft"`` (default) — the balance rows of transit
|
|
640
|
+
nodes (no ``exist_gen`` / ``exist_load``) are weighted like the
|
|
641
|
+
others (see ``transit_balance_weight_factor``); ``"hard"`` — they are
|
|
642
|
+
equality constraints with the penalty of ``balance_mode="hard"``,
|
|
643
|
+
the other balance rows stay soft. Ignored when ``balance_mode`` is
|
|
644
|
+
already ``"hard"``.
|
|
645
|
+
transit_balance_tol_p_mw, transit_balance_tol_q_mvar: admissible
|
|
646
|
+
|injection| of a transit node in the hard transit mode (MW / MVAr).
|
|
631
647
|
fixed_injection_from_input: the balance row of a node carries the
|
|
632
648
|
input injection of its parts without a box variable (no
|
|
633
649
|
``exist_gen`` / ``exist_load``) as a fixed term instead of zero.
|
|
@@ -732,6 +748,11 @@ def build_ipm_setup(
|
|
|
732
748
|
if balance_mode not in ("soft", "hard"):
|
|
733
749
|
raise ValueError(f"balance_mode={balance_mode!r} is not one of ['soft', 'hard']")
|
|
734
750
|
hard = balance_mode == "hard"
|
|
751
|
+
if transit_balance_mode not in ("soft", "hard"):
|
|
752
|
+
raise ValueError(
|
|
753
|
+
f"transit_balance_mode={transit_balance_mode!r} is not one of ['soft', 'hard']"
|
|
754
|
+
)
|
|
755
|
+
transit_hard = transit_balance_mode == "hard" and not hard and n_balance > 0
|
|
735
756
|
|
|
736
757
|
# ---- Prior measurements: z=0, individual σ². Only for box-vars with σ²>0 ----
|
|
737
758
|
pgen_prior_arr = np.asarray(pgen_sec.prior_s2, dtype=np.float64)
|
|
@@ -816,6 +837,12 @@ def build_ipm_setup(
|
|
|
816
837
|
for start in (n_old, n_old + n_balance):
|
|
817
838
|
rows = sigma2_new[start : start + n_balance]
|
|
818
839
|
rows[transit] = np.minimum(rows[transit], transit_s2)
|
|
840
|
+
transit_eq = np.zeros(0, dtype=np.int64)
|
|
841
|
+
if transit_hard:
|
|
842
|
+
transit = _transit_mask(nodes_arr, active_ids)
|
|
843
|
+
pos = np.flatnonzero(transit)
|
|
844
|
+
transit_eq = np.concatenate([n_old + pos, n_old + n_balance + pos]).astype(np.int64)
|
|
845
|
+
sigma2_new[transit_eq] = _adaptive_balance_sigma2(sigma2_old, hard_balance_rho_factor)
|
|
819
846
|
if n_prior > 0:
|
|
820
847
|
prior_sigmas = np.concatenate(
|
|
821
848
|
[
|
|
@@ -893,6 +920,31 @@ def build_ipm_setup(
|
|
|
893
920
|
meas_id=new_meas_id,
|
|
894
921
|
)
|
|
895
922
|
|
|
923
|
+
balance_tol = (
|
|
924
|
+
np.concatenate(
|
|
925
|
+
[
|
|
926
|
+
np.full(n_balance, balance_tol_p_mw / BASE_MVA),
|
|
927
|
+
np.full(n_balance, balance_tol_q_mvar / BASE_MVA),
|
|
928
|
+
]
|
|
929
|
+
)
|
|
930
|
+
if hard
|
|
931
|
+
else None
|
|
932
|
+
)
|
|
933
|
+
eq_rows: np.ndarray | None = None
|
|
934
|
+
eq_tol: np.ndarray | None = None
|
|
935
|
+
if hard:
|
|
936
|
+
eq_rows = np.arange(n_old, n_old + 2 * n_balance, dtype=np.int64)
|
|
937
|
+
eq_tol = balance_tol
|
|
938
|
+
elif transit_eq.size:
|
|
939
|
+
n_t = transit_eq.size // 2
|
|
940
|
+
eq_rows = transit_eq
|
|
941
|
+
eq_tol = np.concatenate(
|
|
942
|
+
[
|
|
943
|
+
np.full(n_t, transit_balance_tol_p_mw / BASE_MVA),
|
|
944
|
+
np.full(n_t, transit_balance_tol_q_mvar / BASE_MVA),
|
|
945
|
+
]
|
|
946
|
+
)
|
|
947
|
+
|
|
896
948
|
return IPMSetup(
|
|
897
949
|
layout=layout,
|
|
898
950
|
box_idx_in_state=box_idx_arr,
|
|
@@ -907,16 +959,9 @@ def build_ipm_setup(
|
|
|
907
959
|
meas_index=meas_index_aug,
|
|
908
960
|
balance_start=n_old,
|
|
909
961
|
n_balance=n_balance,
|
|
910
|
-
balance_tol=
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
np.full(n_balance, balance_tol_p_mw / BASE_MVA),
|
|
914
|
-
np.full(n_balance, balance_tol_q_mvar / BASE_MVA),
|
|
915
|
-
]
|
|
916
|
-
)
|
|
917
|
-
if hard
|
|
918
|
-
else None
|
|
919
|
-
),
|
|
962
|
+
balance_tol=balance_tol,
|
|
963
|
+
eq_rows=eq_rows,
|
|
964
|
+
eq_tol=eq_tol,
|
|
920
965
|
role_rows=np.arange(role_start, n_new, dtype=np.int64),
|
|
921
966
|
role_meas_ids=role_ids.astype(np.int64),
|
|
922
967
|
role_dropped_ids=np.asarray(
|
|
@@ -75,6 +75,52 @@ def test_unknown_balance_mode_is_rejected():
|
|
|
75
75
|
_setup(_build_net_with_transit(), balance_mode="strict")
|
|
76
76
|
|
|
77
77
|
|
|
78
|
+
def test_transit_hard_mode_makes_only_transit_rows_equalities():
|
|
79
|
+
# Node order 1..4: node 2 is the transit node.
|
|
80
|
+
setup = _setup(
|
|
81
|
+
_build_net_with_transit(),
|
|
82
|
+
transit_balance_mode="hard",
|
|
83
|
+
transit_balance_tol_p_mw=0.02,
|
|
84
|
+
transit_balance_tol_q_mvar=0.2,
|
|
85
|
+
hard_balance_rho_factor=1e3,
|
|
86
|
+
)
|
|
87
|
+
assert setup.balance_tol is None
|
|
88
|
+
assert setup.eq_rows is not None and setup.eq_tol is not None
|
|
89
|
+
np.testing.assert_array_equal(setup.eq_rows, [2 + 1, 2 + N_BALANCE + 1])
|
|
90
|
+
np.testing.assert_allclose(setup.eq_tol, [0.02 / BASE_MVA, 0.2 / BASE_MVA])
|
|
91
|
+
sigma2 = setup.r_matrix.diagonal()[2 : 2 + 2 * N_BALANCE]
|
|
92
|
+
soft = _setup(_build_net_with_transit()).r_matrix.diagonal()[2 : 2 + 2 * N_BALANCE]
|
|
93
|
+
is_eq = np.zeros(2 * N_BALANCE, dtype=bool)
|
|
94
|
+
is_eq[[1, N_BALANCE + 1]] = True
|
|
95
|
+
assert np.allclose(sigma2[is_eq], 2.5e-4 / 1e3)
|
|
96
|
+
np.testing.assert_array_equal(sigma2[~is_eq], soft[~is_eq])
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_soft_modes_have_no_equality_rows():
|
|
100
|
+
setup = _setup(_build_net_with_transit(), transit_balance_weight_factor=10.0)
|
|
101
|
+
assert setup.eq_rows is None and setup.eq_tol is None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_global_hard_mode_overrides_the_transit_mode():
|
|
105
|
+
setup = _setup(
|
|
106
|
+
_build_net_with_transit(),
|
|
107
|
+
balance_mode="hard",
|
|
108
|
+
balance_tol_p_mw=2.0,
|
|
109
|
+
transit_balance_mode="hard",
|
|
110
|
+
transit_balance_tol_p_mw=0.02,
|
|
111
|
+
)
|
|
112
|
+
assert setup.eq_rows is not None and setup.eq_tol is not None
|
|
113
|
+
np.testing.assert_array_equal(setup.eq_rows, setup.balance_rows)
|
|
114
|
+
np.testing.assert_array_equal(setup.eq_tol, setup.balance_tol)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_unknown_transit_balance_mode_is_rejected():
|
|
118
|
+
with pytest.raises(ValueError, match="transit_balance_mode"):
|
|
119
|
+
_setup(_build_net_with_transit(), transit_balance_mode="strict")
|
|
120
|
+
with pytest.raises(ValueError, match="ipm_transit_balance_mode"):
|
|
121
|
+
PipelineConfig(algorithm="ipm_pd", ipm_transit_balance_mode="strict")
|
|
122
|
+
|
|
123
|
+
|
|
78
124
|
def test_fixed_injection_from_input():
|
|
79
125
|
m = _build_net_with_transit()
|
|
80
126
|
# Transit node 2 gets a non-estimated load and generation.
|
|
@@ -131,6 +177,26 @@ def test_hard_balance_closes_the_estimated_imbalance(algorithm: str):
|
|
|
131
177
|
assert imb_p <= 0.1 and imb_q <= 0.1
|
|
132
178
|
|
|
133
179
|
|
|
180
|
+
@pytest.mark.parametrize("algorithm", ["ipm", "ipm_pd"])
|
|
181
|
+
def test_transit_hard_balance_zeroes_the_transit_injection(algorithm: str):
|
|
182
|
+
# Soft, the transit node 2 absorbs the data conflict (≈ 4 MW / 14 MVAr).
|
|
183
|
+
soft = _build_net_with_transit()
|
|
184
|
+
estimate(soft, algorithm=algorithm, reconcile_balance=False, include_quality_summary=False)
|
|
185
|
+
n_soft = soft.nodes.to_numpy()
|
|
186
|
+
assert abs(n_soft["p_inj_calc"][1]) > 1.0 and abs(n_soft["q_inj_calc"][1]) > 1.0
|
|
187
|
+
m = _build_net_with_transit()
|
|
188
|
+
res = estimate(
|
|
189
|
+
m,
|
|
190
|
+
algorithm=algorithm,
|
|
191
|
+
reconcile_balance=False,
|
|
192
|
+
include_quality_summary=False,
|
|
193
|
+
transit_balance_mode="hard",
|
|
194
|
+
)
|
|
195
|
+
assert res.success
|
|
196
|
+
n = m.nodes.to_numpy()
|
|
197
|
+
assert abs(n["p_inj_calc"][1]) <= 0.01 and abs(n["q_inj_calc"][1]) <= 0.1
|
|
198
|
+
|
|
199
|
+
|
|
134
200
|
def test_ipm_pd_close_to_ipm():
|
|
135
201
|
results = {}
|
|
136
202
|
for algorithm in ("ipm", "ipm_pd"):
|
|
@@ -170,6 +236,7 @@ def test_measurement_bounds_require_ipm_pd():
|
|
|
170
236
|
def test_config_defaults_and_ranges():
|
|
171
237
|
cfg = PipelineConfig(algorithm="ipm_pd")
|
|
172
238
|
assert cfg.ipm_balance_mode == "soft"
|
|
239
|
+
assert cfg.ipm_transit_balance_mode == "soft"
|
|
173
240
|
assert not cfg.ipm_measurement_bounds and not cfg.ipm_fixed_injection_from_input
|
|
174
241
|
# The soft balance weight may now exceed the median measurement weight tenfold.
|
|
175
242
|
dataclasses.replace(cfg, ipm_balance_weight_factor=1e3)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|