Skip to content

Commit

Permalink
Bump version
Browse files Browse the repository at this point in the history
  • Loading branch information
bonjourmauko committed Dec 13, 2023
1 parent 82ddcc1 commit 6ede041
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 85 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

### 41.4.1 [#1202](https://github.com/openfisca/openfisca-core/pull/1202)

#### Technical changes

- Check that entities are fully specified when expanding over axes.

## 41.4.0 [#1197](https://github.com/openfisca/openfisca-core/pull/1197)

#### New features
Expand Down
38 changes: 0 additions & 38 deletions openfisca_core/simulations/_axis.py

This file was deleted.

12 changes: 1 addition & 11 deletions openfisca_core/simulations/helpers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
from __future__ import annotations

from typing import Type, Union

from openfisca_core.errors import SituationParsingError

from .typing import ExplParams


def calculate_output_add(simulation, variable_name: str, period):
return simulation.calculate_add(variable_name, period)
Expand All @@ -15,11 +9,7 @@ def calculate_output_divide(simulation, variable_name: str, period):
return simulation.calculate_divide(variable_name, period)


def check_type(
input: ExplParams,
input_type: Type[Union[dict, list, str]],
path: list[str] | None = None,
) -> None:
def check_type(input, input_type, path=None):
json_type_map = {
dict: "Object",
list: "Array",
Expand Down
15 changes: 7 additions & 8 deletions openfisca_core/simulations/simulation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import Dict, NamedTuple, Optional, Set, Union
from openfisca_core.types import Population, TaxBenefitSystem, Variable
from typing import Dict, NamedTuple, Optional, Set

import tempfile
import warnings
Expand All @@ -10,22 +11,20 @@
from openfisca_core import commons, errors, indexed_enums, periods, tracers
from openfisca_core import warnings as core_warnings

from .typing import GroupPopulation, SinglePopulation, TaxBenefitSystem, Variable


class Simulation:
"""
Represents a simulation, and handles the calculation logic
"""

tax_benefit_system: TaxBenefitSystem
populations: Dict[str, Union[SinglePopulation, GroupPopulation]]
populations: Dict[str, Population]
invalidated_caches: Set[Cache]

def __init__(
self,
tax_benefit_system: TaxBenefitSystem,
populations: Dict[str, Union[SinglePopulation, GroupPopulation]],
populations: Dict[str, Population],
):
"""
This constructor is reserved for internal use; see :any:`SimulationBuilder`,
Expand Down Expand Up @@ -531,7 +530,7 @@ def set_input(self, variable_name: str, period, value):
return
self.get_holder(variable_name).set_input(period, value)

def get_variable_population(self, variable_name: str) -> GroupPopulation:
def get_variable_population(self, variable_name: str) -> Population:
variable: Optional[Variable]

variable = self.tax_benefit_system.get_variable(
Expand All @@ -543,7 +542,7 @@ def get_variable_population(self, variable_name: str) -> GroupPopulation:

return self.populations[variable.entity.key]

def get_population(self, plural: Optional[str] = None) -> Optional[GroupPopulation]:
def get_population(self, plural: Optional[str] = None) -> Optional[Population]:
return next(
(
population
Expand All @@ -556,7 +555,7 @@ def get_population(self, plural: Optional[str] = None) -> Optional[GroupPopulati
def get_entity(
self,
plural: Optional[str] = None,
) -> Optional[GroupPopulation]:
) -> Optional[Population]:
population = self.get_population(plural)
return population and population.entity

Expand Down
47 changes: 24 additions & 23 deletions openfisca_core/simulations/simulation_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from openfisca_core import errors, periods

from . import helpers
from ._axis import _Axis
from ._type_guards import is_abbr_spec, is_axes_spec, is_expl_spec, is_impl_spec
from .simulation import Simulation
from .typing import (
Expand Down Expand Up @@ -65,7 +64,7 @@ class SimulationBuilder:
variable_entities: dict[str, Entity] = {}

#: Axes use for axes expansion.
axes: list[list[_Axis]]
axes: list[list[AxisParams]]

#: ?
axes_entity_counts: dict[str, int]
Expand Down Expand Up @@ -646,20 +645,20 @@ def get_roles(self, entity_name: str) -> Sequence[Role]:
def add_parallel_axis(self, axis: AxisParams) -> None:
# All parallel axes have the same count and entity.
# Search for a compatible axis, if none exists, error out
self.axes[0].append(_Axis(**axis))
self.axes[0].append(axis)

def add_perpendicular_axis(self, axis: AxisParams) -> None:
# This adds an axis perpendicular to all previous dimensions
self.axes.append([_Axis(**axis)])
self.axes.append([axis])

def expand_axes(self) -> None:
# This method should be idempotent & allow change in axes
perpendicular_dimensions: list[list[_Axis]] = self.axes
perpendicular_dimensions: list[list[AxisParams]] = self.axes
cell_count: int = 1

for parallel_axes in perpendicular_dimensions:
first_axis: _Axis = parallel_axes[0]
axis_count: int = first_axis.count
first_axis: AxisParams = parallel_axes[0]
axis_count: int = first_axis["count"]
cell_count *= axis_count

# Scale the "prototype" situation, repeating it cell_count times
Expand Down Expand Up @@ -701,30 +700,30 @@ def expand_axes(self) -> None:
if len(self.axes) == 1 and len(self.axes[0]):
parallel_axes = self.axes[0]
first_axis = parallel_axes[0]
axis_count: int = first_axis.count
axis_entity = self.get_variable_entity(first_axis.name)
axis_count: int = first_axis["count"]
axis_entity = self.get_variable_entity(first_axis["name"])
axis_entity_step_size = self.entity_counts[axis_entity.plural]
# Distribute values along axes
for axis in parallel_axes:
axis_index = axis.index
axis_period = axis.period or self.default_period
axis_name = axis.name
axis_index = axis.get("index", 0)
axis_period = axis.get("period", self.default_period)
axis_name = axis["name"]
variable = axis_entity.get_variable(axis_name)
array = self.get_input(axis_name, str(axis_period))
if array is None:
array = variable.default_array(axis_count * axis_entity_step_size)
elif array.size == axis_entity_step_size:
array = numpy.tile(array, axis_count)
array[axis_index::axis_entity_step_size] = numpy.linspace(
axis.min,
axis.max,
axis["min"],
axis["max"],
num=axis_count,
)
# Set input
self.input_buffer[axis_name][str(axis_period)] = array
else:
first_axes_count: list[int] = (
parallel_axes[0].count for parallel_axes in self.axes
parallel_axes[0]["count"] for parallel_axes in self.axes
)
axes_linspaces = [
numpy.linspace(0, axis_count - 1, num=axis_count)
Expand All @@ -733,14 +732,14 @@ def expand_axes(self) -> None:
axes_meshes = numpy.meshgrid(*axes_linspaces)
for parallel_axes, mesh in zip(self.axes, axes_meshes):
first_axis = parallel_axes[0]
axis_count = first_axis.count
axis_entity = self.get_variable_entity(first_axis.name)
axis_count = first_axis["count"]
axis_entity = self.get_variable_entity(first_axis["name"])
axis_entity_step_size = self.entity_counts[axis_entity.plural]
# Distribute values along the grid
for axis in parallel_axes:
axis_index = axis.index
axis_period = axis.period or self.default_period
axis_name = axis.name
axis_index = axis.get("index", 0)
axis_period = axis.get("period", self.default_period)
axis_name = axis["name"]
variable = axis_entity.get_variable(axis_name, check_existence=True)
array = self.get_input(axis_name, str(axis_period))
if array is None:
Expand All @@ -749,9 +748,11 @@ def expand_axes(self) -> None:
)
elif array.size == axis_entity_step_size:
array = numpy.tile(array, cell_count)
array[axis_index::axis_entity_step_size] = axis.min + mesh.reshape(
cell_count
) * (axis.max - axis.min) / (axis_count - 1)
array[axis_index::axis_entity_step_size] = axis[
"min"
] + mesh.reshape(cell_count) * (axis["max"] - axis["min"]) / (
axis_count - 1
)
self.input_buffer[axis_name][str(axis_period)] = array

def get_variable_entity(self, variable_name: str) -> Entity:
Expand Down
3 changes: 1 addition & 2 deletions openfisca_core/variables/variable.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

from numpy.typing import NDArray as Array
from openfisca_core.types import Formula, Instant
from typing import Optional, Union

Expand Down Expand Up @@ -468,7 +467,7 @@ def check_set_value(self, value):

return value

def default_array(self, array_size: int) -> Array:
def default_array(self, array_size):
array = numpy.empty(array_size, dtype=self.dtype)
if self.value_type == Enum:
array.fill(self.default_value.index)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@

setup(
name="OpenFisca-Core",
version="41.4.0",
version="41.4.1",
author="OpenFisca Team",
author_email="[email protected]",
classifiers=[
Expand Down
8 changes: 6 additions & 2 deletions tests/core/test_tracers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
from .parameters_fancy_indexing.test_fancy_indexing import parameters


class TestException(Exception):
...


class StubSimulation(Simulation):
def __init__(self):
self.exception = None
Expand Down Expand Up @@ -91,9 +95,9 @@ def test_tracer_contract(tracer):
def test_exception_robustness():
simulation = StubSimulation()
simulation.tracer = MockTracer()
simulation.exception = Exception(":-o")
simulation.exception = TestException(":-o")

with raises(Exception):
with raises(TestException):
simulation.calculate("a", 2017)

assert simulation.tracer.calculation_start_recorded
Expand Down

0 comments on commit 6ede041

Please sign in to comment.