library¶
This module has vocation to concentrate all the functions mentioned in input data files.
Todo
Equations’ indexes are to be improved again.
Note
Contact us as soon as you see something wrong and/or, ambiguous, which is likely given the very early stage of development we are in. Moreover, methods that rely on the structure of their arguments will sooner or later be turned structure-independent.
-
class
iamax.library.ArraysDealer¶ Mixin class that aggregates a bunch of private methods related to (numpy) arrays processing.
-
static
_take(ary: np.ndarray, idx: int, axis: int = 0, keepdims: bool = False)¶ Partialized version of
numpy.takewithmode='clip'to prevent negative indexing and/orIndexError.- Parameters
ary (numpy.ndarray) – Array to be sliced.
idx (int) – Integer index of interest along axis
axis.axis (int) – Axis the slice must be taken along.
0by default.keepdims (bool) – Whether the reduced axis is left in the result as size-one dimension. To
Falseby default.
Note
The original
numpy.takefunction does not feature the keepdims argument, which this method does because of the API divergence on that matter between JAX and NumPy.- Example
>>> ary = np.arange(6).reshape(3, 2) >>> ary array([[0, 1], [2, 3], [4, 5]]) >>> ArraysDealer._take(ary=ary, idx=0) array([0, 1]) >>> ArraysDealer._take(ary=ary, idx=-1) array([0, 1]) >>> ArraysDealer._take(ary=ary, idx=2) array([4, 5]) >>> ArraysDealer._take(ary=ary, idx=3) array([4, 5]) >>> ArraysDealer._take(ary=ary, idx=3, keepdims=True) array([[4, 5]])
-
static
_split(ary: np.ndarray, indices: list[int], axis: int = 0)¶ Split an array into multiple sub-arrays as views into
ary.- Parameters
Note
Compared to its
numpy.split()counterpart, this method can be identity.- Example
>>> ArraysDealer._split(ary=np.arange(3), indices=[1, -1]) [array([0]), array([1]), array([2])] >>> ArraysDealer._split(ary=np.arange(3), indices=[1, None]) [array([0]), array([1, 2]), array([], dtype=int32)] >>> ArraysDealer._split(ary=np.arange(3), indices=[0, -1]) [array([], dtype=int32), array([0, 1]), array([2])] >>> ArraysDealer._split(ary=np.arange(3), indices=[0, 2]) [array([], dtype=int32), array([0, 1]), array([2])] >>> ArraysDealer._split(ary=np.arange(3), indices=[0, None]) [array([], dtype=int32), array([0, 1, 2]), array([], dtype=int32)]
-
static
_infs_to_num(x: np.ndarray, posinf: float = _posinf, neginf: float = _neginf)¶ Replace infinity with numbers.
- Parameters
x (numpy.ndarray) – Array to be processed.
posinf (float) – Value to be used to fill positive infinity values. Set to
numpy.finfo(float).maxby default.neginf (float) – Value to be used to fill negative infinity values. Set to
numpy.finfo(float).minby default.
- Example
>>> ArraysDealer._infs_to_num( ... x=np.array([np.inf, -np.inf, np.nan]), ... posinf=1, neginf=-1 ... ) array([ 1., -1., nan])
-
classmethod
_sum(cls, a: np.ndarray, axis: int = None, keepdims: bool = False)¶ Pro-differentiation NAN-immunized sum of array elements over a given axis.
- Parameters
ary (numpy.ndarray) – Array to be processed.
axis (int) – Axis or axes along which a sum is performed. To
Noneby default.keepdims (bool) – Whether the reduced axis is left in the result as size-one dimension. To
Falseby default.
Note
This (class) method requires a clipping upper bound to prevent floating-point overflow during computations. When summing large values, intermediate results can exceed the maximum representable value for
numpy.float64. Additionally, in the context of second-order derivatives (Hessian), quadratic growth amplifies these values, further increasing the risk of overflow. Clipping ensures numerical stability by constraining intermediate results to a manageable range while preserving the overall summation behavior.
-
static
_divide(n: np.ndarray, d: np.ndarray, nan: float = 0.0, num_infs: bool = False)¶ Pro-differentiation NAN-immunized divider.
- Parameters
n (numpy.ndarray) – Numerator operand.
d (numpy.ndarray) – Denominator operand.
nan (float or numpy.ndarray) – Value to be used to fill
float('nan')values. Set to0.by default.num_infs (boolean) – Whether positive and negative infinity are to replaced with large finite numbers. Set to
Falseby default.
- Example
>>> ArraysDealer._divide( ... n=(n := np.ones(3)), ... d=np.zeros_like(n), ... ) array([0., 0., 0.])
-
static
_multiply(a: np.ndarray, b: np.ndarray)¶ Pro-differentiation NAN-immunized to-0 multiplicator.
- Parameters
a (numpy.ndarray) – Potentially equal-to-0 operand.
b (numpy.ndarray) – Potentially equal-to-0 other operand.
- Example
>>> a, b = 0, float('inf') >>> a * b nan >>> ArraysDealer._multiply(a, b) array(0.)
Note
Implying this method may not be sufficient if. e.g one of the operands potentially consists in a by-0-division.
-
classmethod
_rdistance(cls, f: np.ndarray, c: np.ndarray)¶ Quasi-scale-invariant division-by-0-immunized symmetrical signed distance computer.
(174)¶\[D(\boldsymbol{f}, \boldsymbol{c}) = \left( \frac{ \boldsymbol{f}-\boldsymbol{c} }{ \sqrt{ \varepsilon^{2} + \boldsymbol{f}^{2} + \boldsymbol{c}^{2} } } \right)\]See also
- Parameters
f (numpy.ndarray) – First array to be processed.
c (numpy.ndarray) – Second array to be processed.
- Example
>>> ArraysDealer._rdistance(f=np.array(2), c=np.array(3)) 0.27732343367971996 >>> ArraysDealer._rdistance(f=np.array(3), c=np.array(2)) -0.27732343367971996 >>> ArraysDealer._rdistance(f=np.array(2), c=np.array(0)) -0.9996876464081226 >>> ArraysDealer._rdistance(f=np.array(0), c=np.array(2)) 0.9996876464081226 >>> ArraysDealer._rdistance(f=np.ones(3), c=np.arange(3)) array([-1. , 0. , 0.45])
-
classmethod
_constancy(cls, ary: np.ndarray, axis: int = None, keepdims: bool = False, where: np.ndarray[bool]|bool = True)¶ Compute a dimensionless smooth subgradient-based manhattan “constancy” metric along a specified axis.
- Parameters
ary (numpy.ndarray) – Array to be processed.
axis (int) – Axis the process must be performed along.
Noneby default.keepdims (bool) – Whether the reduced axis is left in the result as size-one dimension. To
Falseby default.where (numpy.ndarray or bol) – Elements to include in the sum. Set to
Trueby default, which boils down to include all elements.
- Example
>>> a = np.array([[-1., .0, 1.]]) >>> ArraysDealer._constancy(ary=a, keepdims=True) array([[0.82]])
>>> v = np.stack((a, np.ones_like(a), np.zeros_like(a))) >>> ArraysDealer._constancy(ary=v, axis=2, keepdims=True) array([[[0.82]], [[0. ]], [[0. ]]])
-
classmethod
_power(cls, x1: np.ndarray, x2: np.ndarray, num_infs: bool = False, div_by_0_to_0: bool = True, compute_croots: bool = False)¶ Pro-differentiation NAN-immunized power operator.
- Parameters
x1 (numpy.ndarray) – Bases of exponentiation.
x2 (numpy.ndarray) – Exponents.
num_infs (boolean) – Whether positive and negative infinity are to replaced with large finite numbers. Set to
Falseby default.div_by_0_to_0 (bool) – Whether divisions by
0should result in0s instead of resulting innumpy.inf. Set toTrueby default.compute_croots (bool) – Whether complex roots are allowed. Set to
Falseby default.
Attention
Argument
compute_crootsisn’t well tested. Do not use unless you know exactly what you are doing.Order-dependent special cases below are expressed relative to the real-axis reference values \(-1\), \(0\), \(1\) and \(\pm\infty\). They therefore apply only to operands lying on that same complex line. Genuinely non-real finite operands bypass these real-domain branches and are evaluated by
numpy.power.Complex-valued infinite limits are instead characterized through their modulus. For a finite complex base \(z\) and a real exponent tending to \(\pm\infty\), convergence to \(0\) or infinity depends on whether \(|z|\) is respectively below or above \(1\). Conversely, for a complex base whose modulus tends to infinity and a finite exponent \(w\), convergence depends on the sign of \(\Re(w)\).
Boundary configurations for which no unique complex limit exists are mapped to
0.as a NAN-immunization convention. Such values must not be interpreted as mathematical limits.- Example
>>> ꚙ = np.inf >>> x1 = np.array([ ... 1, .5, .5, 2, 2, -.5, -.5, -2, -2, -2, 0, 0, ꚙ, ꚙ, ꚙ, -ꚙ, ... ]) >>> x2 = np.array([ ... ꚙ, -ꚙ, ꚙ, -ꚙ, ꚙ, -ꚙ, ꚙ, -ꚙ, ꚙ, -.5, ꚙ, -ꚙ, ꚙ, -ꚙ, 0, 0, ... ]) >>> np.vstack(( ... x1, x2, ... ArraysDealer._power( ... x1, x2, num_infs=False, div_by_0_to_0=False, ... ), ... )).T array([[ 1. , inf, 1. ], [ 0.5, -inf, inf], [ 0.5, inf, 0. ], [ 2. , -inf, 0. ], [ 2. , inf, inf], [-0.5, -inf, inf], [-0.5, inf, 0. ], [-2. , -inf, 0. ], [-2. , inf, inf], [-2. , -0.5, 0. ], [ 0. , inf, 0. ], [ 0. , -inf, inf], [ inf, inf, inf], [ inf, -inf, 0. ], [ inf, 0. , 1. ], [-inf, 0. , 1. ]]) >>> np.vstack(( ... x1, x2, ... ArraysDealer._power( ... x1, x2, num_infs=False, div_by_0_to_0=False, ... compute_croots=True ... ), ... )).T array([[ 1. +0.j, inf+0.j, 1. +0.j], [ 0.5+0.j, -inf+0.j, inf+0.j], [ 0.5+0.j, inf+0.j, 0. +0.j], [ 2. +0.j, -inf+0.j, 0. +0.j], [ 2. +0.j, inf+0.j, inf+0.j], [-0.5+0.j, -inf+0.j, inf+0.j], [-0.5+0.j, inf+0.j, 0. +0.j], [-2. +0.j, -inf+0.j, 0. +0.j], [-2. +0.j, inf+0.j, inf+0.j], [-2. +0.j, -0.5+0.j, -2. +0.j], [ 0. +0.j, inf+0.j, 0. +0.j], [ 0. +0.j, -inf+0.j, inf+0.j], [ inf+0.j, inf+0.j, inf+0.j], [ inf+0.j, -inf+0.j, 0. +0.j], [ inf+0.j, 0. +0.j, 1. +0.j], [-inf+0.j, 0. +0.j, 1. +0.j]])
Genuinely complex finite bases are instead preserved as complex operands.
>>> x1 = np.array( ... -0.0020594357921656713 ... - 0.003567047426956803j ... ) >>> ArraysDealer._power(x1, np.array(-1.5)) array(-3782.97+4.63e-13j)
-
classmethod
_weighter(cls, a: np.ndarray, axis: int = -1, keepdims: bool = False)¶ s/e.
- Parameters
ary (numpy.ndarray) – Array to be processed.
axis (int) – Axis or axes along which a sum is performed. To
Noneby default.keepdims (bool) – Whether the reduced axis is left in the result as size-one dimension. To
Falseby default.
-
static
_lminusr_computer(a: np.ndarray, keepdims: bool, axis: int = -1)¶ Compute the difference between the sum of the first (left) half and the sum of the second (right) half along the specified axis.
- Parameters
a (numpy.ndarray) – Array of even horizontal size.
keepdims (bool) – Whether the output has the same number of dimensions as the input.
axis (int) – Axis or axes along which a sum is performed. Set to
-1bu default.
- Example
>>> (a := np.array([[1, 2, 3, 4], [3, 4, 1, 2]])) array([[1, 2, 3, 4], [3, 4, 1, 2]]) >>> ArraysDealer._lminusr_computer(a, keepdims=True) array([[-4], [ 4]])
Another example showing that the first half is favored in case of uneven split.
>>> (a := np.array([[1, 1, 2, 3, 4], [0, 3, 4, 1, 2]])) array([[1, 1, 2, 3, 4], [0, 3, 4, 1, 2]]) >>> ArraysDealer._lminusr_computer(a, keepdims=True) array([[-3], [ 4]])
-
static
-
class
iamax.library.RatesDealer¶ Mixin class that aggregates a bunch of private methods related to rates calculations, conversions, etc.
-
static
_markup_to_margin_rater(mkr: np.ndarray|float)¶ Markup-to-margin rate converter.
\[\text{mgr} = \frac{\text{mkr}}{1 + \text{mkr}}\]- Parameters
mkr (numpy.ndarray or float) – Markup rate to be processed.
- Example
>>> RatesDealer._markup_to_margin_rater(mkr=1.0).item() 0.5
-
static
_margin_to_markup_rater(mgr: np.ndarray|float)¶ Margin-to-markup rate converter.
\[\text{mkr} = \frac{\text{mgr}}{1 - \text{mgr}}\]- Parameters
mgr (numpy.ndarray or float) – Margin rate to be processed.
- Example
>>> RatesDealer._margin_to_markup_rater(mgr=.5).item() 1.0
-
static
-
class
iamax.library.Passive(*_, **__)¶ Class to be (used directly or) inherited from to explicit the idea of an entity not actively at work and whose e.g. consumption/production is determined by the system’s set of constraints.
-
class
iamax.library.AddedOPCosts¶ Class whose name is rather, say, self-explanatory.
-
static
operating_cost_computer(*, operating_costs: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(175)¶\[v_{q,j} = \sum_{k \in \mcI_j} v_{q,k}\]with \(\mcI_j\) the index set required to get \(v_{q,j}\).
- Parameters
operating_costs (numpy.ndarray) – \((\bv_{q,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
operating_costs’s slice.- Example
>>> a = np.array([[1., 0., 4.]]) >>> AddedOPCosts.operating_cost_computer( ... operating_costs=a ... ) array([[5.]])
Let’s vectorize the above example.
>>> AddedOPCosts.operating_cost_computer( ... operating_costs=np.stack((a, .1*a)) ... ) array([[[5. ]], [[0.5]]])
-
static
-
class
iamax.library.AddedVolumes¶ Class whose name is rather, say, self-explanatory.
-
static
employed_volume_computer(*, employed_volumes: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(176)¶\[q_j = \sum_{k \in \mcI_j} q_k\]with \(\mcI_j\) the index set required to get \(q_j\).
- Parameters
employed_volumes (numpy.ndarray) – \((\bq_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
employed_volumes’s slice.- Example
>>> a = np.array([[1., 0., 4.]]) >>> AddedVolumes.employed_volume_computer( ... employed_volumes=a ... ) array([[5.]])
Let’s vectorize the above example.
>>> AddedVolumes.employed_volume_computer( ... employed_volumes=np.stack((a, .1*a)) ... ) array([[[5. ]], [[0.5]]])
-
static
available_volume_rooter(*, t: int, available_volumes: np.ndarray)¶ s/e., \(1 \times 1\) unit-dimensionless zero, denoted as
(177)¶\[-1 + \frac{\hq_j}{\sum_{k \in \mcI_j} \hq_k} \approx 0\]with \(\mcI_j\) the index set required to get \(\hq_j\).
- Parameters
t (int) – Year-targeting integer index. Cf.
t, i.e. a_ilocalizations’s integer element.available_volumes (numpy.ndarray) – The \(j\)th \(|\mcL| \times (1 + |\mcI_j|)\)
available_volumes’s slice.
See also
\(|\mcL|\)’s archetype
_ilocalizations.Important
The variable
tis involved to provide the current method with (column-bound) time series arguments. Indeed, the first element of such arguments is always associated with the variable that is being targeted.Note
This method is vectorization friendly over the
-3th axis, if any.- Example
>>> a = np.array([ ... [[0, 0, 0]], ... [[5, 3, 2]], ... [[6, 3, 0]], ... [[3, 6, 0]], ... ]) >>> AddedVolumes.available_volume_rooter( ... t=1, available_volumes=a ... ) array([[0.]]) >>> AddedVolumes.available_volume_rooter( ... t=2, available_volumes=a ... ) array([[-0.45]]) >>> AddedVolumes.available_volume_rooter( ... t=3, available_volumes=a ... ) array([[0.45]])
Let’s vectorize the above example, keeping in mind that the temporal axis must remain first (hence the
numpy.ndarray.swapaxesbelow).>>> (v := np.stack((a, .1*a)).swapaxes(1, 0)) array([[[[0. , 0. , 0. ]], [[0. , 0. , 0. ]]], [[[5. , 3. , 2. ]], [[0.5, 0.3, 0.2]]], [[[6. , 3. , 0. ]], [[0.6, 0.3, 0. ]]], [[[3. , 6. , 0. ]], [[0.3, 0.6, 0. ]]]]) >>> AddedVolumes.available_volume_rooter( ... t=1, available_volumes=v ... ) array([[[0.]], [[0.]]]) >>> AddedVolumes.available_volume_rooter( ... t=2, available_volumes=v ... ) array([[[-0.45]], [[-0.45]]]) >>> AddedVolumes.available_volume_rooter( ... t=3, available_volumes=v ... ) array([[[0.45]], [[0.45]]])
-
static
-
class
iamax.library.ImplicitTransitories¶ Class that abstracts the idea of economic agents who are just accounting artifacts that need, at some point, to be formalized explicitly regarding their “custom QOIs” only.
-
static
transitory_computer(transitories: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(178)¶\[\mcr_j = \sum_{k \in \mcI_j} \mcr_k\]with \(\mcI_j\) the index set required to get \(\mcr_j\).
- Parameters
transitories (numpy.ndarray) – The \(j\)th \(1 \times |\mcI_j|\) slice of
transitories.- Example
>>> a = np.array([[4., 6.]]) >>> ImplicitTransitories.transitory_computer( ... transitories=a ... ) array([[10.]])
Let’s vectorize the above example for free.
>>> ImplicitTransitories.transitory_computer( ... transitories=np.vstack((a, .1*a)) ... ) array([[10.], [ 1.]])
-
static
-
class
iamax.library.ImplicitIncome¶ Class that abstracts the idea of economic agents who are just accounting artifacts that need, at some point, to be formalized explicitly regarding their disposable income only.
-
static
budget_constraint_computer(budget_constraints: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(179)¶\[\mcr_j = \sum_{k \in \mcI_j} \mcr_k\]with \(\mcI_j\) the index set required to get \(\mcr_j\).
- Parameters
budget_constraints (numpy.ndarray) – \((\bmcr_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
budget_constraints’s slice.- Example
>>> a = np.array([[4., 6.]]) >>> ImplicitIncome.budget_constraint_computer( ... budget_constraints=a ... ) array([[10.]])
Let’s vectorize the above example for free.
>>> ImplicitIncome.budget_constraint_computer( ... budget_constraints=np.vstack((a, .1*a)) ... ) array([[10.], [ 1.]])
-
static
-
class
iamax.library.ImplicitEntity¶ 
Class that abstracts the idea of economic agents who are just accounting artifacts that need, at some point, to be formalized explicitly.
Note
This class has not vocation to be vectorization friendly since implicit entities are recursively function of each others.
-
static
other_costs_computer(other_costs: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(180)¶\[v_{\ootau,\ j} = \sum_{k \in \mcI_j} v_{\ootau,\ k}\]with \(\mcI_j\) the index set required to get \(v_{\ootau,\ j}\).
- Parameters
other_costs (numpy.ndarray) – \((\bv_{\ootau,\ k})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
other_costs.
-
static
net_surplus_computer(net_surplus: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(181)¶\[\pi_{j} = \sum_{k \in \mcI_j} \pi_{k}\]with \(\mcI_j\) the index set required to get \(\pi_{j}\).
- Parameters
net_surplus (numpy.ndarray) – \((\bpi_{k})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
net_surplus.
-
static
routed_private_income_computer(routed_private_incomes: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(182)¶\[\mcr_{\text{cum},\ j} = \sum_{k \in \mcI_j} \mcr_{\text{cum},\ k}\]with \(\mcI_j\) the index set required to get \(\mcr_{\text{cum},\ j}\).
- Parameters
routed_private_incomes (numpy.ndarray) – \((\bmcr_k)_{\text{cum},\ k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
routed_private_incomes.
-
static
input_values_computer(input_values: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(183)¶\[\bmcV_{:,j} = \sum_{k \in \mcI_j} \bmcV_{:,k}\]with \(\mcI_j\) the index set required to get \(\bmcV_{:,j}\).
- Parameters
input_values (numpy.ndarray) – \((\bmcV_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
input_values’s slice.
See also
\(\mcI\)’s archetype
_iidentifiers.- Example
>>> a = np.hstack(( ... _1s := np.ones((4,))[:, None], ... _1s.cumsum(axis=0), .5*_1s, ... )) >>> a array([[1. , 1. , 0.5], [1. , 2. , 0.5], [1. , 3. , 0.5], [1. , 4. , 0.5]]) >>> ImplicitEntity.input_values_computer(input_values=a) array([[2.5], [3.5], [4.5], [5.5]])
Let’s vectorize the above example.
>>> (v := np.stack((a, .1*a))) array([[[1. , 1. , 0.5 ], [1. , 2. , 0.5 ], [1. , 3. , 0.5 ], [1. , 4. , 0.5 ]], [[0.1 , 0.1 , 0.05], [0.1 , 0.2 , 0.05], [0.1 , 0.3 , 0.05], [0.1 , 0.4 , 0.05]]]) >>> ImplicitEntity.input_values_computer(input_values=v) array([[[2.5 ], [3.5 ], [4.5 ], [5.5 ]], [[0.25], [0.35], [0.45], [0.55]]])
-
static
specific_margins_computer(specific_margins: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(184)¶\[\bV^{(\utau)}_{:,j} = \sum_{k \in \mcI_j} \bV^{(\utau)}_{:,k}\]with \(\mcI_j\) the index set required to get \(\bV^{(\utau)}_{:,j}\).
- Parameters
specific_margins (numpy.ndarray) – \((\bV^{(\utau)}_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
specific_margins’s slice.
-
static
trade_margins_computer(trade_margins: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(185)¶\[\bV^{(\jtau)}_{:,j} = \sum_{k \in \mcI_j} \bV^{(\jtau)}_{:,k}\]with \(\mcI_j\) the index set required to get \(\bV^{(\jtau)}_{:,j}\).
- Parameters
trade_margins (numpy.ndarray) – \((\bV^{(\jtau)}_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
trade_margins’s slice.
-
static
sales_taxes_computer(sales_taxes: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(186)¶\[\bV^{(\htau)}_{:,j} = \sum_{k \in \mcI_j} \bV^{(\htau)}_{:,k}\]with \(\mcI_j\) the index set required to get \(\bV^{(\htau)}_{:,j}\).
- Parameters
sales_taxes (numpy.ndarray) – \((\bV^{(\htau)}_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
sales_taxes’s slice.
-
static
excises_computer(excises: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(187)¶\[\bV^{(\ctau)}_{:,j} = \sum_{k \in \mcI_j} \bV^{(\ctau)}_{:,k}\]with \(\mcI_j\) the index set required to get \(\bV^{(\ctau)}_{:,j}\).
- Parameters
excises (numpy.ndarray) – \((\bV^{(\ctau)}_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
excises’s slice.
-
static
-
class
iamax.library.BalanceOfTrade¶ Accounting entity that consists in a given nation’s net exports.
-
static
budget_constraint_computer(budget_constraints: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(188)¶\[\mcr_j = \sum_{k=1}^{|\mcI_j|/2} \mcr_k - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} \mcr_k\]with \(\mcI_j\) the index set required to get \(\mcr_j\), by default asserted to be of even cardinality.
- Parameters
budget_constraints (numpy.ndarray) – \((\bmcr_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
budget_constraints’s slice.
Important
This method relies on the structure of its argument, with exports concentrated in the first half of
budget_constraintsand imports in the second.- Example
>>> a = np.array([[4., 16., 3., 2.]]) >>> BalanceOfTrade.budget_constraint_computer( ... budget_constraints=a ... ) array([[15.]])
Let’s vectorize the above example
>>> (v := np.stack((a, a[:, ::-1]))) array([[[ 4., 16., 3., 2.]], [[ 2., 3., 16., 4.]]]) >>> BalanceOfTrade.budget_constraint_computer( ... budget_constraints=v ... ) array([[[ 15.]], [[-15.]]])
-
static
other_costs_computer(other_costs: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(189)¶\[v_{\ootau,\ j} = \sum_{k=1}^{|\mcI_j|/2} v_{\ootau,\ k} - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} v_{\ootau,\ k}\]with \(\mcI_j\) the index set required to get \(v_{\ootau,\ j}\), by default asserted to be of even cardinality.
- Parameters
other_costs (numpy.ndarray) – \((\bv_{\ootau,\ k})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
other_costs.
Important
This method relies on the structure of its argument, with exports concentrated in the first half of
other_costsand imports in the second.
-
static
net_surplus_computer(net_surplus: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(190)¶\[\pi_{j} = \sum_{k=1}^{|\mcI_j|/2} \pi_{k} - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} \pi_{k}\]with \(\mcI_j\) the index set required to get \(\pi_{j}\), by default asserted to be of even cardinality.
- Parameters
net_surplus (numpy.ndarray) – \((\bpi_{k})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
net_surplus.
Important
This method relies on the structure of its argument, with exports concentrated in the first half of
net_surplusand imports in the second.
-
static
routed_private_income_computer(routed_private_incomes: np.ndarray)¶ s/e., \(1 \times 1\), denoted as
(191)¶\[\mcr_{\text{cum},\ j} = \sum_{k=1}^{|\mcI_j|/2} \mcr_{\text{cum},\ k} - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} \mcr_{\text{cum},\ k}\]with \(\mcI_j\) the index set required to get \(\mcr_{\text{cum},\ j}\), by default asserted to be of even cardinality.
- Parameters
routed_private_incomes (numpy.ndarray) – \((\bmcr_k)_{\text{cum},\ k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
routed_private_incomes.
Important
This method relies on the structure of its argument, with exports concentrated in the first half of
routed_private_incomesand imports in the second.
-
static
input_values_computer(input_values: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(192)¶\[\bmcV_{:,j} = \sum_{k=1}^{|\mcI_j|/2} \bmcV_{:,k} - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} \bmcV_{:,k}\]with \(\mcI_j\) the index set required to get \(\bmcV_{:,j}\), by default asserted to be of even cardinality.
- Parameters
input_values (numpy.ndarray) – \((\bmcV_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
input_values’s slice.
See also
\(\mcI\)’s archetype
_iidentifiers.- Example
>>> a = np.hstack(( ... x := np.arange(-2, 3)[:, None], ... m := np.ones_like(x), ... )) >>> a array([[-2, 1], [-1, 1], [ 0, 1], [ 1, 1], [ 2, 1]]) >>> BalanceOfTrade.input_values_computer(input_values=a) array([[-3], [-2], [-1], [ 0], [ 1]])
Let’s vectorize the above example.
>>> (v := np.stack((a, -2*a))) array([[[-2, 1], [-1, 1], [ 0, 1], [ 1, 1], [ 2, 1]], [[ 4, -2], [ 2, -2], [ 0, -2], [-2, -2], [-4, -2]]]) >>> BalanceOfTrade.input_values_computer(input_values=v) array([[[-3], [-2], [-1], [ 0], [ 1]], [[ 6], [ 4], [ 2], [ 0], [-2]]])
Yet another example with an odd number of trade components.
>>> a = np.hstack((x , np.ones_like(x), m)) >>> (v := np.stack((a, -a))) array([[[-2, 1, 1], [-1, 1, 1], [ 0, 1, 1], [ 1, 1, 1], [ 2, 1, 1]], [[ 2, -1, -1], [ 1, -1, -1], [ 0, -1, -1], [-1, -1, -1], [-2, -1, -1]]]) >>> BalanceOfTrade.input_values_computer(input_values=v) array([[[-2], [-1], [ 0], [ 1], [ 2]], [[ 2], [ 1], [ 0], [-1], [-2]]])
-
static
specific_margins_computer(specific_margins: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(193)¶\[\bV^{(\utau)}_{:,j} = \sum_{k=1}^{|\mcI_j|/2} \bV^{(\utau)}_{:,j} - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} \bV^{(\utau)}_{:,j}\]with \(\mcI_j\) the index set required to get \(\bV^{(\utau)}_{:,j}\), asserted to be of even cardinality.
- Parameters
specific_margins (numpy.ndarray) – \((\bV^{(\utau)}_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
specific_margins’s slice.
-
static
trade_margins_computer(trade_margins: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(194)¶\[\bV^{(\jtau)}_{:,j} = \sum_{k=1}^{|\mcI_j|/2} \bV^{(\jtau)}_{:,j} - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} \bV^{(\jtau)}_{:,j}\]with \(\mcI_j\) the index set required to get \(\bV^{(\jtau)}_{:,j}\), asserted to be of even cardinality.
- Parameters
trade_margins (numpy.ndarray) – \((\bV^{(\jtau)}_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
trade_margins’s slice.
-
static
sales_taxes_computer(sales_taxes: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(195)¶\[\bV^{(\htau)}_{:,j} = \sum_{k=1}^{|\mcI_j|/2} \bV^{(\htau)}_{:,j} - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} \bV^{(\htau)}_{:,j}\]with \(\mcI_j\) the index set required to get \(\bV^{(\htau)}_{:,j}\), asserted to be of even cardinality.
- Parameters
sales_taxes (numpy.ndarray) – \((\bV^{(\htau)}_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
sales_taxes’s slice.
-
static
excises_computer(excises: np.ndarray)¶ s/e., \(|\mcI_j| \times 1\), denoted as
(196)¶\[\bV^{(\ctau)}_{:,j} = \sum_{k=1}^{|\mcI_j|/2} \bV^{(\ctau)}_{:,j} - \sum_{k=1 + |\mcI_j|/2}^{|\mcI_j|} \bV^{(\ctau)}_{:,j}\]with \(\mcI_j\) the index set required to get \(\bV^{(\ctau)}_{:,j}\), asserted to be of even cardinality.
- Parameters
excises (numpy.ndarray) – \((\bV^{(\ctau)}_{:,k})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI| \times |\mcI_j|\)
excises’s slice.
-
static
-
class
iamax.library.AQConserver¶ Class that captures the essence of the conservation law regarding additive quantities.
-
static
additive_output_volume_rooter(output_volume: np.ndarray, aggregated_input_volumes: np.ndarray)¶ s/e., \(1 \times 1\) unit-dimensionless zero.
(197)¶\[\approx 0\]- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.aggregated_input_volumes (numpy.ndarray) – \((\bq^{T,\text{drate}}_{k,1})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
aggregated_input_volumes’s slice.
- Example
>>> ovol = 10. >>> aivols = np.array([[6., 4.]]) >>> AQConserver.additive_output_volume_rooter( ... output_volume=ovol, aggregated_input_volumes=aivols, ... ) array([[0.]])
>>> vovol = np.array([[[ovol]], [[.5*ovol]]]) >>> vovol array([[[10.]], [[ 5.]]]) >>> vaivols = np.stack((aivols, .5*aivols[..., ::-1])) >>> vaivols array([[[6., 4.]], [[2., 3.]]]) >>> AQConserver.additive_output_volume_rooter( ... output_volume=vovol, aggregated_input_volumes=vaivols, ... ) array([[[0.]], [[0.]]])
-
static
-
class
iamax.library.SymmetricNodes¶ Class that captures the essence of entities balancing each other out through
routed_private_incomeattribute.-
static
routed_private_income_rooter(routed_private_incomes: np.ndarray)¶ s/e., \(1 \times 1\) unit-dimensionless zero.
- Parameters
routed_private_incomes (numpy.ndarray) – \((\bmcr_k)_{\text{cum},\ k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
routed_private_incomes.- Example
>>> a = np.array([[.9, -.9]]) >>> SymmetricNodes.routed_private_income_rooter( ... routed_private_incomes=a ... ) array([[0.]])
Let’s vectorize the above example.
>>> v = np.stack(( ... np.array([[.5, -.5]]), ... np.array([[.0, -.5]]), ... np.array([[.5, .0]]), ... )) >>> SymmetricNodes.routed_private_income_rooter( ... routed_private_incomes=v ... ) array([[[ 0.]], [[ 1.]], [[-1.]]])
-
static
-
class
iamax.library.BalancedWorldTrade¶ Class that refers to the requirement in international economics that the sum of all trade balances across regions must equal zero. This identity reflects the idea that every export is matched by an import somewhere else, ensuring that total exports equal total imports when viewed globally.
Note
This class assumes that world trade is resolved in terms of physical volumes.
-
static
spendings_dfree_rooter(spendings_dfree: np.ndarray)¶ s/e., \(1 \times 1\) unit-dimensionless zero.
- Parameters
spendings_dfree (numpy.ndarray) – \((\bmcv_k)_{\neg\ttau,\ k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
spendings_dfree.- Example
>>> a = np.array([[.9, -.9]]) >>> BalancedWorldTrade.spendings_dfree_rooter( ... spendings_dfree=a ... ) array([[0.]])
Let’s vectorize the above example.
>>> v = np.stack(( ... np.array([[.5, -.5]]), ... np.array([[.0, -.5]]), ... np.array([[.5, .0]]), ... )) >>> BalancedWorldTrade.spendings_dfree_rooter( ... spendings_dfree=v ... ) array([[[ 0.]], [[ 1.]], [[-1.]]])
-
static
Class that abstracts the idea of agents who jointly own 100% of an activity’s outstanding shares.
s/e., \(1 \times 1\) unit-dimensionless zero.
(198)¶\[\approx 0\]- Parameters
income_private_circuit_rsto (numpy.ndarray) – \((\obtheta_{k})_{k \in \mcI_j}\), i.e. a \(1 \times |\mcI_j|\) slice of
income_private_circuit_rsto.
See also
- Example
>>> a = np.array([[.9]]) >>> Shareholders.income_private_circuit_rsto_rooter( ... income_private_circuit_rsto=a ... ) array([[-0.1]])
Let’s vectorize the above example.
>>> (v := np.stack((a, 1 - a, a + .1))) array([[[0.9]], [[0.1]], [[1. ]]]) >>> Shareholders.income_private_circuit_rsto_rooter( ... income_private_circuit_rsto=v ... ) array([[[-0.1]], [[-0.9]], [[ 0. ]]])
-
class
iamax.library.Accountant¶ Static class (to be inherited) that aggregates a bunch of methods related to accounting equations.
-
static
output_price_computer(*, output_volume: float, input_values: np.ndarray)¶ s/e., \(1 \times 1\).
(199)¶\[\up_j = \frac{\sum_{k \in \mcI_j} \mcv_k}{q_j}\]with \(\mcI_j\) the index set required to get \(\up_j\).
- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.
See also
- Example
>>> a = 1. >>> b = np.array([[1., 9.]]) >>> Accountant.output_price_computer( ... output_volume=a, input_values=b ... ) array([[10.]])
Let’s vectorize the above example
>>> Accountant.output_price_computer( ... output_volume=np.atleast_2d([a, 5*a]).T, ... input_values=np.vstack((b, b)) ... ) array([[10.], [ 2.]])
-
static
-
class
iamax.library.CoInitiatedVolumes(scaling_factor: float = 1.0)¶ Class that abstracts the concept of (independent) volumes whose initial state are yet to be determined jointly.
- Parameters
scaling_factor (float) – S/e. set to
1by default.
-
output_volumes_ccomputer(self, *, input_values: np.ndarray, additive_output_volumes: np.ndarray)¶ s/e.
- Parameters
additive_output_volumes (numpy.ndarray) – \(q_j\), i.e. the \(j\)ths \(1 \times 1\)
additive_output_volumes’s elements, whose last component only is of interest.input_values (numpy.ndarray) – \((\bmcV_{kk,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI_j| \times |\mcI_j| + 1\)
input_values’s slice (diagonal) rectangular slice.
Important
This method relies on the structure of its argument, as outlined in the description of argument
additive_output_volumes.Attention
By appending its output with a 0, this method overwrites the last component of the targeted attribute.
-
class
iamax.library.BalancedSM¶ Class that abstracts the concept of specific margins summing to zero across consumers subjected to it.
-
static
specific_margin_balance_rooter(specific_margins_balances: np.ndarray)¶ s/e., \(1 \times 1\) unit-dimensionless zero.
- Parameters
specific_margins_balances (numpy.ndarray) – \(\bv_{\utau,\ j}\), i.e. the \(j\)th \(1 \times 1\) element of
specific_margins_balances.- Example
>>> a = np.array([[.9]]) >>> BalancedSM.specific_margin_balance_rooter( ... specific_margins_balances=a ... ) array([[0.9]])
Let’s vectorize the above example.
>>> v = np.stack(( ... np.array([[.5]]), ... np.array([[.0]]), ... np.array([[.5]]), ... )) >>> BalancedSM.specific_margin_balance_rooter( ... specific_margins_balances=v ... ) array([[[0.5]], [[0. ]], [[0.5]]])
-
static
-
class
iamax.library.InitiallyBalancedSM¶ BalancedSM’s counterpart that restricts the balancing at time t=0.-
static
specific_margin_balance_crooter(specific_margins_balances: np.ndarray)¶ s/e., \(1 \times 1\) unit-dimensionless zero.
- Parameters
specific_margins_balances (numpy.ndarray) – \(\bv_{\utau,\ j}\), i.e. the \(j\)th \(1 \times 1\)
specific_margins_balances’s element.- Example
>>> a = np.array([[.9]]) >>> InitiallyBalancedSM.specific_margin_balance_crooter( ... specific_margins_balances=a ... ) array([[0.9]])
Let’s vectorize the above example.
>>> v = np.stack(( ... np.array([[.5]]), ... np.array([[.0]]), ... np.array([[.5]]), ... )) >>> InitiallyBalancedSM.specific_margin_balance_crooter( ... specific_margins_balances=v ... ) array([[[0.5]], [[0. ]], [[0.5]]])
-
static
-
class
iamax.library.CES(sigma: float|tuple[float]|np.ndarray, nu: float|tuple[float]|np.ndarray = 1.0, eta: float|tuple[float]|np.ndarray = 0.0)¶ Constant Elasticity of Substitution base class and/or mixin class.
- Parameters
sigma (float or np.ndarray) – The elasticity of substitution \(\sigma \in [0,+\infty]\), with the substitution parameter being defined as \(\rho = \frac{\sigma - 1}{\sigma}\).
nu (float) – The degree of homogeneity of the aggregation \(\nu \in ]0,+\infty]\), set to
1.by default.eta (float) – The responsiveness parameter \(\eta \in [-\infty,+\infty]\), used under dynamic circumstances, if any. Set to
.0by default.
Note
This class can either be linear, Cobb–Douglas or Leontief:
If \((\sigma \to \infty) \iff (\rho \to 1)\), we get a linear or perfect substitutes function;
If \((\sigma \to 1) \iff (\rho \to 0)\), we get a Cobb–Douglas function;
If \((\sigma \to 0) \iff (\rho \to -\infty)\), we get a Leontief or perfect complements function.
- Example
>>> CES(sigma=0).aggregation_type 'Leontief' >>> CES(sigma=.5).aggregation_type 'Gross complements' >>> CES(sigma=1).aggregation_type 'Cobb–Douglas' >>> CES(sigma=2).aggregation_type 'Imperfect Substitutes' >>> CES(sigma=np.inf).aggregation_type 'Perfect substitutes' >>> CES(sigma=[0, 1, np.inf]).aggregation_type ['Leontief', 'Cobb–Douglas', 'Perfect substitutes']
-
property
aggregation_type(self)¶ Aggregation qualifier, be this aggregation related to cardinal (e.g. production) or ordinal (e.g. utility level) quantities.
- Example
>>> CES(sigma=[0, 1, np.inf]).aggregation_type ['Leontief', 'Cobb–Douglas', 'Perfect substitutes']
-
property
sigma(self)¶ Elasticity of substitution \(\sigma\in[0,+\infty]\).
-
property
rho(self)¶ Substitution parameter \(\rho\in[-\infty,1]\).
-
property
nu(self)¶ Aggregation’s degree of homogeneity \(\nu\in]0,+\infty]\).
-
property
eta(self)¶ Responsiveness to input price changes \(\eta\in \mathbb{R}\).
-
abstract
compute_calibrand_0(self, **kwargs: float)¶ Method to be called during calibration.
Attention
This method is assumed (but not asserted) to only be dealing with Keyword-Only Arguments.
Warning
This method will likely be reattached as soon as a technology (or preference) morphism being ontologically upstream of
CESis defined.
-
_aggregator(self, *, shares: np.ndarray, aggregands: np.ndarray)¶ Class’s core morphism, \(1 \times 1\), denoted as
(200)¶\[y = n^{-\nu\text{I}(\rho=-\infty)} \left(\prod_{i=1}^n x_i^{\nu a_i\text{I}(\rho=0)}\right) \left( \sum_{i=1}^n a_i x_i^{\rho^{\text{I}(\rho\neq-\infty)}} \right)^{ \frac{\nu\text{I}(\rho\neq0)}{ \rho^{\text{I}(\rho\neq-\infty)\text{I}(\rho\neq0)} } }\]where \(n=\text{dim}(\boldsymbol{x})\), \(y\) is the quantity of aggregate, \(x_i\) the quantity of \(i\)-aggregand, \(a_i\) its associated share, \(\rho\) the substitution parameter and \(\nu\) the homogeneity degree of the aggregation.
Note
At \(\rho=0\), the ordinary CES contribution is neutralized, while the multiplicative contribution becomes
(201)¶\[y &= \prod_{i=1}^n x_i^{\nu a_i} &= \left(\prod_{i=1}^n x_i^{a_i}\right)^\nu,\]i.e. the Cobb-Douglas limit. Since the degree of homogeneity of this expression is \(\nu\sum_i a_i\), retaining \(\nu\) as the homogeneity degree requires
(202)¶\[\sum_{i=1}^n a_i = 1.\]At \(\rho=1\), both the Leontief normalization and Cobb-Douglas contribution are neutral, while the ordinary CES contribution reduces to
(203)¶\[y = \left(\sum_{i=1}^n a_i x_i\right)^\nu,\]i.e. the perfect-substitutes form, which becomes linear under constant returns to scale, \(\nu=1\).
At the Leontief limit \(\rho=-\infty\), the power applied to each aggregand and the outer CES exponent both reduce to \(1\) and \(\nu\), respectively, so that
(204)¶\[y &= n^{-\nu} \left(\sum_{i=1}^n a_i x_i\right)^\nu &= \left(\frac{1}{n}\sum_{i=1}^n a_i x_i\right)^\nu.\]Aggregands are assumed in this case to be supplied in perfectly complementary quantities,
(205)¶\[a_i x_i = a_{i'}x_{i'} \quad \forall i,i',\]implying
(206)¶\[\frac{1}{n}\sum_{i=1}^n a_i x_i = \min_i\{a_i x_i\}.\]The usual complementarity operator can therefore be replaced, over this restricted domain, by the smooth arithmetic expression above without changing the resulting aggregate.
This method is vectorization friendly over the 0th axis. Incidentally, it may also be turned into instance method once the developments stabilize.
- Parameters
shares (numpy.ndarray) – \(1 \times n\) archetype of the distribution parameters.
aggregands (numpy.ndarray) – \(1 \times n\) archetype of the aggregands.
- Example
>>> kws = {'aggregands': np.array([[1782.232, 19190.896]])}
Let’s first play with a gross-complement case.
>>> agc = np.array([[0.29151, 0.95657]]) >>> CES(sigma=2.)._aggregator(shares=agc, **kws) array([[20973.22]])
At the Cobb-Douglas limit, consider normalized distribution parameters.
>>> acd = np.array([[.25, .75]]) >>> CES(sigma=1.)._aggregator(shares=acd, **kws) array([[10594.06]])
At the perfect-substitutes limit, aggregation becomes linear under constant returns to scale.
>>> aps = agc >>> CES(sigma=np.inf)._aggregator(shares=aps, **kws) array([[18876.97]])
At the Leontief limit, consider three aggregands supplied in perfectly complementary quantities. Their share-adjusted quantities are consequently identical.
>>> apc = 1e4 / kws['aggregands'] >>> apc array([[5.61, 0.52]]) >>> CES(sigma=0.)._aggregator(shares=apc, **kws) array([[10000.]])
The same construction preserves the specified degree of homogeneity.
>>> CES(sigma=0., nu=2.)._aggregator(shares=apc, **kws) array([[1.e+08]])
Let’s illustrate how such calculation can be vectorized along the 0th axis.
>>> vces = CES(sigma=np.array([[.0], [1.], [2.], [np.inf]])) >>> vces._aggregator( ... shares=np.vstack((apc, acd, agc, aps)), **kws ... ) array([[10000. ], [10594.06], [20973.22], [18876.97]]) >>> vces.aggregation_type ['Leontief', 'Cobb–Douglas', 'Imperfect Substitutes', 'Perfect substitutes']
-
class
iamax.library.CESCapacity¶ 
Benchmark-calibrated
CESmorphism from productive quantity underliers to potential output.Calibration identifies the
CESdistribution parameters required for observed productive underliers to support the potential output implied by observed production and its idle rate. Subsequent aggregation is entirely delegated to_aggregator().-
compute_calibrand_0(self, *, output_volume_underlier: float, idle_rate: float, input_volumes_underliers: np.ndarray)¶ Calibrate productive-capacity CES distribution parameters.
Let \(\uq_j\) denote observed output underlier of aggregate \(j\), \(\tau_{\neg q,j}\) its idle rate and
(207)¶\[\mfc_j = \frac{\uq_j}{1-\tau_{\neg q,j}}\]the corresponding potential output. For productive underlier \(k \in \mcI_j\), calibration sets
(208)¶\[a_{k,j} = |\mcI_j|^{-\text{I}(\rho_j\neq-\infty)} \left( \frac{\mfc_j^{1/\nu_j}}{\uQ_{k,j}} \right)^{\rho_j^{\text{I}(\rho_j\neq-\infty)}}.\]Thus, for finite nonzero \(\rho_j\), observed underliers make equal benchmark contributions,
(209)¶\[a_{k,j}\uQ_{k,j}^{\rho_j} = \frac{\mfc_j^{\rho_j/\nu_j}}{|\mcI_j|}.\]At the Leontief limit, the same calibration instead yields
(210)¶\[a_{k,j}\uQ_{k,j} = \mfc_j^{1/\nu_j},\]thereby satisfying the perfect-complementarity condition expected by
_aggregator().- Parameters
output_volume_underlier (float) – \(\uq_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes_underliers’s element.idle_rate (float) – \(\tau_{\neg q,j}\), i.e. the \(j\)th \(1 \times 1\)
idle_rates’s element.input_volumes_underliers (numpy.ndarray) – \((\ubQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes_underliers’s slice.
Note
With only one benchmark observation, relative technological contributions are not independently identified. Calibration therefore assigns equal benchmark contributions wherever the CES parametrization permits this directly.
At the Cobb-Douglas limit, Eq.208 reduces to \(a_{k,j}=1/|\mcI_j|\). Consequently, exact benchmark reproduction additionally requires
(211)¶\[\mfc_j = \left( \prod_{k \in \mcI_j} uQ_{k,j}^{1/|\mcI_j|} \right)^{\nu_j}.\]This follows from retaining normalized CES shares and \(\nu_j\) as the inherited homogeneity degree; an arbitrary additional Cobb-Douglas scale cannot be encoded in those shares alone.
- Example
Consider first a single productive underlier. With observed output
80, a20%idle rate and an underlier quantity of100, benchmark potential output is also100.>>> ivolu = np.array([[100.]]) >>> c = CESCapacity(sigma=2.).compute_calibrand_0( ... output_volume_underlier=np.array([[80.]]), ... input_volumes_underliers=ivolu, ... idle_rate=np.array([[.2]]), ... ) >>> c.calibrand_0 array([[1.]])
With a single underlier, the same unit calibrand is obtained across all four aggregation regimes when benchmark potential output and the underlier quantity coincide.
>>> vivolu = np.array(4*[[[100.]]]) >>> vovolu = np.array(4*[[[80.]]]) >>> virate = np.array(4*[[[.2]]]) >>> c = CESCapacity( ... sigma=np.array([[[2.]], [[1.]], [[np.inf]], [[0.]]]) ... ) >>> c.compute_calibrand_0( ... output_volume_underlier=vovolu, ... input_volumes_underliers=vivolu, ... idle_rate=virate, ... ).calibrand_0 array([[[1.]], [[1.]], [[1.]], [[1.]]])
Consider now two productive underliers supporting potential output
100from observed production80and a20%idle rate.>>> ivolus = np.array([[50., 200.]]) >>> c = CESCapacity(sigma=2.).compute_calibrand_0( ... output_volume_underlier=np.array([[80.]]), ... input_volumes_underliers=ivolus, ... idle_rate=np.array([[.2]]), ... ) >>> c.calibrand_0 array([[0.71, 0.35]])
Let’s illustrate how such calculation can be vectorized along the 0th axis across the four aggregation regimes.
>>> vivolus = np.repeat(ivolus[None, ...], 4, axis=0) >>> vovolu = np.array(4*[[[80.]]]) >>> virate = np.array(4*[[[.2]]]) >>> c = CESCapacity( ... sigma=np.array([[[2.]], [[1.]], [[np.inf]], [[0.]]]) ... ) >>> c.aggregation_type ['Imperfect Substitutes', 'Cobb–Douglas', 'Perfect substitutes', 'Leontief'] >>> c.compute_calibrand_0( ... output_volume_underlier=vovolu, ... input_volumes_underliers=vivolus, ... idle_rate=virate, ... ).calibrand_0 array([[[0.71, 0.35]], [[0.5 , 0.5 ]], [[1. , 0.25]], [[2. , 0.5 ]]])
See also
-
output_volume_potentiation(self, *, input_volumes_underliers: np.ndarray)¶ Potentiate productive quantity underliers into potential output.
Potential output is obtained directly from the inherited
_aggregator(), usingcalibrand_0as its distribution parameters and current productive underliers as its aggregands.- Parameters
input_volumes_underliers (numpy.ndarray) – \((\ubQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes_underliers’s slice.
Note
This method is vectorization friendly over the 0th axis.
- Example
Consider first a single productive underlier. With observed output
80, a20%idle rate and an underlier quantity of100, benchmark potential output is100and the calibrated distribution parameter is one.>>> c = CESCapacity(sigma=-1).compute_calibrand_0( ... output_volume_underlier=np.array([[80.]]), ... input_volumes_underliers=np.array([[100.]]), ... idle_rate=np.array([[.2]]), ... ) >>> c.calibrand_0 array([[1.]]) >>> c.output_volume_potentiation( ... input_volumes_underliers=np.array([[100.]]) ... ) array([[100.]])
Here,
sigma=-1deliberately lies outside the economically admissible CES domain to emphasize that, with a single productive underlier, substitution is immaterial: there is no alternative input to substitute toward or away from. Under constant returns to scale, the resulting one-underlier productive-capacity morphism is therefore the identity, irrespective of \(\sigma\), so a change in the productive underlier translates one-for-one into potential output.>>> c.output_volume_potentiation( ... input_volumes_underliers=np.array([[120.]]) ... ) array([[120.]]) >>> c.output_volume_potentiation( ... input_volumes_underliers=np.array([[75.]]) ... ) array([[75.]])
This identity is independent of the substitution regime when there is only one underlier and its calibrated distribution parameter is one.
>>> vivolu = np.array(4*[[[100.]]]) >>> vovolu = np.array(4*[[[80.]]]) >>> virate = np.array(4*[[[.2]]]) >>> c = CESCapacity( ... sigma=np.array([[[2.]], [[1.]], [[np.inf]], [[0.]]]) ... ).compute_calibrand_0( ... output_volume_underlier=vovolu, ... input_volumes_underliers=vivolu, ... idle_rate=virate, ... ) >>> c.output_volume_potentiation( ... input_volumes_underliers=np.array(4*[[[120.]]]) ... ) array([[[120.]], [[120.]], [[120.]], [[120.]]])
Consider now the two-underlier calibration above. The four aggregation regimes all reproduce the same benchmark potential output.
>>> ivolus = np.array([[50., 200.]]) >>> vivolus = np.repeat(ivolus[None, ...], 4, axis=0) >>> vovolu = np.array(4*[[[80.]]]) >>> virate = np.array(4*[[[.2]]]) >>> c = CESCapacity( ... sigma=np.array([[[2.]], [[1.]], [[np.inf]], [[0.]]]) ... ).compute_calibrand_0( ... output_volume_underlier=vovolu, ... input_volumes_underliers=vivolus, ... idle_rate=virate, ... ) >>> c.output_volume_potentiation( ... input_volumes_underliers=vivolus ... ) array([[[100.]], [[100.]], [[100.]], [[100.]]])
A common halving of all productive underliers preserves their relative configuration and, under constant returns to scale, halves potential output in every regime.
>>> c.output_volume_potentiation( ... input_volumes_underliers=.5 * vivolus ... ) array([[[50.]], [[50.]], [[50.]], [[50.]]])
See also
-
-
class
iamax.library.HicksianCES(*args, **kwargs)¶ 
Constant Elasticity of Substitution abstraction whose optimal demand function derives from a maximization program formulated à la Hicks.
Note
Eq.200’s \(\nu\) is fully internalized as the technology’s degree of homogeneity. Hicksian input demands consequently scale with \(q_j^{1/\nu_j}\), while the output producer price is the dual shadow price of \(q_j\).
-
compute_calibrand_0(self, *, output_volume: float, input_volumes: np.ndarray, input_values: np.ndarray)¶ This method supports the FOC-based calibration of \((a_{k,j})_{k \in \mcI_j}\), the \(|\mcI_j|\) demand distribution parameters related to aggregate \(j\),
(212)¶\[a_k = \left[ \left( \frac{\mcv_k}{\sum_{k' \in \mcI_j} \mcv_{k'}} \right)^{ \text{I}(\rho_j \neq -\infty) } \left(\frac{q_j^{1/\nu_j}}{q_k}\right)^{ \rho_j^{\text{I}(\rho_j \neq -\infty)} } \right]^{\text{I}(\rho_j \neq 1)}, \ \forall k \ \in \mcI_j\]with \(q_j\) the output level to be satisfied, \(\rho_j\) the substitution parameter, \(\nu_j\) the degree of homogeneity, \(\mcI_j\) the index set of inputs required by \(q_j\)’s underlying technology, \(q_k\) the optimal level of input required to meet \(q_j\), \(\mcv_k\) the \(q_k\)’s input value and \(\text{I}(\cdot)\) an indicator function returning the trueness of the statement being passed as argument.
- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.
- Example
>>> ovol = 20973.128 >>> ivols = np.array([[1782.232, 19190.896]]) >>> ivals = 1e3*ivols
>>> h = HicksianCES(sigma=2.) >>> _ = h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... ) >>> h.calibrand_0 array([[0.29, 0.96]])
The same technology calibration is recovered for \(\nu_j=2\) when the output target is squared:
>>> hν = HicksianCES(sigma=2., nu=2.).compute_calibrand_0( ... output_volume = ovol**2, ... input_volumes = ivols, ... input_values = ivals, ... ) >>> hν.calibrand_0 array([[0.29, 0.96]])
Let’s illustrate how such calculation can be vectorized along the 0th axis.
>>> vovol = np.array([[[ovol]], [[ovol]]]) >>> vivols = np.stack((ivols, .1*ivols)) >>> vivals = 1e3*vivols
>>> h.compute_calibrand_0( ... output_volume = vovol, ... input_volumes = vivols, ... input_values = vivals, ... ).calibrand_0 array([[[0.29, 0.96]], [[0.92, 3.02]]])
The non-constant instantiation parameters case follows.
>>> h = HicksianCES(sigma=[[[2.]], [[3.]]]) >>> _ = h.compute_calibrand_0( ... output_volume = vovol, ... input_volumes = vivols, ... input_values = vivals, ... ) >>> h.calibrand_0 array([[[0.29, 0.96]], [[2.04, 4.51]]])
See also
-
compute_calibrand_0_star(self, *, ioq_shares_drates: np.ndarray, ioq_shares_drates2: np.ndarray, ioq_productivities_drates: np.ndarray, ioq_productivities_drates2: np.ndarray)¶ Define
calibrand_0_star, i.e. a version ofcalibrand_0that internalizes (crises-like) shocks,(213)¶\[\begin{split}a_k^{*} &= a_k \left( 1 + \beta^{\text{drate}}_k + \beta^{\text{drate}^{ii}}_k \right)^{ \rho_j^{\text{I}(\rho_j \neq -\infty)} \text{I}(\rho_j \neq 1) } \\ & \left( 1 + \alpha^{-1,\ \text{drate}}_k + \alpha^{-1,\ \text{drate}^{ii}}_k \right)^{\text{I}(\rho_j = -\infty)}, \ \forall k \ \in \mcI_j\end{split}\]where \(a_k\) and \(\rho_j\) are as defined in Eq.212, \(\beta^\text{drate}_k\) and \(\beta^{\text{drate}^{ii}}_k\) are respectively a crisis-like shock and a spread from it, \(\alpha^{-1,\ \text{drate}^{ii}}_k\) and \(\alpha^{-1,\ \text{drate}}_k\) are, respectively, a scenarized productivity (discrete) growth and a spread from it.
- Parameters
ioq_shares_drates (numpy.ndarray) – \((\bbeta^\text{drate}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_shares_drates’s slice.ioq_shares_drates2 (numpy.ndarray) – \((\bbeta^{\text{drate}^{ii}}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_shares_drates2’s slice.ioq_productivities_drates (numpy.ndarray) – \((\balpha^{-1,\ \text{drate}_{k,j}})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_productivities_drates’s slice.ioq_productivities_drates2 (numpy.ndarray) – \((\balpha^{-1,\ \text{drate}^{ii}_{k,j}})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_productivities_drates2’s slice.
Note
ioq_productivities_drateshas vocation to “overwrite”ioq_shares_dratessooner or later.Important
Keep in mind that \(a_k\) and \(\rho_j\) are internally handled as instance attributes, i.e. in the same manner as
calibrand_0andrho.
Alleged input shares, \(1 \times |\mcI_j|\), denoted as
where \(\eta_j\) is a \(j\)-specific responsiveness parameter and \(\mcI_j\) and \(p_k\) are as described in Eq.219.
- Parameters
input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.input_prices_lagged (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of the lagged version of
input_prices.ioq_intensities_lagged (numpy.ndarray) – \((\balpha_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of the lagged version of
ioq_intensities.
- Example
>>> invariants = dict( ... input_prices = np.array([[1., 1.25]]), ... input_prices_lagged = np.array([[1., 1.]]), ... ioq_intensities_lagged = np.array([[.4, .6]]), ... )
>>> HicksianCES( ... sigma=np.inf, eta=0. ... ).allege_input_shares(**invariants).alleged_input_shares array([[0.4, 0.6]]) >>> HicksianCES( ... sigma=np.inf, eta=1. ... ).allege_input_shares(**invariants).alleged_input_shares array([[0.35, 0.65]]) >>> HicksianCES( ... sigma=np.inf, eta=4. ... ).allege_input_shares(**invariants).alleged_input_shares array([[0.21, 0.79]])
-
compute_input_volumes_shocks(self, *, input_volumes_drates: np.ndarray)¶ Input-volume shocks, \(1 \times |\mcI_j|\), calculated and assigned to attribute
input_volumes_shockssince required in several methods of the instance.(215)¶\[\bQ^\text{dmult}_j = 1 + \bQ^\text{drate}_j\]- Parameters
input_volumes_drates (numpy.ndarray) – \((\bQ^\text{drate}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes_drates’s slice.
Note
Since the name of this method mirrors nothing within the list of eligible variables (be them related to targets or arguments), it will be assumed to work in place.
Important
Keep in mind that
input_volumes_shocksis defined and internally handled as instance attributes, cf. the example section below.- Example
>>> h = HicksianCES(sigma=None) >>> h.compute_input_volumes_shocks( ... input_volumes_drates=np.array([[.1, .2]]) ... ).input_volumes_shocks array([[1.1, 1.2]])
-
_output_volume_computer(self, *, input_volumes: np.ndarray)¶ Output supply, \(1 \times 1\), denoted as
(216)¶\[q_j = |\mcI_j|^{-\nu_j\text{I}(\rho_j=-\infty)} \left( \prod_{k \in \mcI_j} q_k^{\nu_j a_k\text{I}(\rho_j=0)} \right) \left( \sum_{k \in \mcI_j} a_k q_k^{\rho_j^{\text{I}(\rho_j\neq-\infty)}} \right)^{ \frac{\nu_j\text{I}(\rho_j\neq0)}{ \rho_j^{ \text{I}(\rho_j\neq-\infty) \text{I}(\rho_j\neq0) } } }\]where \(|\mcI_j|\) is the number of inputs associated with aggregate \(j\), while \(\mcI_j\), \(q_j\), \(q_k\), \(a_k\), \(\rho_j\), \(\nu_j\) and \(\text{I}(\cdot)\) are as described in Eq.212.
See also
Note
Eq.216 is unconditionally valid only when \(q_{k=1, \ldots, |\mcI_j|}\)’s levels are the optimal input demands’.
- Parameters
input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.- Example
>>> ovol = 20973.128 >>> ivols = np.array([[1782.232, 19190.896]]) >>> ivals = 1e3*ivols
>>> h = HicksianCES(sigma=2.) >>> _ = h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals ... ) >>> h._output_volume_computer( ... input_volumes = ivols, ... ) array([[20973.13]])
The degree of homogeneity is fully internalized in output supply:
>>> hν = HicksianCES(sigma=2., nu=2.).compute_calibrand_0( ... output_volume = ovol**2, ... input_volumes = ivols, ... input_values = ivals ... ) >>> hν._output_volume_computer(input_volumes=ivols).item() 439872098.1043841 >>> ovol**2 439872098.104384
Let’s illustrate how such calculation can be vectorized along the 0th axis.
>>> vovol = np.array([[[ovol]], [[.5*ovol]], [[ovol]]]) >>> vivols = np.stack((ivols, .5*ivols, ivols)) >>> vivals = 1e3*vivols
>>> _ = h.compute_calibrand_0( ... output_volume = vovol, ... input_volumes = vivols, ... input_values = vivals, ... ) >>> h._output_volume_computer( ... input_volumes = vivols, ... ) array([[[20973.13]], [[10486.56]], [[20973.13]]])
-
compute_output_price_driver(self, *, output_price_drate: np.ndarray)¶ Output-price multiplicative driver, \(1 \times 1\), calculated and assigned to attribute
output_price_driver.(217)¶\[d_j = 1 + \up^\text{drate}_j\]- Parameters
output_price_drate (float) – \(\up^\text{drate}_j\), i.e. the \(j\)th \(1 \times 1\)
producer_net_prices_drates’s element.
Note
The driver multiplicatively shifts the technology-implied producer price returned by
output_price_computer().
-
output_price_computer(self, *, output_volume: float, input_prices: np.ndarray)¶ Output producer price, \(1 \times 1\), denoted as
(218)¶\[\up_j = d_j \frac{q_j^{1/\nu_j-1}}{\nu_j} \left( \sum_{k \in \mcI_j} \left[ a_k^{ (-1)^{\text{I}(\sigma_j = 0)} \sigma_j^{\text{I}(\sigma_j \neq 0)} } \right]^{\text{I}(\sigma_j \neq \infty)} p_k^{ (1 - \sigma_j)^{\text{I}(\sigma_j \neq \infty)} } s_k^{\text{I}(\sigma_j = \infty)} \right)^{ (1 - \sigma_j)^{-\text{I}(\sigma_j \neq \infty)} }\]where \(\mcI_j\), \(q_j\), \(a_k\), \(\nu_j\) and \(\text{I}(\cdot)\) are as in Eq.212, \(\sigma_j\) and \(p_k\) are as in Eq.219, \(\up_j\) is the output’s producer price, i.e. its dual shadow price, \(s_k\) is as in Eq.214 and \(d_j\) as in Eq.217.
- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.
See also
Important
This method overrides its (parent)
output_price_computercounterpart.- Example
>>> ovol = 20973.128 >>> ivols = np.array([[1782.232, 19190.896]]) >>> iprcs = np.array([[1000., 1000.]]) >>> ivals = iprcs*ivols
>>> h = HicksianCES(sigma=2.) >>> _ = h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... ) >>> h.output_price_computer( ... output_volume = ovol, ... input_prices = iprcs, ... ).item() 1000.0
With \(\nu_j=2\), the same calibrated input technology produces \(q_j=\mathtt{ovol}^2\); its output price now internalizes the resulting returns to scale:
>>> hν = HicksianCES(sigma=2., nu=2.).compute_calibrand_0( ... output_volume = ovol**2, ... input_volumes = ivols, ... input_values = ivals, ... ) >>> hν.output_price_computer( ... output_volume = ovol**2, ... input_prices = iprcs, ... ) array([[0.02]])
Let’s illustrate how such calculation can be vectorized over the 0th axis.
>>> vovol = np.array([[[ovol]], [[.5*ovol]], [[ovol]]]) >>> vivols = np.stack((ivols, .5*ivols, ivols)) >>> vivals = 1e3*vivols >>> viprcs = 1e3*np.ones_like(vivols)
>>> _ = h.compute_calibrand_0( ... output_volume = vovol, ... input_volumes = vivols, ... input_values = vivals, ... ) >>> h.output_price_computer( ... output_volume = vovol, ... input_prices = viprcs, ... ) array([[[1000.]], [[1000.]], [[1000.]]])
-
input_volumes_computer(self, *, output_volume: float, input_prices: np.ndarray)¶ Input demands, \(1 \times |\mcI_j|\), denoted as
(219)¶\[\begin{split}q_k &= q_j^{1/\nu_j} \left[ \alpha_k \left(\frac{\up_j}{p_k}\right)^{\sigma_j} \right]^{\text{I}(\sigma_j \neq \infty)} \left[s_k\right]^{\text{I}(\sigma_j = \infty)} \\ &= q_j^{1/\nu_j} \left[ \alpha_k p_k^{-\sigma_j} \left( \sum_{k' \in \mcI_j} \alpha_{k'} p_{k'}^{1 - \sigma_j} \right)^{ \frac{\sigma_j}{1 - \sigma_j} } \right]^{\text{I}(\sigma_j \neq \infty)} \left[s_k\right]^{\text{I}(\sigma_j = \infty)}, \ \forall k \ \in \mcI_j\end{split}\]where \(\alpha_k=a_k^{(-1)^{\text{I}(\sigma_j = 0)} \sigma_j^{\text{I}(\sigma_j \neq 0)}}\) and \(\mcI_j\), \(q_j\), \(q_k\), \(a_k\), \(\nu_j\) and \(\text{I}(\cdot)\) are as in Eq.212, \(p_k\) is the \(q_k\)’s price and \(s_k\) is as described in Eq.214.
- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.
- Example
>>> ovol = 20973.128 >>> ivols = np.array([[1782.232, 19190.896]]) >>> iprcs = np.array([[1000., 1000.]]) >>> ivals = iprcs*ivols
>>> h = HicksianCES(sigma=2) >>> _ = h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... ) >>> h.input_volumes_computer( ... output_volume = ovol, ... input_prices = iprcs, ... ) array([[ 1782.23, 19190.9 ]])
The same optimal input levels are recovered at \(\nu_j=2\) when the corresponding output target is squared:
>>> hν = HicksianCES(sigma=2., nu=2.) >>> _ = hν.compute_calibrand_0( ... output_volume = ovol**2, ... input_volumes = ivols, ... input_values = ivals, ... ) >>> hν.input_volumes_computer( ... output_volume = ovol**2, ... input_prices = iprcs, ... ) array([[ 1782.23, 19190.9 ]])
Let’s illustrate how such calculation can be vectorized over the 0th axis.
>>> h = HicksianCES(sigma=[[[2.]], [[2.]], [[.5]]]) >>> vovol = np.array([[[ovol]], [[ovol]], [[ovol]]]) >>> vivols = np.stack((ivols, ivols[:, ::-1], ivols)) >>> vivals = 1e3*vivols >>> viprcs = 1e3*np.ones((3, 1, 2))
>>> h.compute_calibrand_0( ... output_volume = vovol, ... input_volumes = vivols, ... input_values = vivals, ... ).input_volumes_computer( ... output_volume = vovol, ... input_prices = viprcs, ... ) array([[[ 1782.23, 19190.9 ]], [[19190.9 , 1782.23]], [[ 1782.23, 19190.9 ]]])
Once again, but moving away from the calibration context regarding relative prices.
>>> viprcs[..., 0] *= .5 >>> h.input_volumes_computer( ... output_volume = vovol, ... input_prices = viprcs, ... ) array([[[ 6055.96, 16302.5 ]], [[20931.83, 485.98]], [[ 2457.72, 18713.25]]])
-
-
class
iamax.library.HicksianICES(*args, **kwargs)¶ 
Ordinal-production altered version of
HicksianCES.Important
At the moment, this method cannot be instantiated at \(\sigma \to \infty\) since it would require
MSystemto be endowed with a new economic attribute k.a. iwq_intensities.-
compute_calibrand_0(self, *, ordinal_volume: float, input_volumes: np.ndarray, input_values: np.ndarray)¶ s/e.
See also
LSP-offending (in-place) computer.
See also
The reason why this method is nullified.
- Example
>>> HicksianICES.allege_input_shares() Traceback (most recent call last): ... NotImplementedError: Require `core.MSystem.iwq_intensities`
-
ordinal_volume_computer(self, *, input_volumes: np.ndarray)¶ s/e.
See also
-
input_volumes_computer(self, *, ordinal_volume: float, input_prices: np.ndarray)¶ s/e.
-
-
class
iamax.library.HicksianPICES(*args, scaling_factor: float = 1.0, **kwargs)¶ 
Augmented version of
HicksianICESthat also computes the price of the ordinal quantities being generated.- Parameters
scaling_factor (float) – Ordinal price scaling factor. To
1by default.
-
compute_ordinal_price_driver(self, *, ordinal_price_drate: np.ndarray)¶ s/e.
-
ordinal_price_computer(self, *, input_prices: np.ndarray)¶ s/e.
-
class
iamax.library.ScHicksianCES¶ 
HicksianCES’s altered version whose calibrands determination is solver-based.Candidate distribution parameters are directly served by the solving system and rooted against both their CES normalization condition and their ability to reproduce observed input volumes through the inherited Hicksian demand system.
-
compute_calibrand_0(self, *, ioq_intensities_drates: np.ndarray)¶ Attach solver-served candidate distribution parameters. The supplied
ioq_intensities_dratesare directly attached as both baseline and currently applicable calibrands, their consistency being subsequently assessed byioq_intensities_drates_crooter().- Parameters
ioq_intensities_drates (numpy.ndarray) – \((\balpha^{\text{drate}}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
ioq_intensities_drates.- Example
>>> ScHicksianCES(sigma=2.).compute_calibrand_0( ... ioq_intensities_drates=np.array([[.36, .64]]) ... ).calibrand_0 array([[0.36, 0.64]])
See also
-
ioq_intensities_drates_crooter(self, *, input_volumes: np.ndarray, input_prices: np.ndarray)¶ Root solver-served distribution parameters against their CES normalization and Hicksian input-volume reproduction conditions.
Let \(a_{k,j}\) denote the candidate distribution parameter associated with input \(k\) of aggregate \(j\). The first component requires
(220)¶\[\sum_{k \in \mcI_j} a_{k,j}^{\sigma_j} = 1,\]where \(\sigma_j\) denotes aggregate \(j\)’s elasticity of substitution and \(\mcI_j\) its input index set.
The observed input volumes are additionally passed through the inherited CES aggregation and Hicksian demand mappings. Let \(q_j\) denote the aggregate volume elicited from observed input volumes \((q_{k,j})_{k \in \mcI_j}\), and let \(q^H_{k,j}\) denote the corresponding Hicksian demand evaluated at observed input prices \((p_{k,j})_{k \in \mcI_j}\). Calibration additionally requires
(221)¶\[q^H_{k,j} = q_{k,j}, \ \forall k \in \mcI_j.\]The returned criterion is null iff both the CES normalization and exact reproduction of observed input volumes by the corresponding Hicksian demand system hold.
- Parameters
input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.
Note
This method is vectorization friendly over the
-3th axis, if any.- Example
In the one-input case, a unit calibrand satisfies the CES normalization condition. The aggregate reconstructed from the observed input volume is consequently reproduced by its Hicksian demand.
>>> h = ScHicksianCES(sigma=2.).compute_calibrand_0( ... ioq_intensities_drates=np.array([[1.]]) ... ) >>> h.ioq_intensities_drates_crooter( ... input_volumes=np.array([[3.]]), ... input_prices=np.array([[2.]]), ... ) array([[9.06e-16]])
-
-
class
iamax.library.SmHicksianCES¶ 
HicksianCES’s altered version whose calibrands determination is softmax-based.Unlike
compute_calibrand_0(), the present calibration does not require an observed aggregate output volume. Distribution parameters are instead recovered from input prices and volumes through their substitution-elasticity-adjusted expenditure weights.-
compute_calibrand_0(self, *, input_prices: np.ndarray, input_volumes: np.ndarray)¶ This method supports the softmax-derived calibration of \((a_{k,j})_{k \in \mcI_j}\), the \(|\mcI_j|\) demand distribution parameters related to aggregate \(j\),
(222)¶\[a_k = \left[ \frac{p_{k}q_{k}^{1/\sigma_j}}{ \sum_{k' \in \mcI_j} p_{k'}q_{k'}^{1/\sigma_j} } \right]^{\text{I}(\sigma_j \neq \infty)}, \ \forall k \ \in \mcI_j\]with \(\sigma_j\) the elasticity of substitution, \(\mcI_j\) the index set of inputs required by \(q_j\)’s underlying technology, \(q_k\) the optimal level of input required to meet \(q_j\), \(p_k\) the \(q_k\)’s associated input price and \(\text{I}(\cdot)\) an indicator function returning the trueness of the statement being passed as argument.
For finite \(\sigma_j\), the expression consists in the normalization of
\[p_k q_k^{1/\sigma_j}\]over \(\mcI_j\), equivalently corresponding to a softmax over \(\log p_k + \sigma_j^{-1}\log q_k\) whenever these logarithms are defined. For \(\sigma_j \to \infty\), the perfect-substitutes limit is handled consistently with
HicksianCESby neutralizing the normalized term through \(\text{I}(\sigma_j \neq \infty)\).- Parameters
input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.
Note
This method is vectorization friendly over the
-3th axis, if any.- Example
Let’s consider two inputs whose respective prices and volumes are
>>> iprcs = np.array([[2., 1.]]) >>> ivols = np.array([[4., 9.]])
With an elasticity of substitution equal to \(2\), the unnormalized softmax terms amount respectively to \(2\sqrt{4}=4\) and \(\sqrt{9}=3\).
>>> h = SmHicksianCES(sigma=2.) >>> h.compute_calibrand_0( ... input_prices=iprcs, input_volumes=ivols ... ).calibrand_0 array([[0.57, 0.43]])
The Cobb-Douglas case directly reduces the softmax terms to input values.
>>> SmHicksianCES(sigma=1.).compute_calibrand_0( ... input_prices=iprcs, input_volumes=ivols ... ).calibrand_0 array([[0.47, 0.53]])
Finally, the perfect-substitutes limit neutralizes the normalized term.
>>> SmHicksianCES(sigma=np.inf).compute_calibrand_0( ... input_prices=iprcs, input_volumes=ivols ... ).calibrand_0 array([[1., 1.]])
See also
-
-
class
iamax.library.HicksianFCES¶ 
HicksianCES’s fixed-calibration variant whose underlying input trade-off is externally forced.Contrary to
HicksianCES, candidate input volumes are not endogenously computed from the CES demand system. Instead, the \(|\mcI_j|\) inputs are partitioned into a set of externally forced inputs and a freely traded-off set containing a single input,(223)¶\[\mcI_j = \mcI_j^{\mathrm{forced}}\mathbin{\dot\cup}\mcI_j^{\mathrm{free}}, \ |\mcI_j^{\mathrm{free}}|=1.\]Hence, the forcing structure distinguishes two sets of inputs but does not restrict the CES itself to two inputs: \(|\mcI_j|\) may be arbitrary. Given the externally determined candidate input bundle, consistency with the fixed CES calibration is imposed through
aggregated_input_volumes_rooter().The class itself remains agnostic as to which elements of the supplied input-volume vector are forced and which one is freely traded off; this distinction is determined by the surrounding model.
LSP-offending (in-place) computer.
-
aggregated_input_volumes_rooter(self, *, output_volume: np.ndarray, input_volumes: np.ndarray)¶ Residual associated with the forced input-volume constraint, \(1 \times 1\) assumed unit-dimensionless.
Denoting by \(q_j\) the output volume to be satisfied and by \((q_k)_{k \in \mcI_j}\) the candidate input-volume vector, the finite non-Cobb-Douglas CES case implies
(224)¶\[\widehat q_j = \left( \sum_{k \in \mcI_j}a_k q_k^{\rho_j} \right)^{1/\rho_j}, \ \rho_j=\frac{\sigma_j-1}{\sigma_j},\]where \(a_k\) denotes the \(k\)th fixed CES distribution parameter. The root condition is
(225)¶\[r\left(\widehat q_j,q_j\right) \approx 0,\]where \(r\) is
_rdistance(). Thus, the candidate bundle is admissible when the output it implies under the fixed CES calibration coincides with the required output volume.The method does not distinguish between \(\mcI_j^{\mathrm{forced}}\) and \(\mcI_j^{\mathrm{free}}\): it only evaluates the complete candidate input bundle supplied by the caller.
- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.
- Example
Consider a three-input CES with \(\sigma=.5\), hence
\[\rho=\frac{\sigma-1}{\sigma}=-1.\]At calibration, let all three input volumes and the output volume equal one, while input values are respectively \(2\), \(1\) and \(1\). The resulting distribution parameters are therefore \(a_1=.5\) and \(a_2=a_3=.25\).
>>> h = HicksianFCES(sigma=.5).compute_calibrand_0( ... output_volume=np.array([[1.]]), ... input_volumes=np.ones((1, 3)), ... input_values=np.array([[2., 1., 1.]]), ... ) >>> h.calibrand_0_star array([[0.5 , 0.25, 0.25]])
Suppose now that the second and third inputs are externally forced to \(q_2=2\) and \(q_3=4\), respectively, while the first input remains freely traded off. Requiring \(q_j=1\) gives
\[1 = \left(.5q_1^{-1} +.25(2)^{-1} +.25(4)^{-1}\right)^{-1},\]and hence
\[q_1 = \frac{.5}{1-.25/2-.25/4} = \frac{8}{13}.\]>>> q1 = 8. / 13. >>> h.aggregated_input_volumes_rooter( ... output_volume=np.array([[1.]]), ... input_volumes=np.array([[q1, 2., 4.]]), ... ) array([[0.]])
Thus, although two inputs are externally forced in this example, the single freely traded-off input suffices to satisfy the scalar CES output constraint. Nothing in the rooter restricts the total number of inputs to two.
See also
-
class
iamax.library.HicksianUFCES¶ 
Unimodular extension of
HicksianFCES.Unlike
HicksianFCES, which evaluates the CES aggregation constraint over real input volumes only,HicksianUFCESadmits a complex extension of each scalar input volume through the unimodular rotation\[q^\angle_{k,j} = q_{k,j}\left( \cos\angle q^\angle_{k,j} + \mathrm{i}\sin\angle q^\angle_{k,j} \right) = q_{k,j}\exp\left( \mathrm{i}\angle q^\angle_{k,j} \right).\]The extension is unimodular because
\[\left|q^\angle_{k,j}\right| = \left|q_{k,j}\right|.\]Economic input volumes therefore remain real magnitudes. The angles provide auxiliary dimensions used only when evaluating the continued CES aggregation constraint and the associated real-domain selection residual.
Denoting the continued CES residual by
\[r_\theta = r\left( q_j, F_j\left((q^\angle_{k,j})_{k\in\mcI_j}\right) \right),\]aggregated_input_volumes_rooter()exposes \(r_\theta\) directly.The sole purpose of the second residual exposed by
output_volume_rooter()is different: it selects the canonical zero-angle representation whenever the corresponding FCES equation admits a strictly positive real solution, while releasing the angle whenever such a solution is analytically impossible.Importantly, this decision is made independently for every candidate input and from the CES structure itself. No input, sector or block is designated ex ante as requiring complex continuation.
For finite \(\rho_j\neq0\), counterfactually let input \(k\) be the singleton free input and hold every other input fixed. Writing
\[x_{\ell,j} = \frac{q_{\ell,j}}{s_{\ell,j}},\]where \(s_{\ell,j}\) denotes the corresponding input-volume shock, the real CES constraint is
\[q_j^{\rho_j} = a_{k,j}x_{k,j}^{\rho_j} + \sum_{\ell\neq k}a_{\ell,j}x_{\ell,j}^{\rho_j}.\]For \(a_{k,j}>0\), a strictly positive real \(x_{k,j}\) exists if and only if
\[\sum_{\ell\neq k}a_{\ell,j} \left(\frac{x_{\ell,j}}{q_j}\right)^{\rho_j} < 1.\]The condition is evaluated in logarithmic form. Define
\[\lambda_{\ell,j} = \log a_{\ell,j} + \rho_j\left(\log x_{\ell,j}-\log q_j\right),\]and the leave-one-out log-sum-exp
\[\Lambda_{k,j} = \log\left( \sum_{\ell\neq k}\exp\lambda_{\ell,j} \right).\]The logarithmic real-feasibility slack is then
\[\delta_{k,j} = -\Lambda_{k,j}.\]Hence, exactly,
\[\delta_{k,j}>0 \iff \exists\,x_{k,j}>0: F_j\left((x_{\ell,j})_{\ell\in\mcI_j}\right) = q_j.\]This log-domain formulation avoids explicitly forming potentially overflowing terms such as \((x_{\ell,j}/q_j)^{\rho_j}\).
The leave-one-out log-sum-exp is evaluated in linear time and memory. In particular, the implementation does not form an \(|\mcI_j|\times|\mcI_j|\) exclusion matrix. A global maximum and, only where needed, a second maximum are used to retain numerical accuracy when one contribution dominates the complete sum.
Two CES limiting cases require their own exact feasibility condition.
At the Cobb-Douglas limit, \(\rho_j=0\),
\[q_j = \prod_{\ell\in\mcI_j}x_{\ell,j}^{a_{\ell,j}}.\]For \(a_{k,j}>0\), a positive real free input exists for every positive finite target if and only if every active forced input is strictly positive and finite.
At the smooth Leontief limit implemented by
CES,\[q_j = \frac{1}{n_j} \sum_{\ell\in\mcI_j}a_{\ell,j}x_{\ell,j},\]where \(n_j\) is the number of nonzero distribution parameters. The corresponding feasibility condition is
\[\frac{1}{n_j q_j} \sum_{\ell\neq k}a_{\ell,j}x_{\ell,j} < 1,\]which is evaluated through the same leave-one-out log-sum-exp machinery.
The feasibility slack is used by
compute_qois()to form the exact real-feasibility active set\[\begin{split}I_{k,j} = \begin{cases} 1, & \delta_{k,j}>0,\\ 0, & \delta_{k,j}\leq0, \end{cases}\end{split}\]whenever the corresponding test is certifiable. Uncertifiable candidates are conservatively assigned \(I_{k,j}=1\).
The angle supplied to the CES aggregation is then
\[\widetilde{\angle q}^\angle_{k,j} = (1-I_{k,j})\angle q^\angle_{k,j}.\]Hence a real-feasible candidate is evaluated on the real branch, whereas a real-infeasible candidate retains its full continuation angle.
The raw angular residual is
\[\widetilde r_{\angle,j} = \sum_{k\in\mcI_j}I_{k,j}\angle q^\angle_{k,j}.\]Under the class contract that at most one input-volume angle is free to differ from zero, this has the desired exact interpretation.
If the free input is real-feasible,
\[\delta_{k,j}>0 \Longrightarrow I_{k,j}=1,\]and therefore
\[\widetilde r_{\angle,j}=0 \Longrightarrow \angle q^\angle_{k,j}=0.\]If the free input is real-infeasible,
\[\delta_{k,j}\leq0 \Longrightarrow I_{k,j}=0,\]so that the angular residual vanishes independently of the angle and the continued CES residual is free to determine the required complex rotation.
The exposed angular residual is normalized by \(2\pi\) and by the square root of the number of vectorized angular residuals. This changes neither its zero set nor the active-set selection.
Unlike a periodic chordal penalty, the residual uses the unwrapped angle itself. Hence \(2\pi\), \(-2\pi\), and other equivalent rotations are not treated as alternative representations of the real branch: the unique canonical real representative is
\[\angle q^\angle_{k,j} = 0.\]This distinction is material when solver variables are unbounded in angle space.
Candidates whose real feasibility cannot safely be certified are handled conservatively. In particular, a zero distribution parameter, a negative or undefined forced economic quantity, an invalid target, or an invalid CES parameter does not release the corresponding angle. The candidate is instead retained on the real branch.
_positive_feasibility_gate()additionally provides the continuous, semismooth mapping\[\begin{split}g(\delta) = \begin{cases} 1-\exp(-\delta), & \delta>0,\\ 0, & \delta\leq0, \end{cases}\end{split}\]for callers that require a positive feasibility weight. The current
compute_qois()does not use this mapping: it deliberately uses the exact Boolean active-set classification above.Warning
The exact active-set selection introduces a regime change at \(\delta_{k,j}=0\). It is therefore not globally differentiable across the real-feasibility boundary. Within either selected regime, the residual mapping retains the ordinary derivatives of the corresponding real or continued CES branch.
Warning
The term continuation does not imply that the complete complex CES mapping is globally smooth or analytic as a function of the input-volume angles.
Non-integer complex powers possess branch cuts. Consequently, \(r_\theta\) is smooth only inside connected regions in which the relevant complex powers remain on the same branch and away from singular cases handled specially by the underlying power operator.
In particular, rotations through the negative real axis require care for non-integer CES exponents. The numerical example below uses \(\rho=-1\), so its relevant powers are integer.
Note
The angular residual assumes that at most one scalar input-volume angle per FCES block is free to differ from zero. This assumption must be enforced by the surrounding model.
The feasibility calculation nevertheless treats every input counterfactually as the potential free input. Hence it does not require the identity of that free input, or the identity of any real-infeasible block, to be known ex ante.
-
static
_leave_one_out_logsumexp(x: np.ndarray)¶ Compute stable leave-one-out log-sum-exp values.
For every last-axis element \(x_k\), return
\[\log\left(\sum_{\ell\neq k}\exp x_\ell\right).\]The calculation is linear in the last-axis size. A global stabilized reduction handles every exclusion except a unique maximum, for which a second maximum avoids cancellation. Positive infinities are handled analytically, an empty sum gives
-np.inf, and anyNaNis propagated across its last-axis slice.- Parameters
x (numpy.ndarray) – Array to be leave-one-out processed.
- Example
An ordinary row returns the log-sum-exp of all other entries,
>>> x = np.array([[.0, 1., 2.]]) >>> HicksianUFCES._leave_one_out_logsumexp(x) array([[2.31, 2.13, 1.31]])
while a unique dominant maximum remains numerically stable:
>>> x = np.array([[1000., .0, -1000.]]) >>> HicksianUFCES._leave_one_out_logsumexp(x) array([[ 0., 1000., 1000.]])
Positive infinities are treated exactly,
>>> x = np.array([[np.inf, .0, 1.]]) >>> HicksianUFCES._leave_one_out_logsumexp(x) array([[1.31, inf, inf]]) >>> x = np.array([[np.inf, np.inf, 1.]]) >>> HicksianUFCES._leave_one_out_logsumexp(x) array([[inf, inf, inf]])
and the empty-sum and undefined cases remain explicit:
>>> HicksianUFCES._leave_one_out_logsumexp(np.array([[5.]])) array([[-inf]]) >>> x = np.array([[np.nan, .0, 1.]]) >>> HicksianUFCES._leave_one_out_logsumexp(x) array([[nan, nan, nan]])
-
_real_feasibility_logslacks_computer(self, *, output_volume: np.ndarray, input_volumes: np.ndarray)¶ Compute counterfactual positive-real feasibility log-slacks.
Treat every last-axis input in turn as the singleton free input. Let
\[x_{k,j} = \frac{q_{k,j}}{s_{k,j}}.\]For finite \(\rho_j\neq0\), the corresponding slack is
\[\delta_{k,j} = -\log\left[ \sum_{\ell\neq k}a_{\ell,j}\left( \frac{x_{\ell,j}}{q_j^{1/\nu_j}} \right)^{\rho_j} \right].\]For \(a_{k,j}>0\), \(\delta_{k,j}>0\) is necessary and sufficient for a strictly positive real free input. Cobb-Douglas feasibility is represented by
+/-np.inf; smooth-Leontief uses the corresponding normalized leave-one-out sum.At \(\nu_j=+\infty\), under the limiting CES interpretation, a strictly positive finite target is attainable only for \(q_j=1\).
The second returned array identifies certifiable slacks. Values produced for uncertifiable candidates are numerical placeholders.
- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.
- Example
Consider
\[q_j = \left( \frac{1}{2}q_{1,j}^{-1} + \frac{1}{4}q_{2,j}^{-1} + \frac{1}{4}q_{3,j}^{-1} \right)^{-1},\]calibrated at unit volumes and \(q_j=1\):
>>> invariants = dict( ... output_volume=np.array([[1.]]), ... input_volumes=np.ones((1, 3)), ... input_values=np.array([[2., 1., 1.]]) ... ) >>> h = HicksianUFCES(sigma=.5).compute_calibrand_0( ... **invariants ... )
With
[2., 1., 1.], every singleton-free-input problem is real-feasible and certifiable:>>> d, cert = h._real_feasibility_logslacks_computer( ... output_volume=np.array([[1.]]), ... input_volumes=np.array([[2., 1., 1.]]) ... ) >>> d array([[0.69, 0.69, 0.69]]) >>> cert array([[ True, True, True]])
With
[2., .4, .4], the first candidate is real-infeasible because its forced contribution is \(1.25>1\):>>> d, cert = h._real_feasibility_logslacks_computer( ... output_volume=np.array([[1.]]), ... input_volumes=np.array([[2., .4, .4]]) ... ) >>> d array([[-0.22, 0.13, 0.13]]) >>> cert array([[ True, True, True]])
The homogeneity degree enters through \(q_j^{1/\nu_j}\). Hence, with \(\nu_j=2\), target
4.is reduced to the pre-homogeneity target \(4^{1/2}=2\):>>> hν = HicksianUFCES( ... sigma=.5, nu=2. ... ).compute_calibrand_0(**invariants) >>> d, cert = hν._real_feasibility_logslacks_computer( ... output_volume=np.array([[4.]]), ... input_volumes=np.array([[4., 2., 2.]]) ... ) >>> d array([[0.69, 0.69, 0.69]]) >>> cert array([[ True, True, True]])
Finally, an invalid value may occupy the hypothetical free position, but prevents certification whenever it is forced:
>>> d, cert = h._real_feasibility_logslacks_computer( ... output_volume=np.array([[1.]]), ... input_volumes=np.array([[np.nan, 1., 1.]]) ... ) >>> cert array([[ True, False, False]])
-
aggregated_input_volumes_rooter(self)¶ Return the unimodular CES aggregation residual.
See also
-
output_volume_rooter(self)¶ Return the positive-real-feasibility angular residual.
The residual anchors the free angle to zero whenever a positive real FCES solution is analytically available and releases it when such a solution is analytically impossible.
No particular input or FCES block is designated ex ante as real-infeasible.
-
compute_qois(self, *, output_volume: np.ndarray, input_volumes: np.ndarray, input_volumes_angles: np.ndarray | float = 0.0)¶ Compute the continued CES and real-selection residuals.
Economic input volumes remain real. Their auxiliary angles define the unimodular extension
\[q^\angle_{k,j} = q_{k,j}\left( \cos\angle q^\angle_{k,j} + \mathrm{i}\sin\angle q^\angle_{k,j} \right).\]Complex continuation is made available only when the corresponding positive-real FCES problem is analytically infeasible.
Every input is counterfactually treated as the singleton free input and its positive-real feasibility is determined by
_real_feasibility_logslacks_computer().Let \(\delta_{k,j}\) denote the resulting logarithmic feasibility slack and define the active-set indicator
\[\begin{split}I_{k,j} = \begin{cases} 1, & \delta_{k,j}>0,\\ 0, & \delta_{k,j}\leq0. \end{cases}\end{split}\]whenever the feasibility calculation is certifiable. Uncertifiable candidates are conservatively assigned \(I_{k,j}=1\).
The angle actually supplied to the CES evaluation is
\[\widetilde{\angle q}^\angle_{k,j} = (1-I_{k,j})\angle q^\angle_{k,j}.\]Hence real-feasible candidates are projected onto the real manifold before aggregation,
\[I_{k,j}=1 \ \Longrightarrow\ \widetilde{\angle q}^\angle_{k,j}=0,\]while real-infeasible candidates retain their full continuation angle,
\[I_{k,j}=0 \ \Longrightarrow\ \widetilde{\angle q}^\angle_{k,j} = \angle q^\angle_{k,j}.\]Conversely, only angles belonging to the real-feasible active set enter the angular residual. Before normalization, this residual is
\[\widetilde r_{\angle,j} = \sum_{k\in\mcI_j} I_{k,j}\angle q^\angle_{k,j}.\]Under the class contract that at most one scalar input-volume angle per FCES block is free to differ from zero, a real-feasible free input therefore satisfies
\[\widetilde r_{\angle,j}=0 \iff \angle q^\angle_{k,j}=0,\]whereas a real-infeasible free input is entirely released from the angular equation.
To prevent the angular residual family from dominating the global quadratic objective merely because angles are expressed in radians and several FCES blocks are vectorized simultaneously, the exposed residual is normalized as
\[r_{\angle,j} = \frac{\widetilde r_{\angle,j}}{ 2\pi\sqrt{N_{\angle}} },\]where \(N_{\angle}\) is the number of vectorized angular residuals produced by the present call.
The factor \(2\pi\) expresses angular displacement in full-turn units. The factor \(\sqrt{N_{\angle}}\) RMS-normalizes the corresponding quadratic residual family, so its total contribution to a sum-of-squares objective does not mechanically grow with the number of vectorized FCES blocks.
This scaling changes neither the zero set nor the real/complex active-set selection. In particular,
\[r_{\angle,j}=0 \iff \widetilde r_{\angle,j}=0.\]The active-set selection deliberately introduces a regime change at \(\delta_{k,j}=0\). Within each selected regime, however, the residual mapping retains the ordinary derivatives of the corresponding real or continued CES branch.
The unwrapped angle is used directly. Consequently, \(2\pi\), \(-2\pi\), and other equivalent rotations are not alternative zeros of the real-selection residual: \(0\) is the unique canonical representation of the real branch.
input_volumes_anglesmay be scalar or array-valued. NumPy/JAX broadcasting in the active-set selections and rotations makes the default scalar value.0follow the same computational path as a broadcast-compatible angle array.- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.input_volumes_angles (numpy.ndarray or float) – \((\angle\bQ^{\angle}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
input_volumes_angles. To.0by default.
- Example
Consider
\[q_j = \left( \frac{1}{2}q_{1,j}^{-1} + \frac{1}{4}q_{2,j}^{-1} + \frac{1}{4}q_{3,j}^{-1} \right)^{-1},\]with target \(q_j=1\) and \(q_{1,j}\) free. If \(q_{2,j}=q_{3,j}=1\), then
\[\delta_{1,j}=-\log\left(\frac14+\frac14\right)=\log2>0,\]so the positive-real branch exists and the free angle is forced to zero. If instead \(q_{2,j}=q_{3,j}=0.4\),
\[\delta_{1,j}=-\log(1.25)<0,\]and no positive-real \(q_{1,j}\) can satisfy the constraint. Indeed, the ordinary FCES equation would require
\[1 = \frac{1}{2q_{1,j}} + 1.25 \quad\Longrightarrow\quad q_{1,j}=-2.\]This is the point of the unimodular continuation. An
HicksianFCEScannot keep the economic volume equal to+2.and simultaneously use the algebraic value-2.:>>> invariants = dict( ... output_volume=np.array([[1.]]), ... input_volumes=np.ones((1, 3)), ... input_values=np.array([[2., 1., 1.]]) ... ) >>> f = HicksianFCES(sigma=.5).compute_calibrand_0(**invariants) >>> f._output_volume_computer( ... input_volumes=np.array([[2., .4, .4]]) ... ) array([[0.67]]) >>> f._output_volume_computer( ... input_volumes=np.array([[-2., .4, .4]]) ... ) array([[0.8]])
HicksianUFCESinstead keeps the positive magnitude2.and represents the missing sign through a rotation by \(\pi\):>>> h = HicksianUFCES(sigma=.5).compute_calibrand_0(**invariants) >>> q = np.array([[2., .4, .4]]) >>> h.compute_qois( ... output_volume=np.array([[1.]]), ... input_volumes=q, ... input_volumes_angles=np.array([[np.pi, .0, .0]]) ... ).output_volume_rooter() array([[0.]]) >>> h.aggregated_input_volumes_rooter() array([[0.-2.16e-17j]])
The same supplied angle is ignored whenever the real branch is feasible. With unit forced volumes the first candidate has \(\delta_{1,j}>0\), so its effective angle is projected to zero and the angular residual remains nonzero:
>>> h.compute_qois( ... output_volume=np.array([[1.]]), ... input_volumes=np.ones((1, 3)), ... input_volumes_angles=np.array([[np.pi/2., .0, .0]]) ... ).output_volume_rooter() array([[0.25]])
-
static
-
class
iamax.library.HicksianACES¶ 
HicksianCES’s altered version whose costs calculation is based on accounting rules.
-
class
iamax.library.HicksianAFCES¶ 
HicksianACES’s altered version whose underlying trade-off is forced.
-
class
iamax.library.HicksianAUFCES¶ 
HicksianACES’s altered version whose underlying unimodularly rotating trade-off is forced.
-
class
iamax.library.HicksianGAFCES(*args, negated_mask: bool = False, **kwargs)¶ 
HicksianACES’s altered version whose underlying trade-off is forced in a generalized manner by restricting it to a consumption subset of arbitrary size.Inputs are partitioned between those remaining freely subject to the inherited trade-off and those whose consumption is forced onto its externally supplied level.
- Parameters
negated_mask (bool) – Whether the coding passed as argument
input_volumes_drates2of methodcompute_calibrand_0()is to be negated. When set toFalse, values1and0respectively designate freely traded-off and forced inputs. When set toTrue, the equivalent coding is reversed. Set toFalseby default.
Note
Denoting as \(\mathcal{F}_j\) and \(\mathcal{C}_j\) the freely traded-off and forced input sets, respectively, generalized forcing operates through the inherited CES representation in two complementary ways.
For finite
sigma, the base calibrands of inputs in \(\mathcal{F}_j\) retain their initial calibration while those in \(\mathcal{C}_j\) are recalibrated from their current observed consumptions.At
sigma=np.inf, inherited input demand instead relies onalleged_input_shares. Current forced IOQ shares are then imposed directly while freely traded-off inputs preserve the relative allocation returned by the inherited price-responsive mechanism and absorb the remaining share mass.Attention
This class is intended to remain valid for arbitrary
sigmavalues, although finite nonzerosigmacases remain comparatively less tested.-
compute_calibrand_0(self, *, output_volume: float, input_values: np.ndarray, input_volumes: np.ndarray, input_volumes_drates2: np.ndarray)¶ Altered version of
compute_calibrand_0()that initializes the generalized forcing configuration.Denoting as \(d_k\) the \(k\)th component of
input_volumes_drates2and as \(m_k\) its internally harmonized configuration indicator,(226)¶\[\begin{split}m_k = \begin{cases} 1-d_k, & \text{if mask is negated}, \\ d_k, & \text{otherwise}, \end{cases}\end{split}\]\(m_k=1\) designates an input remaining freely subject to trade-off, while every other admissible value designates an input whose consumption is forced.
The inherited CES calibration itself is initially performed ordinarily over the complete input set. The forcing mask stored by this method subsequently determines which base calibrands may be recalibrated by
compute_calibrand_0_star()and which retain their initial value.- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.input_volumes_drates2 (numpy.ndarray) – \((\bQ^{\text{drate}^{ii}}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes_drates2’s slice. Values1and0respectively designate freely traded-off and forced inputs whennegated_mask=False; the equivalent coding is reversed whennegated_mask=True. Extended configurations supplied according toHicksianGPAFCES’s convention are also admissible, in which case both forced states collapse onto the single forced configuration represented here.
- Example
>>> ovol = 20973.128 >>> ivols = np.array([[1782.232, 19190.896]]) >>> ivals = 1e3*ivols >>> imsks = np.array([[1, 0]])
>>> h = HicksianGAFCES(sigma=0, negated_mask=False) >>> _ = h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... input_volumes_drates2 = imsks, ... ) >>> h.calibrand_0 array([[11.77, 1.09]]) >>> h._traded_off array([[ True, False]])
See also
-
compute_calibrand_0_star(self, *, output_volume: float, input_values: np.ndarray, input_volumes: np.ndarray, ioq_shares_drates: np.ndarray = 0.0, ioq_shares_drates2: np.ndarray = 0.0, ioq_productivities_drates: np.ndarray = 0.0, ioq_productivities_drates2: np.ndarray = 0.0)¶ Augmented version of
compute_calibrand_0_star()that integrates generalized consumption forcing.Before the inherited star transformation, the operative base calibration is updated according to
(227)¶\[\begin{split}a_{k,t} = \begin{cases} a_{k,0}, & k \in \mathcal{F}_j, \\ \widehat a_{k,t}, & k \in \mathcal{C}_j, \end{cases}\end{split}\]where \(a_{k,0}\) is the initial calibrand retained by a freely traded-off input and \(\widehat a_{k,t}\) is the ordinary inherited calibration implied by the current observed consumption of a forced input.
The resulting mixed base calibration is then passed unchanged to
compute_calibrand_0_star(), which applies the ordinary share and productivity transformations.- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.ioq_shares_drates (numpy.ndarray) – \((\bbeta^\text{drate}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_shares_drates’s slice. Set to.0by default.ioq_shares_drates2 (numpy.ndarray) – \((\bbeta^{\text{drate}^{ii}}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_shares_drates2’s slice. Set to.0by default.ioq_productivities_drates (numpy.ndarray) – \((\balpha^{-1,\ \text{drate}_{k,j}})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_productivities_drates’s slice. Set to.0by default.ioq_productivities_drates2 (numpy.ndarray) – \((\balpha^{-1,\ \text{drate}^{ii}_{k,j}})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_productivities_drates2’s slice. Set to.0by default.
- Example
>>> ovol = 20973.128 >>> ivols = np.array([[1782.232, 19190.896]]) >>> iprcs = np.array([[1000., 1000.]]) >>> ivals = iprcs*ivols >>> imsks = np.array([[0, 1]]) >>> h = HicksianGAFCES(sigma=.0, negated_mask=False) >>> h.aggregation_type 'Leontief'
>>> h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, # † ... input_volumes_drates2 = imsks, ... ).calibrand_0 array([[11.77, 1.09]]) >>> ivôls = h.input_volumes_computer( ... output_volume = ovol, ... input_prices = iprcs, # † ... ) >>> ivôls array([[ 1782.23, 19190.9 ]]) >>> h._output_volume_computer(input_volumes=ivôls) array([[20973.13]])
Let’s now force the first good’s level of consumption by editing its market configuration.
>>> h.compute_calibrand_0_star( ... output_volume = ovol, ... input_volumes = ivols * np.array([[.5, 2.]]), ... input_values = ivals, # † ... ).calibrand_0 array([[23.54, 1.09]]) >>> ivôls = h.input_volumes_computer( ... output_volume = ovol, ... input_prices = iprcs * np.array([[2., .5]]), # † ... ) >>> ivôls array([[ 891.12, 19190.9 ]]) >>> h._output_volume_computer(input_volumes=ivôls) array([[20973.13]])
† : put aside in the
sigma=0case ; maintained in anticipation of a futuresigma-related generalization.
See also
Alleged input shares, \(1 \times |\mcI_j|\), augmented so as to integrate generalized consumption forcing in the perfect-substitutes allocation.
Let \(\widetilde{s}_k\) denote the price-responsive share returned by
allege_input_shares()and letdenote the current normalized IOQ intensity of input \(k\).
Denoting as \(\mathcal{F}_j\) and \(\mathcal{C}_j\) the freely traded-off and forced input sets, respectively, the resulting alleged shares satisfy
Forced inputs therefore retain their current normalized IOQ intensities, while freely traded-off inputs preserve the relative proportions returned by the inherited price-responsive mechanism and exhaust the residual share mass.
In the all-free limiting case, the inherited alleged shares are consequently left unchanged. In the all-forced limiting case, the result reduces to the complete current normalized IOQ vector.
- Parameters
input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.input_prices_lagged (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of the lagged version of
input_prices.ioq_intensities (numpy.ndarray) – \((\balpha_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_intensities’s slice.ioq_intensities_lagged (numpy.ndarray) – \((\balpha_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of the lagged version of
ioq_intensities.
- Example
>>> invariants = dict( ... input_prices = np.array([[1., 1.25, 1.]]), ... input_prices_lagged = np.array([[1., 1., 1.]]), ... ioq_intensities = np.array([[.5, .4, .1]]), ... ioq_intensities_lagged = np.array([[.6, .2, .2]]), ... ) >>> h = HicksianGAFCES(sigma=np.inf, eta=.0, negated_mask=False)
With every input freely traded-off, the inherited allocation is recovered exactly.
>>> h._traded_off = np.array([[1, 1, 1]]).astype(bool) >>> h.allege_input_shares(**invariants).alleged_input_shares array([[0.6, 0.2, 0.2]])
Let’s now successively force one and then two inputs.
>>> h._traded_off = np.array([[0, 1, 1]]).astype(bool) >>> h.allege_input_shares(**invariants).alleged_input_shares array([[0.5 , 0.25, 0.25]])
>>> h._traded_off = np.array([[0, 0, 1]]).astype(bool) >>> h.allege_input_shares(**invariants).alleged_input_shares array([[0.5, 0.4, 0.1]])
When every input is forced, the current normalized IOQ vector is recovered in full.
>>> h._traded_off = np.array([[0, 0, 0]]).astype(bool) >>> h.allege_input_shares(**invariants).alleged_input_shares array([[0.5, 0.4, 0.1]])
Note
Provided the inherited and current IOQ normalizations are well-defined, the transformation preserves
alleged_input_shares’s right stochasticity:See also
-
class
iamax.library.HicksianRGAFCES¶ 
s/e.
-
aggregated_input_volumes_rooter(self, *, output_volume: np.ndarray, input_volumes: np.ndarray)¶ s/e., \(1 \times 1\) unit-dimensionless zero.
(231)¶\[\approx 0\]- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.
See also
-
-
class
iamax.library.HicksianGPAFCES(*args, negated_mask: bool = False, **kwargs)¶ 
Productivity-aware generalization of
HicksianGAFCES. It extends generalized consumption forcing by distinguishing forced inputs according to whether they belong to the productive CES support. In the absence of unproductive inputs, its behavior reduces to that ofHicksianGAFCES.- Parameters
negated_mask (bool) – Whether the coding passed as argument
input_volumes_drates2of methodcompute_calibrand_0()is to be negated. When set toFalse, values1,0and-1respectively designate freely traded-off, forced productive and forced unproductive inputs. When set toTrue, the equivalent coding respectively becomes0,1and2. Set toFalseby default.
Note
Unproductive input consumptions remain part of input demand and, through
HicksianACES, of accounting costs. Their productive contribution is however removed before aggregation.Freely traded-off productive inputs are allocated endogenously over the productive support. Forced productive inputs remain part of that support but have their consumption imposed exogenously. Forced unproductive inputs are likewise consumed exogenously but neither contribute to output nor consume productive allocation mass.
In the perfect-substitutes case, unproductive consumptions remain outside
alleged_input_shares, leaving the latter as an allocation defined exclusively over the productive support.Removing an unproductive input from a perfect-substitutes technology also removes effective quantity from its linear aggregation. Since the ordinary CES calibration Eq.212 degenerates to unit calibrands when
sigma=np.inf, this missing productive scale cannot be represented by inheritedcalibrand_0parametrization. The calibration-period aggregate productive IOQ intensity is therefore retained separately as an additional scalar calibration coefficient of that limiting technology.This scalar calibration assumes neutral
input_volumes_shocks, i.e. \(\bQ_j^\text{dmult}\) (see Eq.215), at \(t=0\). With non-neutral calibration-period shocks, it would instead be calibrated from calibration-period effective input volumes.Reduction to
HicksianGAFCESwhenever every input is productive is a class invariant: productivity awareness must then become behaviorally neutral rather than define an alternative generalized-forcing mechanism.Attention
This class is intended to remain valid for arbitrary
sigmavalues, although finite nonzerosigmacases remain comparatively less tested.- Example
The reduction to
HicksianGAFCEScan first be seen at the Leontief endpoint. Consider three productive inputs, of which only the second is forced. Both classes consequently start from exactly the same generalized-forcing calibration.>>> calkws = dict( ... output_volume = 100., ... input_volumes = np.array([[20., 25., 10.]]), ... input_values = np.array([[40., 50., 20.]]), ... input_volumes_drates2 = np.array([[1, 0, 1]]), ... ) >>> gaf = HicksianGAFCES(sigma=.0, negated_mask=False) >>> gpaf = HicksianGPAFCES(sigma=.0, negated_mask=False) >>> _ = gaf.compute_calibrand_0(**calkws) >>> _ = gpaf.compute_calibrand_0(**calkws) >>> gaf.calibrand_0, gpaf.calibrand_0 (array([[ 5., 4., 10.]]), array([[ 5., 4., 10.]]))
Suppose now that the observed consumptions become
10.,12.5and20.. The first and third inputs remain freely traded-off, whereas the second one is forced onto its new consumption level. The productivity-aware calibration must consequently collapse onto precisely the same mixed calibration asHicksianGAFCES.>>> ivols1 = np.array([[10., 12.5, 20.]]) >>> ivals1 = 2.*ivols1 >>> _ = gaf.compute_calibrand_0_star( ... output_volume=100., input_volumes=ivols1, input_values=ivals1, ... ) >>> _ = gpaf.compute_calibrand_0_star( ... output_volume=100., input_volumes=ivols1, input_values=ivals1, ... ) >>> gaf.calibrand_0_star, gpaf.calibrand_0_star (array([[ 5., 8., 10.]]), array([[ 5., 8., 10.]])) >>> q_gaf = gaf.input_volumes_computer( ... output_volume=100., input_prices=np.full((1, 3), 2.) ... ) >>> q_gpaf = gpaf.input_volumes_computer( ... output_volume=100., input_prices=np.full((1, 3), 2.) ... ) >>> q_gaf, q_gpaf (array([[20. , 12.5, 10. ]]), array([[20. , 12.5, 10. ]])) >>> ( ... gaf._output_volume_computer(input_volumes=q_gaf), ... gpaf._output_volume_computer(input_volumes=q_gpaf), ... ) (array([[100.]]), array([[100.]]))
The same reduction is particularly consequential at the perfect-substitutes endpoint, where
HicksianGPAFCESotherwise introduces its additional productive-support machinery. With no unproductive input, that machinery must remain neutral and the allocation returned byHicksianGAFCESmust be recovered without alteration.>>> calkws = dict( ... output_volume = 1., ... input_volumes = np.array([[.5, .4, .1]]), ... input_values = np.array([[.5, .4, .1]]), ... input_volumes_drates2 = np.array([[1, 0, 1]]), ... ) >>> invariants = dict( ... input_prices = np.array([[1., 1.25, 1.]]), ... input_prices_lagged = np.array([[1., 1., 1.]]), ... ioq_intensities = np.array([[.5, .4, .1]]), ... ioq_intensities_lagged = np.array([[.6, .2, .2]]), ... ) >>> gaf = HicksianGAFCES( ... sigma=np.inf, eta=.0, negated_mask=False ... ) >>> gpaf = HicksianGPAFCES( ... sigma=np.inf, eta=.0, negated_mask=False ... ) >>> _ = gaf.compute_calibrand_0(**calkws) >>> _ = gpaf.compute_calibrand_0(**calkws) >>> _ = gaf.allege_input_shares(**invariants) >>> _ = gpaf.allege_input_shares(**invariants) >>> gaf.alleged_input_shares, gpaf.alleged_input_shares (array([[0.45, 0.4 , 0.15]]), array([[0.45, 0.4 , 0.15]])) >>> gpaf._ioq_p_scale_0 array([[1.]]) >>> q_gaf = gaf.input_volumes_computer( ... output_volume=1., input_prices=np.ones((1, 3)) ... ) >>> q_gpaf = gpaf.input_volumes_computer( ... output_volume=1., input_prices=np.ones((1, 3)) ... ) >>> q_gaf, q_gpaf (array([[0.45, 0.4 , 0.15]]), array([[0.45, 0.4 , 0.15]])) >>> ( ... gaf._output_volume_computer(input_volumes=q_gaf), ... gpaf._output_volume_computer(input_volumes=q_gpaf), ... ) (array([[1.]]), array([[1.]]))
-
_ioq_supports_computer(self, *, ioq_intensities: np.ndarray)¶ Productive-relative-intensity and unproductive-intensity counterparts of current
ioq_intensities.Let \(\alpha_k\) denote the current
ioq_intensitiesof input \(k\), \(\mathcal{U}_j\) the forced unproductive input set (see Eq.236) and \(A_{j,0}^{\mathrm{prod}}\) the calibration-period productive scale (see Eq.239).The denominator applied to productive current
ioq_intensitiesis(232)¶\[\begin{split}D_j = \begin{cases} A_{j,0}^{\mathrm{prod}}, & \mathcal{U}_j \neq \varnothing, \\ \sum_k \alpha_k, & \mathcal{U}_j = \varnothing, \end{cases}\end{split}\]and the method returns
(233)¶\[\begin{split}\overline{\alpha}_k = \begin{cases} 0, & k \in \mathcal{U}_j, \\ \alpha_k/D_j, & k \notin \mathcal{U}_j, \end{cases}\end{split}\]together with
(234)¶\[\begin{split}\alpha_k^{\mathrm{u}} = \begin{cases} \alpha_k, & k \in \mathcal{U}_j, \\ 0, & k \notin \mathcal{U}_j. \end{cases}\end{split}\]Thus, when an unproductive component exists, productive intensities are expressed relative to the fixed productive requirement calibrated at \(t=0\), rather than to a current productive total varying with equilibrium quantities. Their sum therefore need not equal one: they are relative intensities rather than an alleged share vector. When no unproductive component exists, the historical generalized-forcing normalization is reproduced exactly.
- Parameters
ioq_intensities (numpy.ndarray) – \((\balpha_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
ioq_intensities.- Example
>>> calkws = dict( ... output_volume = 1., ... input_volumes = np.array([[.5, .4, .1]]), ... input_values = np.array([[.5, .4, .1]]), ... )
>>> h = HicksianGPAFCES(sigma=np.inf, negated_mask=False) >>> _ = h.compute_calibrand_0( ... input_volumes_drates2=np.array([[1, 0, -1]]), **calkws, ... ) >>> h._ioq_supports_computer( ... ioq_intensities=np.array([[.5, .4, .1]]) ... ) (array([[0.56, 0.44, 0. ]]), array([[0. , 0. , 0.1]])) >>> h._ioq_p_scale_0 array([[0.9]])
When no component is unproductive, the historical generalized forcing normalization is recovered exactly.
>>> h = HicksianGPAFCES(sigma=np.inf, negated_mask=False) >>> _ = h.compute_calibrand_0( ... input_volumes_drates2=np.array([[1, 1, 1]]), **calkws, ... ) >>> h._ioq_supports_computer( ... ioq_intensities=np.array([[.5, .4, .1]]) ... ) (array([[0.5, 0.4, 0.1]]), array([[0., 0., 0.]])) >>> h._ioq_p_scale_0 array([[1.]])
-
_calibrands_0_computer(self, *, output_volume: float, input_values: np.ndarray, input_volumes: np.ndarray)¶ Unproductivity-naive and technology-unpolluted counterparts of
calibrand_0, each \(1 \times |\mcI_j|\).The first counterpart, denoted \(a_k^{\text{astr}}\), results from the ordinary calibration in Eq.212 while disregarding the unproductive status of the corresponding components. The second, denoted \(a_k^{\text{prod}}\), is calibrated after removing the values attached to unproductive components and subsequently assigning them a null calibration weight, i.e.
(235)¶\[\mcv_k \leftarrow 0,\ a_k^{\text{prod}} \leftarrow 0, \ \forall k \in \mathcal{U}_j,\]where \(\mathcal{U}_j\) denotes the forced unproductive input set (see Eq.236). Such components remain represented by their ordinary calibration in the first counterpart while disappearing from the productive support in the second.
- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
input_values.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
input_volumes.
- Example
>>> ovol = 100. >>> ivols = np.array([[20., 25., 10.]]) >>> ivals = 2.*ivols >>> imsks = np.array([[1, 0, -1]])
>>> h = HicksianGPAFCES(sigma=.0, negated_mask=False) >>> h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... input_volumes_drates2 = imsks, ... )._calibrands_0_computer( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... ) (array([[ 5., 4., 10.]]), array([[5., 4., 0.]]))
The last components illustrate both treatments of an unproductive input. The unproductivity-naive calibration treats its observed consumption ordinarily and therefore yields \(a_3=q_j/q_3=100/10=10\) in the
sigma=0case. Its technology-unpolluted counterpart instead assigns that component a null calibrand, thereby excluding it from productive support.
See also
-
compute_calibrand_0(self, *, output_volume: float, input_values: np.ndarray, input_volumes: np.ndarray, input_volumes_drates2: np.ndarray)¶ Altered version of
compute_calibrand_0()that initializes the generalized forcing configuration and its unproductive support. Denoting as \(m_k\) the internally harmonized configuration indicator,(236)¶\[\begin{split}m_k = \begin{cases} 1-d_k, & \text{if mask is negated}, \\ d_k, & \text{otherwise}, \end{cases}\end{split}\]where \(d_k\) is the \(k\)th component of \((\bQ^{\text{drate}^{ii}}_{k,j})_{k \in \mcI_j}\), i.e. a
input_volumes_drates2slice. Values \(m_k=1\), \(m_k=0\) and \(m_k=-1\) respectively designate freely traded-off productive, forced productive and forced unproductive inputs.The initial calibration combines the two counterparts returned by
_calibrands_0_computer()according to(237)¶\[\begin{split}a_k = \begin{cases} a_k^{\text{astr}}, & m_k=-1, \\ a_k^{\text{prod}}, & \text{otherwise}, \end{cases}\end{split}\]where \(a_k^{\text{astr}}\) and \(a_k^{\text{prod}}\) are as in Eq.235.
The observed calibration-period IOQ intensities are additionally retained according to
(238)¶\[\alpha_{k,0} = q_{k,0}/q_{j,0},\]and, whenever an unproductive component is present, the aggregate productive intensity
(239)¶\[A_{j,0}^{\mathrm{prod}} = \sum_{k \notin \mathcal{U}_j}\alpha_{k,0}\]is retained as the missing scalar calibration coefficient of the perfect-substitutes limit. In an entirely productive bundle this additional coefficient is neutralized to
1.so that the behavior ofHicksianGAFCESis reproduced exactly. This calibration assumes neutralinput_volumes_shocks(see Eq.215) at \(t=0\); otherwise \(A_{j,0}^{\mathrm{prod}}\) would have to be computed from calibration-period effective input volumes.- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.input_volumes_drates2 (numpy.ndarray) – \((\bQ^{\text{drate}^{ii}}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
input_volumes_drates2. Values1,0and-1respectively designate freely traded-off, forced productive and forced unproductive inputs whennegated_mask=False; the equivalent coding is0,1and2whennegated_mask=True.
- Example
>>> ovol = 100. >>> ivols = np.array([[20., 25., 10.]]) >>> ivals = 2.*ivols >>> imsks = np.array([[1, 0, -1]])
>>> h = HicksianGPAFCES(sigma=.0, negated_mask=False) >>> _ = h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... input_volumes_drates2 = imsks, ... ) >>> h.calibrand_0 array([[ 5., 4., 10.]]) >>> h._traded_off array([[ True, False, False]]) >>> h._unproductive array([[False, False, True]]) >>> h._ioq array([[0.2 , 0.25, 0.1 ]]) >>> h._ioq_p_scale_0 array([[0.45]])
The equivalent negated-mask coding follows.
>>> h = HicksianGPAFCES(sigma=.0, negated_mask=True) >>> _ = h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... input_volumes_drates2 = np.array([[0, 1, 2]]), ... ) >>> h.calibrand_0 array([[ 5., 4., 10.]]) >>> h._traded_off array([[ True, False, False]]) >>> h._unproductive array([[False, False, True]])
-
compute_calibrand_0_star(self, *, output_volume: float, input_values: np.ndarray, input_volumes: np.ndarray, ioq_shares_drates: np.ndarray = 0.0, ioq_shares_drates2: np.ndarray = 0.0, ioq_productivities_drates: np.ndarray = 0.0, ioq_productivities_drates2: np.ndarray = 0.0)¶ Altered version of
compute_calibrand_0_star()that integrates generalized consumption forcing and unproductive consumptions. Before the star transformation, the current calibration is updated according to(240)¶\[\begin{split}a_{k,t} = \begin{cases} a_{k,0}, & k \text{ is freely traded-off}, \\ a_{k,t}^{\text{prod}}, & k \text{ is forced and productive}, \\ a_{k,t}^{\text{astr}}, & k \text{ is forced and unproductive}, \end{cases}\end{split}\]where \(a_{k,0}\) is the calibration-period calibrand (see Eq.212), while \(a_{k,t}^{\text{prod}}\) and \(a_{k,t}^{\text{astr}}\) denote the technology-unpolluted and unproductivity-naive calibrations in Eq.235.
Two star counterparts are subsequently maintained. Attribute
calibrand_0_astrapplies the ordinary transformation in Eq.213 to the complete unproductivity-naive calibration and is later used to recover unproductive input consumptions. Attributecalibrand_0_starinstead retains the generalized forcing calibration over the productive support, with unproductive components replaced by their technology-unpolluted counterparts.At
sigma=np.inf, inherited demand instead usesalleged_input_shares(see Eq.241). The missing scalar productive calibration \(A_{j,0}^{\mathrm{prod}}\) (see Eq.239) is supplied separately by_ioq_p_scale_0, while current raw IOQ intensities are retained for recovering forced consumptions.- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.ioq_shares_drates (numpy.ndarray) – \((\bbeta^\text{drate}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_shares_drates’s slice. Set to.0by default.ioq_shares_drates2 (numpy.ndarray) – \((\bbeta^{\text{drate}^{ii}}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_shares_drates2’s slice. Set to.0by default.ioq_productivities_drates (numpy.ndarray) – \((\balpha^{-1,\ \text{drate}_{k,j}})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_productivities_drates’s slice. Set to.0by default.ioq_productivities_drates2 (numpy.ndarray) – \((\balpha^{-1,\ \text{drate}^{ii}_{k,j}})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_productivities_drates2’s slice. Set to.0by default.
- Example
>>> ovol = 100. >>> ivols = np.array([[20., 25., 10.]]) >>> iprcs = np.array([[2., 2., 2.]]) >>> ivals = iprcs*ivols >>> imsks = np.array([[1, 0, -1]])
>>> h = HicksianGPAFCES(sigma=.0, negated_mask=False) >>> _ = h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... input_volumes_drates2 = imsks, ... ) >>> _ = h.compute_calibrand_0_star( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... ) >>> h.calibrand_0 array([[ 5., 4., 10.]]) >>> h.calibrand_0_star array([[5., 4., 0.]]) >>> h.calibrand_0_astr array([[ 5., 4., 10.]])
Let’s now alter all three observed consumptions. The first input remains freely subject to trade-off, the second is forced and productive and the third is forced and unproductive.
>>> ivols1 = ivols * np.array([[.5, .5, 2.]]) >>> ivals1 = iprcs*ivols1 >>> h.compute_calibrand_0_star( ... output_volume = ovol, ... input_volumes = ivols1, ... input_values = ivals1, ... ).calibrand_0 array([[5., 8., 5.]]) >>> h.calibrand_0_star array([[5., 8., 0.]]) >>> h.calibrand_0_astr array([[10., 8., 5.]])
Accordingly, the freely traded-off first input is not forced onto its newly observed level, whereas the two forced consumptions are.
>>> ivôls = h.input_volumes_computer( ... output_volume = ovol, ... input_prices = iprcs, ... ) >>> ivôls array([[20. , 12.5, 20. ]]) >>> h._output_volume_computer(input_volumes=ivôls) array([[100.]])
Alleged productive input shares, \(1 \times |\mcI_j|\), augmented so as to keep unproductive consumptions entirely outside the perfect-substitutes allocation.
Let \(\widetilde{s}_k\) denote the price-responsive share returned by
allege_input_shares()after removing unproductive components fromioq_intensities_lagged(see Eq.214). Let \(\overline{\alpha}_k\) denote the productive relative intensity processed fromioq_intensities(see Eq.233).Denoting as \(\mathcal{F}_j\), \(\mathcal{C}_j\) and \(\mathcal{U}_j\) the freely traded-off productive, forced productive and forced unproductive sets (see Eq.236), the resulting alleged shares satisfy
Thus, with an unproductive input, a forced productive intensity \(\alpha_k\) is translated into \(\alpha_k/A_{j,0}^{\mathrm{prod}}\) (see Eq.239). Since the productive demand system subsequently multiplies the complete allocation by \(A_{j,0}^{\mathrm{prod}}\), forced productive demand is restored exactly rather than altered by normalization.
Unproductive components receive no productive share and therefore consume none of the productive allocation mass. Their current raw intensities are retained separately in
_ioq, directly recovered byinput_volumes_computer().- Parameters
input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.input_prices_lagged (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of the lagged version of
input_prices.ioq_intensities (numpy.ndarray) – \((\balpha_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_intensities’s slice.ioq_intensities_lagged (numpy.ndarray) – \((\balpha_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of the lagged version of
ioq_intensities.
- Example
Some commonalities first. The calibration quantities are made consistent with the current intensities so that, once the third component is declared unproductive, the
t=0productive scale is.9.>>> calkws = dict( ... output_volume = 1., ... input_volumes = np.array([[.5, .4, .1]]), ... input_values = np.array([[.5, .4, .1]]), ... ) >>> invariants = dict( ... input_prices = np.array([[1., 1.25, 1.]]), ... input_prices_lagged = np.array([[1., 1., 1.]]), ... ioq_intensities = np.array([[.5, .4, .1]]), ... ioq_intensities_lagged = np.array([[.6, .2, .2]]), ... )
Let’s first reproduce the ordinary freely traded-off case.
>>> h = HicksianGPAFCES(sigma=np.inf, eta=.0, negated_mask=False) >>> _ = h.compute_calibrand_0( ... input_volumes_drates2=np.array([[1, 1, 1]]), **calkws, ... ) >>> h.allege_input_shares(**invariants).alleged_input_shares array([[0.6, 0.2, 0.2]])
Let’s now force the first productive input.
>>> h = HicksianGPAFCES(sigma=np.inf, eta=.0, negated_mask=False) >>> _ = h.compute_calibrand_0( ... input_volumes_drates2=np.array([[0, 1, 1]]), **calkws, ... ) >>> h.allege_input_shares(**invariants).alleged_input_shares array([[0.5 , 0.25, 0.25]])
The generalized forcing mechanism can also force several productive inputs.
>>> h = HicksianGPAFCES(sigma=np.inf, eta=.0, negated_mask=False) >>> _ = h.compute_calibrand_0( ... input_volumes_drates2=np.array([[0, 0, 1]]), **calkws, ... ) >>> h.allege_input_shares(**invariants).alleged_input_shares array([[0.5, 0.4, 0.1]])
Let’s now make the third consumption unproductive while keeping the first two inputs freely traded-off. It is entirely removed from the productive share vector. The productive unit allocation therefore follows the relative parent shares over the first two components only.
>>> h = HicksianGPAFCES(sigma=np.inf, eta=.0, negated_mask=False) >>> _ = h.compute_calibrand_0( ... input_volumes_drates2=np.array([[1, 1, -1]]), **calkws, ... ) >>> h.allege_input_shares(**invariants).alleged_input_shares array([[0.75, 0.25, 0. ]]) >>> h._ioq_p_scale_0 array([[0.9]])
The three states may finally operate simultaneously. The forced productive intensity
.4represents.4/.9of the fixed productive requirement and hence leaves.5/.9to the freely traded-off productive component.>>> HicksianGPAFCES( ... sigma=np.inf, eta=.0, negated_mask=False ... ).compute_calibrand_0( ... input_volumes_drates2=np.array([[1, 0, -1]]), **calkws, ... ).allege_input_shares(**invariants).alleged_input_shares array([[0.56, 0.44, 0. ]])
The equivalent negated-mask coding produces the same result.
>>> HicksianGPAFCES( ... sigma=np.inf, eta=.0, negated_mask=True ... ).compute_calibrand_0( ... input_volumes_drates2=np.array([[0, 1, 2]]), **calkws, ... ).allege_input_shares(**invariants).alleged_input_shares array([[0.56, 0.44, 0. ]])
Note
Whenever at least one freely traded-off productive component remains, such components absorb the productive mass left after forced productive consumptions have been assigned. A nonnegative residual allocation then requires
If every productive component is forced, no such residual adjustment exists and technological consistency requires
Failure of the latter equality is then a genuine technological inconsistency rather than something this method should normalize away artificially.
-
input_volumes_computer(self, *, output_volume: float, input_prices: np.ndarray)¶ Input demands, \(1 \times |\mcI_j|\), obtained by combining the technology-unpolluted and unproductivity-naive demand systems. Denoting by \(q_k^*\) the demand returned by Eq.219 under
calibrand_0_starand by \(q_k^{\text{astr}}\) its counterpart obtained undercalibrand_0_astr, the finite-elasticity demand is(244)¶\[\begin{split}q_k = \begin{cases} q_k^{\text{astr}}, & k \in \mathcal{U}_j, \\ q_k^*, & k \notin \mathcal{U}_j. \end{cases}\end{split}\]where \(\mathcal{U}_j\) denotes the forced unproductive input set (see Eq.236). The former preserves the demand implied by the ordinary, unproductivity-naive system for unproductive components, whereas the latter determines productive demands without allowing those components to pollute the productive CES support.
At
sigma=np.inf, the inherited demand expression instead readsalleged_input_sharesdirectly. The productive demand then becomes(245)¶\[q_k = q_j A_{j,0}^{\mathrm{prod}} s_k Q^{\text{dmult}}_{k,j}, \ k \notin \mathcal{U}_j,\]where \(q_j\) is as in Eq.219, \(A_{j,0}^{\mathrm{prod}}\) as in Eq.239 and \(s_k\) as in Eq.241. Here, \(Q^{\text{dmult}}_{k,j}\) corresponds to
input_volumes_shocks(see Eq.215).An unproductive input instead obeys
(246)¶\[q_k = q_j \alpha_k^{\mathrm{u}} Q^{\text{dmult}}_{k,j}, \ k \in \mathcal{U}_j.\]with \(\alpha_k^{\mathrm{u}}\) as in Eq.234. Hence
input_volumes_shocksremains fully operative for both productive and unproductive components. The special treatment concerns only the productive scale that the limiting ordinary CES calibration can no longer represent component-wise.- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.
- Example
Perfect substitutes with one freely traded-off productive component, one forced productive component and one forced unproductive component.
>>> h = HicksianGPAFCES(sigma=np.inf, eta=.0) >>> _ = h.compute_calibrand_0( ... output_volume = 1., ... input_volumes = np.array([[.5, .4, .1]]), ... input_values = np.array([[.5, .4, .1]]), ... input_volumes_drates2 = np.array([[1, 0, -1]]), ... ) >>> _ = h.allege_input_shares( ... input_prices = np.ones((1, 3)), ... input_prices_lagged = np.ones((1, 3)), ... ioq_intensities = np.array([[.5, .4, .1]]), ... ioq_intensities_lagged = np.array([[.5, .4, .1]]), ... ) >>> h.input_volumes_computer( ... output_volume=1., input_prices=np.ones((1, 3)) ... ) array([[0.5, 0.4, 0.1]])
The productive and unproductive demand systems therefore reproduce the calibration quantities simultaneously.
>>> ivôls = h.input_volumes_computer( ... output_volume=1., input_prices=np.ones((1, 3)) ... ) >>> h._output_volume_computer(input_volumes=ivôls) array([[1.]])
-
_output_volume_computer(self, *, input_volumes: np.ndarray)¶ Output supply, \(1 \times 1\), purged from the productive contribution of forced unproductive consumptions. Before delegating aggregation to
_output_volume_computer()(see Eq.216), unproductive components are contextually transformed according to(247)¶\[\begin{split}a_k^{*,\mathrm{prod}} = \begin{cases} 0, & k \in \mathcal{U}_j, \\ a_k^*, & k \notin \mathcal{U}_j, \end{cases}\end{split}\]where \(\mathcal{U}_j\) denotes the forced unproductive input set (see Eq.236) and \(a_k^*\) the inherited star calibrand (see Eq.213).
With \(Q^{\text{dmult}}_{k,j}\) denoting
input_volumes_shocks(see Eq.215), input volumes are additionally transformed according to(248)¶\[\begin{split}\widetilde q_k = \begin{cases} Q^{\text{dmult}}_{k,j}, & k \in \mathcal{U}_j, \\ q_k, & k \notin \mathcal{U}_j. \end{cases}\end{split}\]Since inherited aggregation operates on \(\widetilde q_k/Q^{\text{dmult}}_{k,j}\), an unproductive component’s temporary effective volume reduces to
1whenever the shock is non-null, while_divide()maps the indeterminate \(0/0\) case to zero. Combined with its null calibration weight, either case removes that component from the productive CES support without propagating an undefined value.At
sigma=np.inf, productive input demand Eq.245 contains the scalar calibration requirement \(A_{j,0}^{\mathrm{prod}}\) (see Eq.239). Since inherited aggregation is then linear over productive effective volumes, the same fixed coefficient must be removed after aggregation:(249)¶\[q_j = \frac{ \sum_{k \notin \mathcal{U}_j} q_k/Q^{\text{dmult}}_{k,j} }{ A_{j,0}^{\mathrm{prod}} }.\]Thus demand and production remain exact inverses while the productive scale is a fixed technology calibrand rather than a current equilibrium quantity.
- Parameters
input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.- Example
>>> ovol = 100. >>> ivols = np.array([[20., 10.]]) >>> ivals = 2.*ivols >>> imsks = np.array([[0, -1]])
>>> h = HicksianGPAFCES(sigma=.0, negated_mask=False) >>> h.compute_calibrand_0( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... input_volumes_drates2 = imsks, ... ).compute_calibrand_0_star( ... output_volume = ovol, ... input_volumes = ivols, ... input_values = ivals, ... )._output_volume_computer( ... input_volumes=ivols ... ) array([[100.]])
The unproductive input’s consumed amount has no bearing on productive output.
>>> h._output_volume_computer( ... input_volumes=np.array([[20., 1000.]]) ... ) array([[100.]])
The same inverse identity holds in the perfect-substitutes case.
>>> h = HicksianGPAFCES(sigma=np.inf, eta=.0) >>> _ = h.compute_calibrand_0( ... output_volume = 1., ... input_volumes = np.array([[.5, .4, .1]]), ... input_values = np.array([[.5, .4, .1]]), ... input_volumes_drates2 = np.array([[1, 0, -1]]), ... ) >>> _ = h.allege_input_shares( ... input_prices = np.ones((1, 3)), ... input_prices_lagged = np.ones((1, 3)), ... ioq_intensities = np.array([[.5, .4, .1]]), ... ioq_intensities_lagged = np.array([[.5, .4, .1]]), ... ) >>> ivôls = h.input_volumes_computer( ... output_volume=1., input_prices=np.ones((1, 3)) ... ) >>> h._output_volume_computer(input_volumes=ivôls) array([[1.]])
-
class
iamax.library.HicksianFLUMRS(*args, **kwargs)¶ 
Unit MRS linear (forced) production function which boils down to a special case of
HicksianFCESwhere \(a_k=1 \text{ for } k \in \mcI_j\) and \(\sigma \longrightarrow \infty\).Note
This class’s
compute_calibrand_0()has no system-dependence since the underlying calibrands are inherently equal to \(1\).
-
class
iamax.library.MarshallianCES(*args, **kwargs)¶ 
Constant Elasticity of Substitution abstraction whose optimal demand function derives from a maximization program formulated à la Marshall.
Note
Calculations assert constant return to scale, i.e. Eq.200’s \(\nu\) is forced to be \(1\) at instantiation.
-
compute_calibrand_0(self, *, budget_constraint: float, input_values: np.ndarray)¶ Calibrate the \((a_{k,j})_{k \in \mcI_j}\), i.e. the \(|\mcI_j|\) demand share parameters related to aggregate \(j\), considering them equal to the budget share of each of the underlying consumptions in the base year.
(250)¶\[a_k = \frac{\mcv_k}{r_j}, \ \forall k \ \in \mcI_j\]with \(r_j\) the budget constraint to be saturated, \(\mcI_j\) the index set of the subject-to-\(r_j\) traded off consumptions, \(\mcv_k\) the \(q_k\)’s corresponding input value.
- Parameters
budget_constraint (float) – \(r_j\), i.e. the \(j\)th \(1 \times 1\)
budget_constraints’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.
- Example
>>> m = MarshallianCES(sigma=None) >>> _ = m.compute_calibrand_0( ... budget_constraint=200., ... input_values=np.array([[110., 90.]]) ... ) >>> m._shares_sum array([[1.]]) >>> m.calibrand_0 array([[0.55, 0.45]])
>>> _ = m.compute_calibrand_0( ... budget_constraint=100., ... input_values=np.array([[110., 90.]]) ... ) >>> m._shares_sum array([[2.]]) >>> m.calibrand_0 array([[0.55, 0.45]])
See also
-
budget_constraint_crooter(self)¶ compute_calibrand_0()’s companion unit-dimensionless zero aiming at ensuring that the sum of shares add up to 1, \(1 \times 1\).- Example
>>> budc = 200. >>> ivals = np.array([[110., 90.]]) >>> m = MarshallianCES(sigma=None) >>> _ = m.compute_calibrand_0( ... budget_constraint=budc, input_values=ivals ... ) >>> m.budget_constraint_crooter() array([[0.]])
Let’s then illustrate how such calculation can be vectorized.
>>> vbudc = np.array([[[.5*budc]], [[budc]], [[2*budc]]]) >>> vivals = np.stack((ivals, ivals, ivals)) >>> m.compute_calibrand_0( ... budget_constraint=vbudc, input_values=vivals ... ).budget_constraint_crooter() array([[[ 1. ]], [[ 0. ]], [[-0.5]]])
-
input_volumes_computer(self, *, budget_constraint: float, input_prices: np.ndarray)¶ Input demands, \(1 \times |\mcI_j|\), denoted as
(251)¶\[q_k = \frac{ r_j p_{k}^{\frac{1}{\rho_j - 1}} }{ \sum_{k^{'} \in \mcI_j} p_{k^{'}}^{\frac{\rho_j}{\rho_j - 1}} \left[ \frac{a_k}{a_{k^{'}}} \right]^{\frac{1}{\rho_j - 1}} } = \frac{r_j}{ p_{k}^{\sigma_j} \sum_{k^{'} \in \mcI_j} p_{k^{'}}^{1-\sigma_j} \left[ \frac{a_{k^{'}}}{a_{k}} \right]^{\sigma_j} } \ \forall k \ \in \mcI_j\]where \(r_j\) is the budget constraint to be saturated, \(\rho_j = \frac{\sigma_j - 1}{\sigma_j}\) the substitution parameter, \(\sigma_j = \frac{1}{1 - \rho_j}\) the elasticity of substitution, \(\mcI_j\) the index set of consumptions traded off under \(r_j\), \(p_k\) the \(q_k\)’s price and \(a_k\) as in Eq.250.
See also
A two-good version of Eq.251 can be found in the notes prepared for the GAMS workshop on general equilibrium held in December 1995 in Boulder, Colorado.
What happens internally, is actually performed in matrix terms (so as to benefit from vectorization) as follows:
(252)¶\[\bq = \frac{r_j}{ \bp^{\sigma_j} \odot \mathbf{1}_{|\mcI_j|} \left( \bp^{1 - \sigma_j} \odot \left[ \ba \cdot \frac{1}{\ba^{'}} \right]^{\sigma_j} \right)^{'} }\]where \(\mathbf{1}_{|\mcI_j|}\), \(\bq = (q_1, \ldots, q_{|\mcI_j|})\), \(\ba = (a_1, \ldots, a_{|\mcI_j|})\) and \(\bp = (p_1, \ldots, p_{|\mcI_j|})\) are \(1 \times |\mcI_j|\) vectors.
- Parameters
budget_constraint (float) – \(r_j\), i.e. the \(j\)th \(1 \times 1\)
budget_constraints’s element.input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.
- Example
Let’s directly deal with the \(\rho_j=0 \iff \sigma_j=1\) CES’s limiting case, which makes it boil down down to a Cobb-Douglas function.
>>> budc = 200. >>> ivals = np.array([[110., 90.]]) >>> iprcs = np.array([[.9, 1.1]])
>>> m = MarshallianCES(sigma=1) >>> _ = m.compute_calibrand_0( ... budget_constraint=budc, input_values=ivals ... ) >>> m.calibrand_0 array([[0.55, 0.45]])
>>> m.input_volumes_computer( ... budget_constraint=budc, input_prices=np.ones_like(ivals), ... ) array([[110., 90.]]) >>> m.input_volumes_computer( ... budget_constraint=budc, input_prices=iprcs, ... ) array([[122.22, 81.82]])
You can check for yourself via, say, there. Let’s then illustrate how such calculation can be vectorized.
>>> vbudc = np.array([[[.5*budc]], [[budc]], [[2*budc]]]) >>> vivals = np.stack((ivals, ivals, ivals)) >>> viprcs = np.stack((iprcs, iprcs, iprcs))
>>> m = MarshallianCES(sigma=[[[2.]], [[1.]], [[.5]]]) >>> _ = m.compute_calibrand_0( ... budget_constraint=vbudc, input_values=vivals ... ) >>> m.calibrand_0 array([[[0.55, 0.45]], [[0.55, 0.45]], [[0.55, 0.45]]]) >>> m.input_volumes_computer( ... budget_constraint=vbudc, input_prices=viprcs, ... ) array([[[ 71.79, 32.17]], [[122.22, 81.82]], [[222.22, 181.82]]])
-
-
class
iamax.library.MarshallianGFCES(*args, negated_mask: bool = False, **kwargs)¶ 
MarshallianCES’s altered version whose underlying trade-off is forced in a generalized manner by restricting it to a consumption subset of arbitrary size.- Parameters
negated_mask (bool) – Whether the mask passed as argument
input_volumes_drates2of the methodcompute_calibrand_0is to be negated. Argumentinput_volumes_drates2indeed boolean-specifies the good being subject to consumption tradeoff by default. Set toFalseby default.
-
compute_calibrand_0(self, *, budget_constraint: float, input_values: np.ndarray, input_volumes_drates2: np.ndarray)¶ s/e.
- Parameters
budget_constraint (float) – \(r_j\), i.e. the \(j\)th \(1 \times 1\)
budget_constraints’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.input_volumes_drates2 (numpy.ndarray) – \((\bQ^\text{drate}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes_drates2’s slice. This variable is coerced into boolean and used as mask.
- Example
>>> m = MarshallianGFCES(sigma=None, negated_mask=False) >>> m.compute_calibrand_0( ... budget_constraint = 200., ... input_values = np.array([[110., 90.]]), ... input_volumes_drates2 = np.array([[1., 1.]]) ... ) >>> m._shares_sum array([[1.]]) >>> m.calibrand_0 array([[0.55, 0.45]])
>>> m.compute_calibrand_0( ... budget_constraint = 200., ... input_values = np.array([[110., 90.]]), ... input_volumes_drates2 = np.array([[1., 0.]]) ... ) >>> m._shares_sum array([[1.]]) >>> m.calibrand_0 array([[1., 0.]])
>>> m = MarshallianGFCES(sigma=None, negated_mask=True) >>> m.compute_calibrand_0( ... budget_constraint = 200., ... input_values = np.array([[110., 90.]]), ... input_volumes_drates2 = np.array([[0., 0.]]) ... ) >>> m._shares_sum array([[1.]]) >>> m.calibrand_0 array([[0.55, 0.45]])
>>> m.compute_calibrand_0( ... budget_constraint = 200., ... input_values = np.array([[110., 90.]]), ... input_volumes_drates2 = np.array([[1., 0.]]) ... ) >>> m._shares_sum array([[1.]]) >>> m.calibrand_0 array([[0., 1.]])
See also
-
input_volumes_computer(self, budget_constraint: float, input_values: np.ndarray, input_prices: np.ndarray)¶ s/e.
- Parameters
budget_constraint (float) – \(r_j\), i.e. the \(j\)th \(1 \times 1\)
budget_constraints’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.
- Example
Let’s directly deal with the \(\rho_j=0 \iff \sigma_j=1\) CES’s limiting case, which makes it boil down down to a Cobb-Douglas function.
>>> budc = 200. >>> ivals = np.array([[110., 90.]]) >>> iprcs = np.array([[.9, 1.1]])
>>> imsks = np.array([[1., 0.]]) >>> m = MarshallianGFCES(sigma=1, negated_mask=False) >>> m.compute_calibrand_0( ... budget_constraint=budc, input_values=ivals, ... input_volumes_drates2=imsks ... ) >>> m.calibrand_0 array([[1., 0.]]) >>> m.input_volumes_computer( ... budget_constraint=budc, input_prices=np.ones_like(ivals), ... input_values=ivals, ... ) array([[110., 90.]]) >>> m.input_volumes_computer( ... budget_constraint=budc, input_prices=iprcs, ... input_values=ivals, ... ) array([[122.22, 81.82]])
>>> imsks = np.array([[0., 1.]]) >>> m = MarshallianGFCES(sigma=1, negated_mask=True) >>> m.compute_calibrand_0( ... budget_constraint=budc, input_values=ivals, ... input_volumes_drates2=imsks ... ) >>> m.calibrand_0 array([[1., 0.]]) >>> m.input_volumes_computer( ... budget_constraint=budc, input_prices=np.ones_like(ivals), ... input_values=ivals, ... ) array([[110., 90.]]) >>> m.input_volumes_computer( ... budget_constraint=budc, input_prices=iprcs, ... input_values=ivals, ... ) array([[122.22, 81.82]])
See also
-
spendings_rooter(self, *, budget_constraint: float, input_values: np.ndarray)¶ s/e., \(1 \times 1\) unit-dimensionless zero.
(253)¶\[\approx 0\]- Parameters
budget_constraint (float) – \(r_j\), i.e. the \(j\)th \(1 \times 1\)
budget_constraints’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.
-
class
iamax.library.MarshallianLeo¶ 
Particularized version of
MarshallianCESat \(\sigma=0\).Warning
This class has vocation to be removed sooner or later and obtained directly through the parametrization of
MarshallianCES.-
compute_calibrand_0(self, *, input_prices: np.ndarray, input_volumes: np.ndarray)¶ s/e.
(254)¶\[a_k = q_k / \sum_{k^{'} \in \mcI_j} q_{k^{'}} \ \forall k \ \in \mcI_j\]where \(q_k\) is the utility maximizing level of consumption.
- Parameters
input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.
- Example
>>> m = MarshallianLeo() >>> _ = m.compute_calibrand_0( ... input_prices=np.ones((1, 2)), ... input_volumes=np.array([[110., 90.]]) ... ) >>> m.calibrand_0 array([[0.55, 0.45]])
-
input_volumes_computer(self, *, budget_constraint: float, input_prices: np.ndarray, **_: np.ndarray)¶ Input demands, \(1 \times |\mcI_j|\), denoted as
(255)¶\[q_k = a_k \frac{r_j}{ \sum_{k^{'} \in \mcI_j} \tbp_{k^{'}} a_{k^{'}} } \ \forall k \ \in \mcI_j\]where \(r_j\) is the budget constraint to be saturated, \(a_k\) is as in Eq.254 and \(\tbp_k\) is the \(k\)th price of consumption.
- Parameters
budget_constraint (float) – \(r_j\), i.e. a \(j\)-related \(1 \times 1\)
budget_constraints’s element.input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.
- Example
>>> m = MarshallianLeo() >>> _ = m.compute_calibrand_0( ... input_prices=np.array([[1.01, .99]]), ... input_volumes=np.array([[110., 90.]]) ... ) >>> m.calibrand_0 array([[0.55, 0.45]]) >>> m.input_volumes_computer( ... budget_constraint=200, input_prices=np.ones((1, 2)), ... ) array([[110., 90.]])
-
-
class
iamax.library.EmplBMagnitude¶ Utility base class aggregating private methods related to employment- and utilization-based magnitudes.
See also
-
static
_drate_pow_increaser(*, dr: float, c: float = 1.0, s: float = 1.0)¶ Rate differential increasing function.
(256)¶\[\mfr(dr, c, s) := s\left(1 + dr\right)^{c}\]Cf. parameters section below.
- Parameters
Note
For \(s>0\) and \(1+dr>0\), the function is \(dr\)-increasing when \(c>0\) and \(dr\)-decreasing when \(c<0\).
- Example
>>> invariants = {'c': .2, 's': 1.} >>> EmplBMagnitude._drate_pow_increaser(dr=-.5, **invariants) 0.8705505632961241 >>> EmplBMagnitude._drate_pow_increaser(dr=.0, **invariants) 1.0 >>> EmplBMagnitude._drate_pow_increaser(dr=.5, **invariants) 1.0844717711976986
-
static
_factor_pow_increaser(*, f: float, c: float = 1.0, s: float = 1.0)¶ Factor increasing function.
(257)¶\[\mfr(f, c, s) := s\,\Re\left((f+0i)^c\right)\]- Parameters
Note
For \(s>0\) and \(f>0\), the function is \(f\)-increasing when \(c>0\) and \(f\)-decreasing when \(c<0\).
- Example
>>> invariants = { ... 'c': .2, ... 's': 1., ... } >>> EmplBMagnitude._factor_pow_increaser(f=.5, **invariants) 0.8705505632961241 >>> EmplBMagnitude._factor_pow_increaser(f=1.0, **invariants) 1.0 >>> EmplBMagnitude._factor_pow_increaser(f=1.5, **invariants) 1.0844717711976986 >>> EmplBMagnitude._factor_pow_increaser(f=-.5, **invariants) 0.7042902001692477
-
static
_rate_tanh_increaser(*, r: float, a: float = 1.0, b: float = 1.0, c: float = -1.0, s: float = 1.0)¶ Rate increasing function.
(258)¶\[\mfr(r, a, b, c, s) := s\left( a + b \tanh(-c r) \right)\]Cf. parameters section below.
- Parameters
Note
For \(s b > 0\), the function is \(r\)-decreasing when \(c > 0\) and \(r\)-increasing when \(c < 0\).
- Example
A rate-decreasing parametrization first.
>>> invariants = { ... 'a': .05, ... 'b': .711594155955765, ... 'c': 1.09045112440194, ... 's': 1. ... } >>> EmplBMagnitude._rate_tanh_increaser(r=.0, **invariants) 0.05 >>> EmplBMagnitude._rate_tanh_increaser(r=.5, **invariants) -0.3036148489085014 >>> EmplBMagnitude._rate_tanh_increaser(r=1., **invariants) -0.5171709549513277
The default parametrization is rate-increasing.
>>> EmplBMagnitude._rate_tanh_increaser(r=.0) 1.0 >>> EmplBMagnitude._rate_tanh_increaser(r=.5) 1.4621171572600098 >>> EmplBMagnitude._rate_tanh_increaser(r=1.) 1.7615941559557649
-
classmethod
_rate_tanh_sigma_calibrator(cls, *, r: np.ndarray, e: np.ndarray, v: np.ndarray|float = 1.0)¶ Tanh calibration from a reference rate and elasticity.
(259)¶\[\begin{split}v &= \mfr(r, a, b, c, 1) \\ e &= \frac{r}{\mfr(r, a, b, c, 1)} \frac{\partial \mfr(r, a, b, c, 1)}{\partial r} \\ a &= b\end{split}\]Defining \(q=-e\) and \(x=cr\), the calibration admits the closed-form solution
(260)¶\[\begin{split}x &= \frac{1}{2}\left(q + W_0\left(q\exp(-q)\right)\right) \\ c &= \frac{x}{r} \\ a=b &=\frac{v}{1-\tanh(x)}\end{split}\]where \(W_0\) is the principal branch of the Lambert \(W\) function.
- Parameters
r (numpy.ndarray) – Reference rate.
e (numpy.ndarray) – Local elasticity at the reference rate.
v (numpy.ndarray or float) – Magnitude value at the reference rate. To
1.by default.
Note
The stated closed-form calibration and numerical guarantee apply to non-positive local elasticities, for which \(q=-e\geq0\), and to strictly positive reference rates.
See also
- Example
>>> a, b, c = EmplBMagnitude._rate_tanh_sigma_calibrator( ... r=.2, e=-.55 ... ) >>> a.item() 1.6102140203583628 >>> b.item() 1.6102140203583628 >>> c.item() 1.9942499710804265
A vectorized example.
>>> r = np.array([[[.2]], [[.1]]]) >>> e = np.array([[[-.55]], [[-.1]]]) >>> a, b, c = ( ... EmplBMagnitude._rate_tanh_sigma_calibrator( ... r=r, e=e ... ) ... ) >>> a array([[[1.61]], [[1.1 ]]]) >>> b array([[[1.61]], [[1.1 ]]]) >>> c array([[[1.99]], [[0.92]]])
>>> m = a + b*np.tanh(-c*r) >>> np.allclose(m, np.ones_like(m), rtol=0., atol=1e-14) True >>> np.allclose(-c*r*(1. + np.tanh(c*r)), e, rtol=0., atol=1e-14) True
-
classmethod
_lambertw0(cls, *, z: float)¶ Principal Lambert function, as used over nonnegative arguments.
(261)¶\[W_0(z)\exp\left(W_0(z)\right) = z\]The approximation starts from \(\log(1+z)\) and applies five vectorized Halley refinements.
- Parameters
z (float) – Nonnegative Lambert-function argument.
Note
Five Halley refinements are sufficient for the calibration. Indeed, the Lambert-function argument generated by
_rate_tanh_sigma_calibrator()is of the form\[z=q\exp(-q), \ q\geq 0,\]and therefore belongs to \([0, 1/e]\). Over this interval, the principal branch \(W_0\) is smooth, while \(\log(1+z)\) already provides a close initial approximation. Halley’s cubic convergence consequently brings the result to standard floating-point precision within fewer than five refinements.
Attention
This fixed number of refinements is not asserted to suffice for an unrestricted implementation of \(W_0\), notably close to its branch point \(-1/e\) or for arbitrarily large positive arguments.
See also
- Example
The implementation also remains accurate over a much wider positive range than the one required by the calibration.
>>> z = np.array([.0, *10**np.arange(-14., 13.)]) >>> z array([0.e+00, 1.e-14, 1.e-13, 1.e-12, 1.e-11, 1.e-10, 1.e-09, 1.e-08, 1.e-07, 1.e-06, 1.e-05, 1.e-04, 1.e-03, 1.e-02, 1.e-01, 1.e+00, 1.e+01, 1.e+02, 1.e+03, 1.e+04, 1.e+05, 1.e+06, 1.e+07, 1.e+08, 1.e+09, 1.e+10, 1.e+11, 1.e+12]) >>> w = EmplBMagnitude._lambertw0(z=z) >>> np.allclose(w*np.exp(w), z, rtol=1.72e-15, atol=1.02e-10) True
-
static
_lambertw0_step(*, z: float, w: float)¶ Principal Lambert-function Halley step.
(262)¶\[w^{+} := w - \frac{w\exp(w)-z}{ \exp(w)(w+1) -\dfrac{(w+2)(w\exp(w)-z)}{2(w+1)} }\]- Parameters
Note
Arguments are mutually broadcast following NumPy’s standard broadcasting rules.
-
classmethod
_rate_tanh_bounds_calibrator(cls, *, r: np.ndarray, vmin: np.ndarray, vmax: np.ndarray)¶ Tanh calibration from two bounds and a reference value.
(263)¶\[\begin{split}\mfr(0, a, b, c, 1) &= v_{\max} \\ \mfr(r, a, b, c, 1) &= 1 \\ \mfr(1, a, b, c, 1) &= v_{\min}\end{split}\]Defining
\[q := \frac{v_{\max}-1}{v_{\max}-v_{\min}},\]the strictly positive sigmoid parameter solves
\[\frac{\tanh(cr)}{\tanh(c)}-q = 0,\]and belongs to the bracket
\[0 < c < \frac{\operatorname{arctanh}(q)}{r}.\]It follows that
(264)¶\[\begin{split}a &= v_{\max} \\ b &= \frac{v_{\max}-v_{\min}}{\tanh(c)}.\end{split}\]The analytical bracket is valid for calibration targets satisfying
\[0<r<1, \ v_{\max}>1>v_{\min}, \ r < \frac{v_{\max}-1}{v_{\max}-v_{\min}} <1.\]Warning
This calibration deliberately reproduces the functional form and normalization used in the original Scilab implementation. It should therefore be interpreted as a model-replication device rather than as a generally well-posed three-point sigmoid calibration. The calibration assumes
\[f(0) = v_{\max}, \ f(r) = 1, \ f(1) = v_{\min},\]with
\[f(x) = a - b\tanh(cx), \ c > 0.\]Several restrictions follow from this specification. First, the reference value is normalized to one and is not an independent calibration target. Second, because the hyperbolic tangent is not horizontally shifted, its inflection point is fixed at \(x=0\). Over \(x\in[0,1]\), the calibration therefore uses only one concave branch of the sigmoid. Consequently, not every otherwise coherent triplet \((r, v_{\min}, v_{\max})\) can be interpolated. Defining
\[q := \frac{v_{\max}-1}{v_{\max}-v_{\min}},\]a finite strictly positive solution for \(c\) requires
\[0 < r < 1,\ v_{\max} > 1 > v_{\min}, \ r < q < 1.\]The condition \(r<q\) is structural rather than numerical. It follows from the concavity of \(\tanh(cx)\) for \(x>0\). Inputs violating this condition do not correspond to a failure of the root solver; they lie outside the family of curves represented by this parameterization.
The limiting case \(r=q\) corresponds to \(c\to0\), i.e. to the linear limit, and is therefore excluded when a finite strictly positive curvature parameter is required.
The original Scilab calibration uses fixed inputs satisfying these restrictions and performs no explicit admissibility check. Allowing \(r\), \(v_{\min}\), and \(v_{\max}\) to vary therefore generalizes the original parameter values without enlarging the underlying functional family. Users supplying alternative bounds or reference rates are responsible for ensuring that the resulting calibration target remains admissible.
Finally, clipping or otherwise modifying \(v_{\min}\) or \(v_{\max}\) to enforce compatibility changes the requested calibration problem itself. Such preprocessing, if introduced, should therefore be understood as an explicit projection onto the admissible domain rather than as a harmless numerical safeguard.
- Parameters
r (numpy.ndarray) – Reference rate.
vmin (numpy.ndarray) – Magnitude value at \(r=1\).
vmax (numpy.ndarray) – Magnitude value at \(r=0\).
See also
- Example
>>> a, b, c = EmplBMagnitude._rate_tanh_bounds_calibrator( ... r=.2, vmin=.95, vmax=1.05 ... ) >>> a.item() 1.05 >>> b.item() 0.10087575919139345 >>> c.item() 2.7176753624893477
The three calibration conditions are satisfied.
>>> np.allclose(a + b*np.tanh(-c*.2), 1., rtol=.0, atol=1e-14) True >>> np.allclose(a + b*np.tanh(-c), .95, rtol=.0, atol=1e-14) True >>> np.allclose(a, 1.05, rtol=.0, atol=1e-14) True
A vectorized example.
>>> r = np.array([[[.2]], [[.3]], [[.4]]]) >>> vmin = np.array([[[.95]], [[.8]], [[.6]]]) >>> vmax = np.array([[[1.05]], [[1.2]], [[2.]]]) >>> a, b, c = EmplBMagnitude._rate_tanh_bounds_calibrator( ... r=r, vmin=vmin, vmax=vmax ... ) >>> a array([[[1.05]], [[1.2 ]], [[2. ]]]) >>> b array([[[0.1 ]], [[0.43]], [[1.44]]]) >>> c array([[[2.72]], [[1.69]], [[2.14]]])
Each calibration is independently recovered along the first axis.
>>> np.allclose( ... a + b*np.tanh(-c*r), np.ones_like(c), ... rtol=.0, atol=1e-14 ... ) True >>> np.allclose(a + b*np.tanh(-c), vmin, rtol=.0, atol=1e-14) True >>> np.allclose(a, vmax, rtol=.0, atol=1e-14) True
-
classmethod
_rate_tanh_bounds_root(cls, r: np.ndarray, q: np.ndarray, nit: int = 8)¶ Positive tanh bounds-calibration root evaluation.
The strictly positive solution to
\[\frac{\tanh(cr)}{\tanh(c)}=q\]can be characterized through the generalized second-kind Chebyshev relation
\[U_{\frac{2r}{1-r}} \left(\cosh((1-r)c)\right) = \frac{1+q}{1-q}.\]Defining
\[\begin{split}y &:= (1-r)c, \\ \nu &:= \frac{1+r}{1-r}, \\ \log(k) &:= \log(1+q)-\log(1-q),\end{split}\]the transformed root solves
\[G(y) := \log\left(\sinh(\nu y)\right) - \log\left(\sinh(y)\right) - \log(k) = 0.\]Its first two derivatives are
\[\begin{split}G'(y) &= \nu\coth(\nu y)-\coth(y), \\ G''(y) &= -\nu^2\text{csch}^2(\nu y) + \text{csch}^2(y).\end{split}\]The method applies a fixed number of Halley refinements,
\[y^{+} = y - \frac{2G(y)G'(y)}{2G'(y)^2-G(y)G''(y)}.\]After recovering
\[c = \frac{y}{1-r},\]one Newton correction is applied directly to the original equation
\[F(c) := \tanh(rc)-q\tanh(c)=0,\]using
\[F'(c) = r\left(1-\tanh^2(rc)\right) - q\left(1-\tanh^2(c)\right).\]This final correction reduces the residual in the original calibration equation after the logarithmically transformed Halley iterations.
\[c^{+} = c - \frac{F(c)}{F'(c)}.\]- Parameters
r (numpy.ndarray) – Reference rate.
q (numpy.ndarray) – Normalized distance between the reference value and the upper bound.
nit (int) – Number of Halley refinements preceding the single final Newton correction. Set to
8by default.
Note
The method is defined over calibration targets satisfying
\[0<r<q<1.\]For every fixed number of Halley refinements, including the final Newton correction, the implementation consists exclusively of smooth array operations wherever the transformed iterates remain strictly positive and the refinement denominators remain nonzero. It therefore remains compatible with automatic differentiation with respect to both \(r\) and \(q\) over any validated subdomain of \(0<r<q<1\).
The transformed initial approximation is derived from the local inverse expansion at \(q=r\). The chosen number of refinements should nevertheless be validated over the effective numerical domain of the model.
-
static
_rate_tanh_bounds_root_initial(r: np.ndarray, q: np.ndarray)¶ Positive initial approximation of the transformed root.
Defining
\[y=(1-r)c,\]the approximation follows from the local expansion
\[c^2 \sim \frac{3(q-r)} {r(1-r^2)} \ \text{as}\ q\to r^+.\]- Parameters
r (numpy.ndarray) – Reference rate.
q (numpy.ndarray) – Normalized distance between the reference value and the upper bound.
-
static
_log_sinh(x: np.ndarray)¶ Stable logarithm of the hyperbolic sine over positive inputs.
\[\log(\sinh(x)) = x + \log\left(1-\exp(-2x)\right) - \log(2), \ x>0.\]- Parameters
x (numpy.ndarray) – Strictly positive argument.
-
static
_coth(x: np.ndarray)¶ Hyperbolic cotangent over positive inputs.
\[\coth(x) = \frac{1+\exp(-2x)}{1-\exp(-2x)}, \ x>0.\]- Parameters
x (numpy.ndarray) – Strictly positive argument.
-
static
_csch2(x: np.ndarray)¶ Squared hyperbolic cosecant over positive inputs.
\[\text{csch}^2(x) = \frac{4\exp(-2x)}{\left(1-\exp(-2x)\right)^2}, \ x>0.\]- Parameters
x (numpy.ndarray) – Strictly positive argument.
-
static
-
class
iamax.library.PowCurvedNetPrice(sigma: float, urate_bias: float = 0.0)¶ 
Net-price curve abstraction, whose name stems from the generalization of the well established negative relationship between wages and local unemployment, a.k.a. the wage curve.
- Parameters
- Attributes
price_ref (float or numpy.ndarray) – Reference output price.
price_ref_star (float or numpy.ndarray) – Possibly updated reference output price.
urate_ref (float or numpy.ndarray) – Reference unemployment rate.
urate_bias (float or numpy.ndarray) – Additive unemployment-rate bias.
brate_ref (float or numpy.ndarray) – Biased reference unemployment rate, equal to
urate_refplusurate_bias.sigma (float or numpy.ndarray) – Output-price elasticity with respect to the biased reference-to-running unemployment-rate ratio.
Note
Such elasticity is assumed to measure the sensitivity of prices to changes in market conditions relative to a specific baseline, rather than simply the level of unemployment.
-
compute_calibrand_0(self, *, output_price: float, unemployment_rate: float)¶ Curve parametrization, performed such that
(265)¶\[\begin{split}\up^{*}_j &= \up_{j,t=0} \\ \tau_{\neg\hq, j}^{*} &= \tau_{\neg\hq, j,t=0}\end{split}\]where \(\up_{j,t=0}\) is the (producer net) price at \(t=0\) and \(\tau_{\neg\hq, j,t=0}\) the unemployment rate at \(t=0\).
- Parameters
output_price (float) – \(\up_j\), i.e. the \(j\)th \(1 \times 1\)
output_prices’s element.unemployment_rate (float) – \(\tau_{\neg\hq, j}\), i.e. the \(j\)th \(1 \times 1\)
unemployment_rates’s element.
- Example
>>> cnp = PowCurvedNetPrice(sigma=None) >>> cnp.compute_calibrand_0( ... output_price=1e2, unemployment_rate=.1 ... ) >>> cnp.price_ref 100.0 >>> cnp.price_ref_star 100.0 >>> cnp.urate_ref 0.1 >>> cnp.urate_bias 0.0
-
compute_calibrand_0_star(self, *, deflators_fisher_drates: np.ndarray)¶ Reference-output-price recomputation from its time-zero value and the second selected element of
deflators_fisher_drates, performed as(266)¶\[\up_j^{*} \leftarrow \up_{j,t=0} \left( 1+\mfp^{\text{drate}}_{\text{F},2} \right)\]- Parameters
deflators_fisher_drates (numpy.ndarray) – \((\bmfp^{\text{drate}}_{\text{F}, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times 2\) slice of
deflators_fisher_drates, whose second component is of interest.
-
output_price_computer(self, *, unemployment_rate: float, deflators_fisher: np.ndarray, output_price_drate: np.ndarray = 0.0, output_price_drate2: np.ndarray = 0.0)¶ Producer-net-price computation from the updated reference price, the current Fisher deflator, the two exogenous output-price differentials and the biased reference-to-running unemployment-rate ratio, denoted as
(267)¶\[\begin{split}\up_j &= \up^{*}_j ( 1 + \up^{\text{drate}}_j + \up^{\text{drate}^{ii}}_j ) \mfp_{\text{F}, j} \left( \frac{\tau_{\neg\hq, j}^{*} + b}{\tau_{\neg\hq, j} + b} \right)^{\sigma_j} \\ &= \mfr\left( s=\up^{*}_j ( 1 + \up^{\text{drate}}_j + \up^{\text{drate}^{ii}}_j ) \mfp_{\text{F}, j}, c=\sigma_j, f=\frac{\tau_{\neg\hq, j}^{*} + b}{\tau_{\neg\hq, j} + b} \right)\end{split}\]where the star superscript, i.e. \(.^{*}\), and the \(j\) subscript, i.e. \(._{j}\), respectively stand for the idea of “reference” and that of being \(j\)th, \(\up\) is the (producer net) price, \(\tau_{\neg\hq}\) is the rate of unemployment, \(\sigma\) is the elasticity of \(\up\) with respect to the biased reference-to-running unemployment-rate ratio, \(b\) is the unemployment-rate bias parameter, \(\mfp_{\text{F}}\) is the (chained) Fisher deflator and \(\mfr(.)\) is the function detailed in Eq.257.
- Reference:
This formulation is taken (and particularized) from KLEM’s equation 12b, the consumer price index put aside.
- Parameters
unemployment_rate (float) – \(\tau_{\neg\hq, j}\), i.e. the \(j\)th \(1 \times 1\)
unemployment_rates’s element.deflators_fisher (numpy.ndarray) – \((\bmfp_{\text{F}, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times 2\) slice of
deflators_fisher, whose first component is of interest.output_price_drate (float) – \(\up^{\text{drate}}_j\), i.e. the \(j\)th \(1 \times 1\)
producer_net_prices_drates’s element. Set to .0 by default.output_price_drate2 (float) – \(\up^{\text{drate}^{ii}}_j\), i.e. the \(j\)th \(1 \times 1\)
producer_net_prices_drates2’s element. Set to .0 by default.
Important
This method relies on the structure of its argument, as outlined in the description of argument
deflators_fisher.- Example
>>> cnp = PowCurvedNetPrice(sigma=.2) >>> cnp.compute_calibrand_0( ... output_price=100, unemployment_rate=.1 ... ) >>> cnp.output_price_computer( ... unemployment_rate = .1490099501, ... deflators_fisher = np.array([[1.07220603770351, np.nan]]) ... ) array([[99.]]) >>> cnp.output_price_computer( ... unemployment_rate = .0489899499000005, ... deflators_fisher = np.array([[0.87567464071516, np.nan]]) ... ) array([[101.]])
Let’s vectorize the above example.
>>> vcnp = PowCurvedNetPrice( ... sigma=np.array([ ... [[ .2]], [[ .1]], [[-.2]] ... ]) ... ) >>> vcnp.compute_calibrand_0( ... output_price=np.array([ ... [[100.]], [[200.]], [[50.]] ... ]), ... unemployment_rate=np.array([ ... [[.1]], [[.2]], [[.3]] ... ]), ... ) >>> vcnp.output_price_computer( ... unemployment_rate=np.array([ ... [[.2]], [[.1]], [[.6]] ... ]), ... deflators_fisher=np.array([ ... [[1., np.nan]], ... [[1., np.nan]], ... [[1., np.nan]], ... ]), ... ) array([[[ 87.06]], [[214.35]], [[ 57.43]]])
-
class
iamax.library.TanhCurvedNetPrice(sigma: float)¶ 
Yet another net-price curve abstraction.
- Parameters
sigma (float) – Non-positive local price elasticity with respect to the underlying rate, at the reference rate.
- Attributes
a (numpy.ndarray) – Calibrated unscaled magnitude value at a rate of \(0\).
b (numpy.ndarray) – Calibrated unscaled sigmoid amplitude parameter.
c (numpy.ndarray) – Calibrated magnitude sigmoid parameter.
sigma (numpy.ndarray) – Non-positive local price elasticity with respect to the underlying rate, at the reference rate.
reference_real_price (numpy.ndarray) – Reference output price divided by the corresponding reference Fisher price index.
Note
The calibration is defined for a non-positive local elasticity and a strictly positive reference rate.
Warning
A null reference unemployment rate \(\tau_{\neg\hq, j}^{*}\) is incompatible with this specification. Indeed, the local elasticity used for calibration,
\[\frac{\tau_{\neg\hq, j}^{*}}{ \mfr(\tau_{\neg\hq, j}^{*},a,b,c,1) } \frac{ \partial \mfr(\tau_{\neg\hq, j}^{*},a,b,c,1) }{ \partial \tau_{\neg\hq, j}^{*} },\]is necessarily equal to \(0\) at \(\tau_{\neg\hq, j}^{*}=0\) whenever the curve has a finite derivative there. A strictly negative target elasticity therefore cannot be matched. A null target elasticity does not solve the identification problem either: at a null reference rate, the elasticity condition provides no information with which to identify the sigmoid parameter \(c\).
Consequently, this specification should not be selected when the reference unemployment rate is null; a specification identified from another local or benchmark condition should be used instead.
Attention
Elasticities are assumed to be non-positive. For
\[0 < \sigma < W_0\left(\exp(-1)\right),\]two distinct real calibrations exist, respectively associated with the principal and lower real branches of the Lambert function. At the upper bound the two solutions merge, while no real calibration satisfying \(b=a\) exists above it. Restricting \(\sigma\) to non-positive values consequently ensures both a nonnegative Lambert-function argument and a unique real calibration.
-
compute_calibrand_0(self, *, output_price: float, unemployment_rate: float, deflators_fisher: np.ndarray)¶ Curve parametrization, performed such that
(268)¶\[\begin{split}\up^{*}_j &= \up_{j,t=0} \\ \tau_{\neg\hq, j}^{*} &= \tau_{\neg\hq, j,t=0} \\ \mfp_{\text{F}, j}^{*} &= \mfp_{\text{F}, j,t=0} \\ b_j &= a_j \\ \mfr\left( \tau_{\neg\hq, j}^{*}, a_j, b_j, c_j, 1 \right) &= 1 \\ \left. \frac{\tau_{\neg\hq, j}}{ \mfr\left( \tau_{\neg\hq, j}, a_j, b_j, c_j, 1 \right) } \frac{ \partial \mfr\left( \tau_{\neg\hq, j}, a_j, b_j, c_j, 1 \right) }{ \partial \tau_{\neg\hq, j} } \right|_{ \tau_{\neg\hq, j} =\tau_{\neg\hq, j}^{*} } &= \sigma_j\end{split}\]where the star superscript, i.e. \(.^{*}\), and the \(j\) subscript, i.e. \(._j\), respectively stand for the ideas of being a reference value and of being \(j\)th, \(t=0\) denotes the reference period, \(\up_j\) is the (producer net) output price, \(\tau_{\neg\hq, j}\) is the unemployment rate, \(\mfp_{\text{F}, j}\) is the relevant (chained) Fisher price index, \(a_j\) is the unscaled curve value at a rate of \(0\), \(b_j\) is its unscaled sigmoid amplitude parameter, \(c_j\) is its sigmoid parameter, \(\mfr(.)\) is the function defined in Eq.258, and \(\sigma_j\) is the local output-price elasticity with respect to the unemployment rate, evaluated at the reference unemployment rate.
Note
The restriction \(b_j=a_j\) identifies the three curve parameters jointly with the reference-value normalization and the local-elasticity condition. The normalization of \(\mfr(.)\) to \(1\) at the reference rate ensures that the unscaled curve does not alter the reference output price.
- Parameters
output_price (float) – \(\up_j\), i.e. the \(j\)th \(1 \times 1\)
output_prices’s element.unemployment_rate (float) – \(\tau_{\neg\hq, j}\), i.e. the \(j\)th \(1 \times 1\)
unemployment_rates’s element.deflators_fisher (numpy.ndarray) – \((\bmfp_{\text{F}, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
deflators_fisher, whose first component only is of interest.
Attention
In the full-width representation, \(|\mcI_j|=2\). A shorter trailing axis remains admissible whenever it contains the first component used by the current method.
Important
This method relies on the structure of its argument, as outlined in the description of argument
deflators_fisher.- Example
>>> cnp = TanhCurvedNetPrice(sigma=-.55) >>> cnp.compute_calibrand_0( ... output_price=943.5509, unemployment_rate=.2, ... deflators_fisher=np.array([[1.13748, np.nan]]) ... ) >>> cnp._reference_price.item() 943.5509 >>> cnp._reference_rate.item() 0.2 >>> cnp._reference_index.item() 1.13748 >>> cnp.reference_real_price.item() 829.5098814924218 >>> cnp.a.item() 1.6102140203583628 >>> cnp.b.item() 1.6102140203583628 >>> cnp.c.item() 1.9942499710804265
-
output_price_computer(self, *, unemployment_rate: float, deflators_fisher: np.ndarray, deflators_fisher_drates: np.ndarray|float = 0.0)¶ Producer-net-price computation from the reference real price, the current Fisher deflator and its exogenous differential, and the calibrated unemployment-rate tanh curve, denoted as
(269)¶\[\begin{split}\up_j &= \up^{*}_j \frac{ \mfp_{\text{F}, j} }{ \mfp_{\text{F}, j}^{*} }\left( 1 + \mfp^{\text{drate}}_{\text{F}, j} \right)\left( a_j + b_j \tanh(-c_j \tau_{\neg\hq, j}) \right) \\ &= \mfr\left( r=\tau_{\neg\hq, j}, a=a_j, b=b_j, c=c_j, s=\up^{*}_j \frac{ \mfp_{\text{F}, j} }{ \mfp_{\text{F}, j}^{*} }\left( 1 + \mfp^{\text{drate}}_{\text{F}, j} \right) \right)\end{split}\]where the star superscript, i.e. \(.^{*}\), and the \(j\) subscript, i.e. \(._j\), respectively stand for the ideas of being a reference value and of being \(j\)th, \(\up_j\) is the (producer net) output price, \(\tau_{\neg\hq,j}\) is the unemployment rate, \(\mfp_{\text{F},j}\) is the relevant (chained) Fisher price index, \(\mfp^{\text{drate}}_{\text{F},j}\) is its exogenous differential, \(a_j\), \(b_j\) and \(c_j\) are the calibrated tanh-curve parameters, and \(\mfr(.)\) is the function defined in Eq.258.
- Parameters
unemployment_rate (float) – \(\tau_{\neg\hq, j}\), i.e. the \(j\)th \(1 \times 1\)
unemployment_rates’s element.deflators_fisher (numpy.ndarray) – \((\bmfp_{\text{F}, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
deflators_fisher, whose first component is of interest.deflators_fisher_drates (numpy.ndarray or float) – \((\bmfp^{\text{drate}}_{\text{F}, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
deflators_fisher_drates, whose first component is of interest. Set to0by default.
Attention
In the full-width representation, \(|\mcI_j|=2\). A shorter trailing axis remains admissible whenever it contains the first component used by the current method.
- Example
A rate-decreasing normalized example first.
>>> invariant = { ... 'deflators_fisher': np.array([[1., np.nan]]) ... } >>> cnp = TanhCurvedNetPrice(sigma=-.55) >>> cnp.compute_calibrand_0( ... unemployment_rate=.2, output_price=1., **invariant ... ) >>> cnp.output_price_computer( ... unemployment_rate=.5, **invariant ... ) array([[0.39]]) >>> cnp.output_price_computer( ... unemployment_rate=.2, **invariant ... ) array([[1.]]) >>> cnp.output_price_computer( ... unemployment_rate=.0, **invariant ... ) array([[1.61]])
Yet another (scaled) example.
>>> cnp = TanhCurvedNetPrice(sigma=-.55) >>> p0 = 943.5508481986847 >>> d0 = np.array([[1.1374749692500363, np.nan]]) >>> cnp.compute_calibrand_0( ... output_price=p0, ... unemployment_rate=.2, ... deflators_fisher=d0, ... ) >>> r = .05 >>> d = np.array([[1.1280702850130508, np.nan]]) >>> cnp.output_price_computer( ... unemployment_rate=r, deflators_fisher=d, ... deflators_fisher_drates=np.zeros((1, 2)) ... ) array([[1357.01]])
Let’s vectorize the above example.
>>> cnp = TanhCurvedNetPrice( ... sigma=np.array([ ... [[-.55]], [[-.55]], [[-.1]] ... ]) ... ) >>> cnp.compute_calibrand_0( ... deflators_fisher=np.stack((d0, d0, d0)), ... unemployment_rate=np.array([ ... [[.2]], [[.2]], [[.1]] ... ]), ... output_price=np.array([ ... [[p0]], [[.1*p0]], [[p0]] ... ]) ... ) >>> cnp.output_price_computer( ... deflators_fisher=np.stack((d, d, d)), ... unemployment_rate=np.array([ ... [[r]], [[r]], [[r]] ... ]) ... ) array([[[1357.01]], [[ 135.7 ]], [[ 982.7 ]]])
-
class
iamax.library.NetPriceTanhCurvedMultiplier(*, min: float, max: float)¶ 
Net-price’s multiplier abstraction.
- Parameters
- Attributes
min_ (float or numpy.ndarray) – Multiplier value at an idle rate of \(1\).
max_ (float or numpy.ndarray) – Multiplier value at an idle rate of \(0\).
a (numpy.ndarray) – Calibrated unscaled multiplier value at an idle rate of \(0\), equal to
max_.b (numpy.ndarray) – Calibrated unscaled sigmoid amplitude parameter, determined jointly by
min_,max_and the reference idle rate.c (numpy.ndarray) – Calibrated strictly positive sigmoid parameter, determined such that the multiplier equals \(1\) at the reference idle rate while matching
max_at an idle rate of \(0\) andmin_at an idle rate of \(1\).
Note
To learn more about the underlying narrative, refer to Bibas et al.’s (2016) IMAClim-R model documentation (version 1.1).
-
compute_calibrand_0(self, *, idle_rates_transpose: np.ndarray)¶ Multiplier parametrization, performed such that
(270)¶\[\begin{split}\mfr(1, a, b, c, 1) &= m_{\min} \\ \mfr\left(\btau_{\neg q,2}^{*}, a, b, c, 1\right) &= 1 \\ \mfr(0, a, b, c, 1) &= m_{\max}\end{split}\]where \(\btau_{\neg q,2}^{*}\) is the second component of the reference idle-rate slice, \(m_{\min}\) and \(m_{\max}\) respectively denote the multiplier values at idle rates of \(1\) and \(0\), and \(\mfr(.)\) is as defined in Eq.258.
- Parameters
idle_rates_transpose (numpy.ndarray) – \((\btau^{T}_{\neg q, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times 2\)
idle_rates’s slice, whose second component only is of interest.
Important
This method relies on the structure of its argument, as outlined in the description of argument
idle_rates_transpose.
-
output_price_computer(self, *, input_prices: np.ndarray, idle_rates_transpose: np.ndarray)¶ Utilization-adjusted net-price computation, obtained by multiplying the selected input price by the calibrated idle-rate multiplier.
The resulting \(1 \times 1\) magnitude is denoted as
(271)¶\[\begin{split}\up_j &= \tbp_{1,j}(a_j + b_j \tanh(-c_j \btau_{\neg q,2})) \\ &= \mfr(r=\btau_{\neg q,2}, a=a_j, b=b_j, c=c_j, s=\tbp_{1,j})\end{split}\]where \(\up_j\) is the utilization-adjusted net price, \(\tbp_{1,j}\) is the first selected input price, \(\btau_{\neg q,2}\) is the second selected idle-rate component, \(a_j\), \(b_j\) and \(c_j\) are the calibrated multiplier parameters, and \(\mfr(.)\) is the function defined in Eq.258. The scale argument \(s\) is not calibrated: it is set equal to the selected input price \(\tbp_{1,j}\).
- Parameters
input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
input_prices, whose first component only is of interest.idle_rates_transpose (numpy.ndarray) – \((\btau^{T}_{\neg q, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
idle_rates, whose second component only is of interest.
Important
As outlined in the parameters’ descriptions, the current method relies on the structure of its arguments.
Attention
In the full-width representation, \(|\mcI_j|=2\). The
input_pricestrailing axis may be shorter because only its first component is consumed, whereasidle_rates_transposemust contain at least its first two components.- Example
>>> npcm = NetPriceTanhCurvedMultiplier(min=.95, max=1.05) >>> npcm.compute_calibrand_0( ... idle_rates_transpose=np.array([[np.nan, .2]]) ... ) >>> npcm.a.item() 1.05 >>> npcm.b.item() 0.10087575919139345 >>> npcm.c.item() 2.7176753624893477 >>> npcm.output_price_computer(**(ut1 := dict( ... input_prices = np.array([[1., np.nan]]), ... idle_rates_transpose = np.array([[np.nan, .0]]), ... ))) array([[1.05]]) >>> npcm.output_price_computer(**(ut2 := dict( ... input_prices = np.array([[1., np.nan]]), ... idle_rates_transpose = np.array([[np.nan, .5]]), ... ))) array([[0.96]]) >>> npcm.output_price_computer(**(ut3 := dict( ... input_prices = np.array([[1., np.nan]]), ... idle_rates_transpose = np.array([[np.nan, 1.]]), ... ))) array([[0.95]]) >>> npcm.output_price_computer(**(ut4 := dict( ... input_prices = np.array([[1., np.nan]]), ... idle_rates_transpose = np.array([[np.nan, .2]]), ... ))).item() 1.0
Another (less conservative) example.
>>> npcm = NetPriceTanhCurvedMultiplier(min=.8, max=30) >>> npcm.compute_calibrand_0( ... idle_rates_transpose = np.array([[np.nan, .2]]) ... ) >>> npcm.output_price_computer(**ut1).item() 30.0 >>> npcm.output_price_computer(**ut2).item() 0.8000404277688098 >>> npcm.output_price_computer(**ut3).item() 0.8000000000000007 >>> npcm.output_price_computer(**ut4).item() 1.0
Let’s vectorize the above example.
>>> vnpcm = NetPriceTanhCurvedMultiplier( ... min=np.array([[[.95]], [[.8]], [[.6]]]), ... max=np.array([[[1.05]], [[1.2]], [[2.]]]), ... ) >>> idle_rates_ref = np.array([ ... [[np.nan, .2]], ... [[np.nan, .3]], ... [[np.nan, .4]], ... ]) >>> vnpcm.compute_calibrand_0( ... idle_rates_transpose = idle_rates_ref ... ) >>> vnpcm.a array([[[1.05]], [[1.2 ]], [[2. ]]]) >>> vnpcm.b array([[[0.1 ]], [[0.43]], [[1.44]]]) >>> vnpcm.c array([[[2.72]], [[1.69]], [[2.14]]]) >>> vnpcm.output_price_computer( ... idle_rates_transpose = idle_rates_ref, ... input_prices=np.array([ ... [[1., np.nan]], ... [[2., np.nan]], ... [[3., np.nan]], ... ]), ... ) array([[[1.]], [[2.]], [[3.]]])
-
class
iamax.library.TanhCMultipliedTanhCNetPrice(*, sigma: float, m_min: float, m_max: float)¶ Multiplied net-price curve abstraction.
- Parameters
- Attributes
pricecurve (TanhCurvedNetPrice) – Internally composed tanh-curved net-price abstraction.
multiplier (NetPriceTanhCurvedMultiplier) – Internally composed utilization-based net-price multiplier.
Note
This class internally makes use of
TanhCurvedNetPriceandNetPriceTanhCurvedMultiplierthrough composition.- Example
>>> o = TanhCMultipliedTanhCNetPrice( ... **dict.fromkeys(('sigma', 'm_min', 'm_max'), np.nan) ... ) >>> isinstance(o.pricecurve, TanhCurvedNetPrice) True >>> isinstance(o.multiplier, NetPriceTanhCurvedMultiplier) True
>>> invariants = dict( ... output_price=1., unemployment_rate=.2, ... deflators_fisher=np.array([[1., np.nan]]), ... idle_rates_transpose=np.array([[np.nan, .2]]), ... )
>>> o1 = TanhCMultipliedTanhCNetPrice( ... sigma=-.55, m_min=.95, m_max=1.05, ... ) >>> o1.compute_calibrand_0(**invariants) >>> o1.multiplier.a.item() 1.05 >>> o1.multiplier.b.item() 0.10087575919139345 >>> o1.multiplier.c.item() 2.7176753624893477 >>> o1.pricecurve.a.item() 1.6102140203583628 >>> o1.pricecurve.b.item() 1.6102140203583628 >>> o1.pricecurve.c.item() 1.9942499710804265
>>> o2 = TanhCMultipliedTanhCNetPrice( ... sigma=-.55, m_min=.8, m_max=30., ... ) >>> o2.compute_calibrand_0(**invariants) >>> o2.multiplier.a.item() 30.0 >>> o2.multiplier.b.item() 29.200000000027988 >>> o2.multiplier.c.item() 14.18330816758009 >>> o2.pricecurve.a.item() 1.6102140203583628 >>> o2.pricecurve.b.item() 1.6102140203583628 >>> o2.pricecurve.c.item() 1.9942499710804265
-
compute_calibrand_0(self, *, output_price: float, unemployment_rate: float, deflators_fisher: np.ndarray, idle_rates_transpose: np.ndarray)¶ Composite parametrization, performed as explained in Eq.268 and Eq.270.
Note
This method internally resorts to
compute_calibrand_0()andcompute_calibrand_0().- Parameters
output_price (float) – \(\up_j\), i.e. the \(j\)th \(1 \times 1\)
output_prices’s element.unemployment_rate (float) – \(\tau_{\neg \hq, j}\), i.e. the \(j\)th \(1 \times 1\)
unemployment_rates’s element.deflators_fisher (numpy.ndarray) – \((\bmfp_{\text{F}, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
deflators_fisher, whose first component only is of interest.idle_rates_transpose (numpy.ndarray) – \((\btau^{T}_{\neg q, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
idle_rates, whose second component only is of interest.
Attention
In the full-width model representation, \(|\mcI_j|=3\). A shorter trailing axis remains admissible provided that
deflators_fishercontains its first component andidle_rates_transposeits first two components.Important
This method relies on the structure of its argument, as outlined in the description of arguments
deflators_fisherandidle_rates_transpose.- Example
>>> o = TanhCMultipliedTanhCNetPrice( ... sigma=-.55, m_min=.95, m_max=1.05, ... ) >>> o.compute_calibrand_0( ... output_price=943.55, ... unemployment_rate=.2, ... deflators_fisher=np.array([ ... [1.14, np.nan, np.nan] ... ]), ... idle_rates_transpose=np.array([ ... [np.nan, .2, np.nan] ... ]) ... ) >>> (cnp := o.pricecurve)._reference_price.item() 943.55 >>> cnp._reference_rate.item() 0.2 >>> cnp._reference_index.item() 1.14 >>> cnp.reference_real_price.item() 827.6754385964913
-
output_price_computer(self, *, unemployment_rate: float, idle_rates_transpose: np.ndarray, deflators_fisher: np.ndarray, deflators_fisher_drates: np.ndarray)¶ Composite producer-net-price computation, obtained by applying the calibrated unemployment-rate price curve and the calibrated utilization-based multiplier, denoted as
(272)¶\[\begin{split}\up_j &= \up^{*}_j \frac{\mfp_{\text{F},j}}{\mfp_{\text{F},j}^{*}} \left(1+\mfp^{\text{drate}}_{\text{F},j}\right) \left( a^{\mathrm p}_j + b^{\mathrm p}_j \tanh\left( -c^{\mathrm p}_j\tau_{\neg\hq,j} \right) \right) \left( a^{\mathrm m}_j + b^{\mathrm m}_j \tanh\left(-c^{\mathrm m}_j\btau_{\neg q,2}\right) \right) \\ &= \mfr\left( r=\btau_{\neg q,2}, a=a^{\mathrm m}_j, b=b^{\mathrm m}_j, c=c^{\mathrm m}_j, s=\mfr\left( r=\tau_{\neg\hq,j}, a=a^{\mathrm p}_j, b=b^{\mathrm p}_j, c=c^{\mathrm p}_j, s=\up^{*}_j \frac{\mfp_{\text{F},j}}{\mfp_{\text{F},j}^{*}} \left(1+\mfp^{\text{drate}}_{\text{F},j}\right) \right) \right)\end{split}\]where superscripts \(\mathrm p\) and \(\mathrm m\) respectively identify the parameters of the price curve and of the utilization-based multiplier, \(\tau_{\neg\hq,j}\) is the unemployment rate, \(\btau_{\neg q,2}\) is the second selected idle-rate component, \(\up_j^{*}\) is the reference output price, \(\mfp_{\text{F},j}\) and \(\mfp_{\text{F},j}^{*}\) are the current and reference Fisher price indices, and \(\mfp^{\text{drate}}_{\text{F},j}\) is the current exogenous Fisher-deflator differential.
- Parameters
unemployment_rate (float) – \(\tau_{\neg\hq,j}\), i.e. the \(j\)th \(1 \times 1\)
unemployment_rates’s element.idle_rates_transpose (numpy.ndarray) – \((\btau^{T}_{\neg q, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
idle_rates, whose second component only is of interest.deflators_fisher (numpy.ndarray) – \((\bmfp_{\text{F}, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
deflators_fisher, whose first component is of interest.deflators_fisher_drates (numpy.ndarray) – \((\bmfp^{\text{drate}}_{\text{F}, k})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
deflators_fisher_drates, whose first component is of interest.
Attention
In the full-width model representation, \(|\mcI_j|=3\). Shorter trailing axes remain admissible whenever they contain every component used by the current method.
Important
This method relies on the structure of its arguments, as outlined in the descriptions of arguments
idle_rates_transpose,deflators_fisheranddeflators_fisher_drates.- Example
>>> tcmp = TanhCMultipliedTanhCNetPrice( ... sigma=-.55, ... m_min=.95, ... m_max=1.05, ... ) >>> tcmp.compute_calibrand_0( ... output_price = 943.55085, ... unemployment_rate = .2, ... deflators_fisher = np.array([[1.13748]]), ... idle_rates_transpose = np.array([[np.nan, .2]]), ... ) >>> tcmp.output_price_computer( ... unemployment_rate = .2, ... deflators_fisher = np.array([[1.13748]]), ... deflators_fisher_drates = np.zeros((1, 1)), ... idle_rates_transpose = np.array([[np.nan, .2]]), ... ).item() 943.5508500000001 >>> tcmp.output_price_computer( ... unemployment_rate = .05, ... idle_rates_transpose = np.array([[np.nan, .5]]), ... deflators_fisher = np.array([[1.12807]]), ... deflators_fisher_drates = np.zeros((1, 1)) ... ).item() 1304.92286535119
Let’s vectorize the above example.
>>> vtcmp = TanhCMultipliedTanhCNetPrice( ... sigma=np.array([[[-.55]], [[-.1]], [[-.3]]]), ... m_min=np.array([[[.95]], [[.8]], [[.6]]]), ... m_max=np.array([[[1.05]], [[1.2]], [[2.]]]), ... ) >>> unemployment_rates_ref = np.array([[[.2]], [[.1]], [[.15]]]) >>> deflators_fisher_ref = np.array([ ... [[1., np.nan, np.nan]], ... [[1., np.nan, np.nan]], ... [[1., np.nan, np.nan]], ... ]) >>> idle_rates_ref = np.array([ ... [[np.nan, .2, np.nan]], ... [[np.nan, .3, np.nan]], ... [[np.nan, .4, np.nan]], ... ]) >>> output_prices_ref = np.array([[[100.]], [[200.]], [[50.]]]) >>> output_prices_ref array([[[100.]], [[200.]], [[ 50.]]]) >>> vtcmp.compute_calibrand_0( ... output_price=output_prices_ref, ... unemployment_rate=unemployment_rates_ref, ... deflators_fisher=deflators_fisher_ref, ... idle_rates_transpose=idle_rates_ref, ... )
The three reference output prices are independently recovered.
>>> vtcmp.output_price_computer( ... unemployment_rate=unemployment_rates_ref, ... idle_rates_transpose=idle_rates_ref, ... deflators_fisher=deflators_fisher_ref, ... deflators_fisher_drates=np.zeros((3, 1, 3)), ... ) array([[[100.]], [[200.]], [[ 50.]]])
Running rates and price indices may then differ independently along the first axis.
>>> vtcmp.output_price_computer( ... unemployment_rate=np.array([ ... [[.05]], [[.2]], [[.1]] ... ]), ... idle_rates_transpose=np.array([ ... [[np.nan, .5, np.nan]], ... [[np.nan, .1, np.nan]], ... [[np.nan, .8, np.nan]], ... ]), ... deflators_fisher=np.array([ ... [[1.1, np.nan, np.nan]], ... [[.9, np.nan, np.nan]], ... [[1.2, np.nan, np.nan]], ... ]), ... deflators_fisher_drates=np.zeros((3, 1, 3)), ... ) array([[[153.4 ]], [[183.03]], [[ 43.05]]])
-
class
iamax.library.LaborMarket¶ 
s/e.
-
class
iamax.library.UniformProductivityPremia¶ Uniformly solved productivity premia.
-
static
output_volume_rooter(ioq_productivities_drates2: np.ndarray)¶ s/e., \(1 \times 1\) zero(s).
- Parameters
ioq_productivities_drates2 (numpy.ndarray) – \((\balpha^{-1,\ \text{drate}_{kk,j}})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI_j| \times |\mcI_j|\)
ioq_productivities_drates2’s (diagonal) square slice.- Example
>>> a = np.array([0, 1., .2]) * np.identity(3) >>> UniformProductivityPremia.output_volume_rooter( ... ioq_productivities_drates2=a ... ) array([[0.71, 0.71, 0.71]])
Let’s vectorize the above example.
>>> (v := np.stack((a, np.identity(3)))) array([[[0. , 0. , 0. ], [0. , 1. , 0. ], [0. , 0. , 0.2]], [[1. , 0. , 0. ], [0. , 1. , 0. ], [0. , 0. , 1. ]]]) >>> UniformProductivityPremia.output_volume_rooter( ... ioq_productivities_drates2=v ... ) array([[[0.71, 0.71, 0.71]], [[0. , 0. , 0. ]]])
-
static
-
class
iamax.library.UniformGhoshAllocationPremia¶ Uniformly solved GhoshAllocation premia.
-
static
output_volume_rooter(ioq_shares_drates2: np.ndarray)¶ s/e., \(1 \times 1\) zero(s).
- Parameters
ioq_shares_drates2 (numpy.ndarray) – \((\bbeta^{\text{drate}^{ii}}_{kk,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcI_j| \times |\mcI_j|\)
ioq_shares_drates2’s slice.- Example
>>> a = np.array([0, 1., .2]) * np.identity(3) >>> UniformGhoshAllocationPremia.output_volume_rooter( ... ioq_shares_drates2=a ... ) array([[0.71, 0.71, 0.71]])
Let’s vectorize the above example.
>>> (v := np.stack((a, np.identity(3)))) array([[[0. , 0. , 0. ], [0. , 1. , 0. ], [0. , 0. , 0.2]], [[1. , 0. , 0. ], [0. , 1. , 0. ], [0. , 0. , 1. ]]]) >>> UniformGhoshAllocationPremia.output_volume_rooter( ... ioq_shares_drates2=v ... ) array([[[0.71, 0.71, 0.71]], [[0. , 0. , 0. ]]])
-
static
-
class
iamax.library.UniformPrice(price_transmitting: bool = False)¶ Uniformly equalized prices.
- Parameters
price_transmitting (bool) – Whether the price of the aggregate is to be granularly communicated. Set to
Falseby default.
-
compute_calibrand_0(self, *, output_volumes: np.ndarray, t: int = 0)¶ Ancillary method whose only goal is to compute the mask that specifies which elements are to be included when
producer_net_prices_rooter()is called.- Parameters
output_volumes (numpy.ndarray) – \((\ubq_k)_{k \in \mcI_j}\), i.e. a reconstructed slice of
output_volumes.t (int) – Year-targeting integer index. Cf.
t, i.e. a_ilocalizations’s integer element. To0by default.
- Example
>>> a = np.array([ ... [[0, 1., .2, 1.]], ... [[0, 1., 1., 2.]], ... [[0, 3., .4, 8.]], ... [[0, 1., 1., 1.]], ... ])
>>> pt = False >>> uu = UniformPrice(pt).compute_calibrand_0( ... output_volumes=a ... ) >>> uu._ix0, uu._trnsm_mask (1, True)
>>> pt = True >>> uu = UniformPrice(pt).compute_calibrand_0( ... output_volumes=a ... ) >>> uu._ix0, uu._trnsm_mask (0, True)
Let’s vectorize the above example, keeping in mind that the temporal axis must remain first (hence the use of
numpy.ndarray.swapaxesbelow).>>> v = np.stack((a + 1, a)).swapaxes(1, 0) >>> pt = np.array([[[True]], [[False]]]) >>> uu = UniformPrice(pt).compute_calibrand_0( ... output_volumes=v ... ) >>> uu._ix0 0 >>> uu._trnsm_mask array([[[[ True, True, True, True]], [[False, True, True, True]]]])
-
producer_net_prices_rooter(self, *, t: int, producer_net_prices: np.ndarray)¶ s/e.
- Parameters
t (int) – Year-targeting integer index. Cf.
t, i.e. a_ilocalizations’s integer element.producer_net_prices (numpy.ndarray) – \((\ubp_k)_{k \in \mcI_j}\), i.e. a reconstructed slice of
producer_net_prices.
See also
Important
Since it resorts to
t, the current method relies on the structure of its non-scalar arguments, as explained here.Note
This method is vectorization friendly over the
-3th axis, if any.- Example
>>> a = np.array([ ... [[0, 1., .2, 1.]], ... [[0, 1., 1., 2.]], ... [[0, 3., .4, 8.]], ... [[0, 1., 1., 1.]], ... ]) >>> UniformPrice().producer_net_prices_rooter( ... producer_net_prices=a, t=1 ... ) array([[[0.23]]]) >>> UniformPrice().producer_net_prices_rooter( ... producer_net_prices=a, t=2 ... ) array([[[0.59]]]) >>> UniformPrice().producer_net_prices_rooter( ... producer_net_prices=a, t=3 ... ) array([[[0.]]])
Let’s vectorize the above example, keeping in mind that the temporal axis must remain first (hence the use of
numpy.ndarray.swapaxesbelow).>>> (v := np.stack((a + 1, a)).swapaxes(1, 0)) array([[[[1. , 2. , 1.2, 2. ]], [[0. , 1. , 0.2, 1. ]]], [[[1. , 2. , 2. , 3. ]], [[0. , 1. , 1. , 2. ]]], [[[1. , 4. , 1.4, 9. ]], [[0. , 3. , 0.4, 8. ]]], [[[1. , 2. , 2. , 2. ]], [[0. , 1. , 1. , 1. ]]]]) >>> UniformPrice().producer_net_prices_rooter( ... producer_net_prices=v, t=2 ... ) array([[[[0.46]], [[0.59]]]]) >>> UniformPrice().producer_net_prices_rooter( ... producer_net_prices=v, t=3 ... ) array([[[[0.]], [[0.]]]])
-
class
iamax.library.UniformUnemployment¶ Uniformly unemployed capacities.
Note
We may think about labor when reading ‘unemployment’ but this class is absolutely agnostic regarding the very nature of the entities you assign them to.
-
static
unemployment_rates_rooter(t: int, unemployment_rates: np.ndarray)¶ s/e.
See also
Important
Although it resorts to
t, the current method does not rely on the structureunemployment_rates, as explained here.Note
This method is vectorization friendly over the
-3th axis, if any.- Example
>>> a = np.array([ ... [[.2, .1, .3]], ... [[.2, .2, .2]], ... ]) >>> UniformUnemployment.unemployment_rates_rooter( ... t=0, unemployment_rates=a ... ) array([[[0.3]]]) >>> UniformUnemployment.unemployment_rates_rooter( ... t=1, unemployment_rates=a ... ) array([[[9.66e-17]]])
Let’s vectorize the above example, keeping in mind that the temporal axis must remain first (hence the use of
numpy.ndarray.swapaxesbelow).>>> (v := np.stack((a, 2*a)).swapaxes(1, 0)) array([[[[0.2, 0.1, 0.3]], [[0.4, 0.2, 0.6]]], [[[0.2, 0.2, 0.2]], [[0.4, 0.4, 0.4]]]]) >>> UniformUnemployment.unemployment_rates_rooter( ... t=1, unemployment_rates=v ... ) array([[[[9.66e-17]], [[9.77e-17]]]])
-
static
-
class
iamax.library.ULaborMarket¶ 
s/e.
-
class
iamax.library.UMarket¶ 
s/e.
-
class
iamax.library.UUMarket¶ 
s/e.
-
class
iamax.library.TermsOfTrade(sigma: float)¶ Example case-denominated Terms of Trade.
- Parameters
sigma (float) – Elasticity to terms-of-trade of good exports.
-
compute_calibrand_0(self, *, arent_final: np.ndarray, are_only_final: np.ndarray, specific_producer_prices: np.ndarray, consumer_prices: np.ndarray, ioq_shares: np.ndarray)¶ Support the calibration of the constant scale factor implied in the terms-of-trade equation, denoted as
(273)¶\[A_X = \frac{q_{X(t=0)}}{q_{S(t=0)}} \left( \frac{p_{X(t=0)}}{p_{M(t=0)}} \right)^\sigma\]where \(q_{X(t=0)}/q_{S(t=0)}\) is the share of exported quantity with respect to that of the Armington aggregate, \(p_{X(t=0)}/p_{M(t=0)}\) the price ratio of the former against its imported counterpart and \(\sigma\) the elasticity to terms-of-trade of good exports, set at instantiation.
- Parameters
arent_final (numpy.ndarray) – \((\btxta_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
arent_final’s slice.are_only_final (numpy.ndarray) – \((\textbf{f}_k)_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
are_only_final’s slice.specific_producer_prices (numpy.ndarray) – \((\tbP^{T}_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
specific_producer_prices’s slice.consumer_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
consumer_prices’s slice.ioq_shares (numpy.ndarray) – \((\bbeta_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
ioq_shares’s slice.
-
output_volume_rooter(self, specific_producer_prices: np.ndarray, consumer_prices: np.ndarray, ioq_shares: np.ndarray, consumed_volumes_drates: np.ndarray)¶ Terms-of-trade based constraint regarding exported quantities, as follows
(274)¶\[\frac{q_{X(t)}}{q_{S(t)}} = A_X \left( \frac{p_{M(t)}}{p_{X(t)}} \right)^\sigma \left(1 + \epsilon_{X(t)}\right)\]- Parameters
specific_producer_prices (numpy.ndarray) – \((\tbP^{T}_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
specific_producer_prices’s slice.consumer_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
consumer_prices’s slice.ioq_shares (numpy.ndarray) – \((\bbeta_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
ioq_shares’s slice.consumed_volumes_drates (numpy.ndarray) – \((\bQ^{T, \text{drate}}_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
consumed_volumes_drates, one component of which echoes \(\epsilon_X\) above.
-
class
iamax.library.PTermsOfTrade¶ 
Partialized version of
TermsOfTrade- Parameters
sigma (float) – Elasticity to terms-of-trade of good exports.
-
compute_calibrand_0(self, *, arent_final: np.ndarray, are_only_final: np.ndarray, specific_producer_prices: np.ndarray, consumer_prices: np.ndarray, consumed_volumes: np.ndarray)¶ Support the calibration of the constant scale factor implied in the terms-of-trade equation, denoted as
(275)¶\[A_X = q_{X(t=0)} \left( \frac{p_{X(t=0)}}{p_{M(t=0)}} \right)^\sigma\]where \(q_{X(t=0)}\) is the consumed volume of exported quantity, \(p_{X(t=0)}/p_{M(t=0)}\) the price ratio of the latter against its imported counterpart and \(\sigma\) the elasticity to terms-of-trade of good exports, set at instantiation.
- Parameters
arent_final (numpy.ndarray) – \((\btxta_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
arent_final’s slice.are_only_final (numpy.ndarray) – \((\textbf{f}_k)_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
are_only_final’s slice.specific_producer_prices (numpy.ndarray) – \((\tbP^{T}_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
specific_producer_prices’s slice.consumer_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
consumer_prices’s slice.consumed_volumes (numpy.ndarray) – \((\bQ^{T}_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
consumed_volumes.
-
output_volume_rooter(self, specific_producer_prices: np.ndarray, consumer_prices: np.ndarray, consumed_volumes: np.ndarray, consumed_volumes_drates: np.ndarray)¶ Terms-of-trade based constraint regarding exported quantities, as follows
(276)¶\[q_{X(t)} = A_X \left( \frac{p_{M(t)}}{p_{X(t)}} \right)^\sigma \left(1 + \epsilon_{X(t)}\right)\]- Parameters
specific_producer_prices (numpy.ndarray) – \((\tbP^{T}_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
specific_producer_prices’s slice.consumer_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\)
consumer_prices’s slice.consumed_volumes (numpy.ndarray) – \((\bQ^{T}_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
consumed_volumes.consumed_volumes_drates (numpy.ndarray) – \((\bQ^{T, \text{drate}}_{k,j})_{k \in \mcI_j}\), i.e. a \(j\)th \(1 \times |\mcI_j|\) slice of
consumed_volumes_drates, one component of which echoes \(\epsilon_X\) above.
-
class
iamax.library.DynamicStock(delta: float, grpot: float = 0.0, dyear0: float = 1.0, rental_valued: bool = True)¶ Example case mobilized dynamic stock abstraction.
The class provides a common dynamic-stock representation whose computed
available_volumescan alternatively consist of stock volumes or of the corresponding volumes lost through deterioration over the considered periods. In the latter case, the underlying stock is internally recovered from the formerly computed deterioration volume and preceding contributory flow before applying the exact same stock dynamics.Quantities specific to initialization and its implicit prehistory are inferred once during calibration by
compute_calibrand_0(). Since entity-ownavailable_volumes_dratesare not servable to this cross-sectional calibrator, initialization and its implicit prehistory remain untransformed. Subsequent driving rates are applied dynamically byavailable_volume_computer().- Parameters
delta (float) – Annual deterioration rate.
grpot (float) – Annual growth potential. To
.0by default.dyear0 (float) – Yearly recurrence period of the flux under consideration at time
t=0. To1.by default.rental_valued (bool) – Whether the computed
available_volumesshould be expressed as stock volumes intended for valuation through an implicit rental price rather than as volumes lost through deterioration over the considered period. Set toTrueby default.
- Attributes
δ (float) – Annual deterioration rate.
g (float) – Annual growth potential.
ρ (float) –
dyear0-specific effective perpetuity rate associated with the initial contributory flow, used to infer its corresponding initial stock through infinite capitalization.γ_0 (float) – Survival factor over the initial flux recurrence period.
-
compute_calibrand_0(self, *, ordinal_volumes_transpose: np.ndarray)¶ Infers the untransformed initial stock and implicit prehistory subsequently mobilized by
available_volume_computer().Unlike
available_volume_computer(), this calibrator does not invoket. Its non-scalar argument therefore consists of a cross-section rather than of column-bound time series. Under the present dynamic-stock dependency structure, its first component is the initial contributory flow \(\mfq_{-1}\).Let
(277)¶\[\rho = (1 + \delta + g)^{(y_0-y_{-1})} - 1\]denote the effective perpetuity rate associated with the initial recurrence interval. The initial contributory flow yields
(278)¶\[\hq^{\text{stock}}_0 = \frac{\mfq_{-1}}{\rho},\]while reversing the stock accumulation identity gives its predecessor:
(279)¶\[\hq^{\text{stock}}_{-1} = \frac{\hq^{\text{stock}}_0-\mfq_{-1}}{ (1-\delta)^{(y_0-y_{-1})} }.\]The initial capacity can consequently be represented either as this initial stock or as the deterioration of its predecessor over the corresponding interval:
(280)¶\[\begin{split}\hq_0 = \begin{cases} \hq^{\text{stock}}_0, & \text{if is rental-valued}, \\ \hq^{\text{stock}}_{-1} \left[ 1-(1-\delta)^{(y_0-y_{-1})} \right], & \text{otherwise}. \end{cases}\end{split}\]Quantities required one period further below the stored temporal bound are inferred by preserving the initial contribution relative to the stock existing at the beginning of its transition. For a non-null initial contributory flow, this corresponds to
(281)¶\[\frac{\widetilde{\mfq}_{-1}}{\hq^{\text{stock}}_{-2}} = \frac{\mfq_{-1}}{\hq^{\text{stock}}_{-1}},\]where \(\widetilde{\mfq}_{-1}\) denotes the implicit preceding contribution. Combining this relationship with the initialization identities and analytically extending it to a potentially null \(\mfq_{-1}\) gives the equivalent linear forms
(282)¶\[\hq^{\text{stock}}_{-2} = \hq^{\text{stock}}_{-1}\frac{1-\rho}{\gamma_0}, \ \widetilde{\mfq}_{-1} = \rho\hq^{\text{stock}}_{-1}.\]These forms avoid the removable \(0/0\) singularity that would otherwise arise for a null initial contributory flow and therefore preserve its first-order differentiability. They also imply that the calibrated stock prehistory follows the geometric relationship
(283)¶\[\frac{\hq^{\text{stock}}_{-2}}{\hq^{\text{stock}}_{-1}} = \frac{\hq^{\text{stock}}_{-1}}{\hq^{\text{stock}}_0} = \frac{1-\rho}{\gamma_0}.\]The backcast therefore imposes no monotonic increase towards \(t=0\). In particular, whenever \((1-\rho)/\gamma_0>1\), predecessor stocks increase when moving backward in time, so that the corresponding forward trajectory is decreasing up to initialization:
(284)¶\[\hq^{\text{stock}}_{-2} > \hq^{\text{stock}}_{-1} > \hq^{\text{stock}}_0.\]Conversely, \((1-\rho)/\gamma_0<1\) implies an increasing stock trajectory towards \(t=0\), while equality implies a locally stationary one. These alternatives are implications of the calibrated perpetuity and survival factors rather than additional restrictions imposed on the backcast.
The resulting initial capacity, the two implicit predecessor stocks and the contribution entering the transition from \(t=-2\) to \(t=-1\) are attached to the instance.
- Parameters
ordinal_volumes_transpose (numpy.ndarray) – \((\bmfq^{T}_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
ordinal_volumes_transpose.
Note
This method is vectorization friendly over the
-3th axis, if any.
-
available_volume_computer(self, *, available_volumes: np.ndarray, available_volumes_drates: np.ndarray, ordinal_volumes: np.ndarray, dyears: np.ndarray, t: int)¶ Computes a \(1 \times 1\) capacity, denoted as \(\hq_t\), whose representation depends on
rental_valued’s truthiness:(285)¶\[\begin{split}\hq_t = \begin{cases} \hq^{\text{stock}}_t, & \text{if is rental-valued}, \\ \hq^{\text{stock}}_{t-1} \left[1 - (1 - \delta)^{(y_t - y_{t-1})}\right], & \text{otherwise}. \end{cases}\end{split}\]Hence \(\hq^{\text{stock}}_t\) denotes the underlying stock from which the returned \(\hq_t\) derives. When
rental_valued=False, \(\hq_t\) instead represents the volume of the preceding stock lost through deterioration over the corresponding period. Switchingrental_valuedthus changes only the representation returned by the method, not the stock trajectory underlying it.Initialization-specific quantities are inferred once beforehand by
compute_calibrand_0(). Since the entity-ownavailable_volumes_dratesseries is not available to that calibrator, initialization and its implicit prehistory remain untransformed. In particular,(286)¶\[\hq^{\text{stock}}_0 = \frac{\mfq_{-1}}{\rho},\]and
(287)¶\[\hq^{\text{stock}}_{-1} = \frac{\hq^{\text{stock}}_0 - \mfq_{-1}}{ (1 - \delta)^{(y_0-y_{-1})} }.\]The capacity returned at initialization consequently follows
(288)¶\[\begin{split}\hq_0 = \begin{cases} \hq^{\text{stock}}_0, & \text{if is rental-valued}, \\ \hq^{\text{stock}}_{-1} \left[ 1 - (1 - \delta)^{(y_0 - y_{-1})} \right], & \text{otherwise}. \end{cases}\end{split}\]For \(t > 0\), computing the next capacity first requires recovering the preceding underlying stock \(\hq^{\text{stock}}_{t-1}\) from formerly returned available volumes. When
rental_valued=True, these available volumes already consist of the required stock levels:(289)¶\[\hq^{\text{stock}}_{t-1} = \hq_{t-1}, \ \text{if is rental-valued}.\]Otherwise, the formerly returned capacity \(\hq_{t-1}\) consists of the deterioration of \(\hq^{\text{stock}}_{t-2}\) over the preceding period:
(290)¶\[\hq_{t-1} = \hq^{\text{stock}}_{t-2} \left[1 - (1 - \delta)^{(y_{t-1} - y_{t-2})}\right], \ \text{if isn't rental-valued}.\]The stock existing at the beginning of this deterioration period can therefore be recovered directly, without integrating the full formerly computed time series:
(291)¶\[\hq^{\text{stock}}_{t-2} = \frac{\hq_{t-1}}{ 1 - (1 - \delta)^{(y_{t-1} - y_{t-2})} }, \ \text{if isn't rental-valued}.\]Once \(\hq^{\text{stock}}_{t-2}\) has been recovered, the common stock recurrence directly yields its successor:
(292)¶\[\begin{split}\hq^{\text{stock}}_{t-1} = \hq^{\text{stock}}_{t-2} (1 - \delta)^{(y_{t-1} - y_{t-2})} + \begin{cases} \mfq_{-1}, & t = 1, \\ \mfq_{t-2} (1 + \hq^{\text{drate}}_{t-1}), & t > 1. \end{cases}\end{split}\]The lower-bound case thus uses the same untransformed initial contributory flow as the calibration itself. From subsequent observed transitions onward, the corresponding driving rates transform their contributory flows contemporaneously.
Once \(\hq^{\text{stock}}_{t-1}\) has either been directly retrieved or locally recovered from the preceding deterioration volume, the exact same stock dynamics apply under either representation:
(293)¶\[\hq^{\text{stock}}_t = \hq^{\text{stock}}_{t-1} (1 - \delta)^{(y_t - y_{t-1})} + \mfq_{t-1} (1 + \hq^{\text{drate}}_t), \ t>0.\]At \(t=0\), the same identity instead uses the untransformed \(\mfq_{-1}\) as its contributory term. The initial \(\hq^{\text{drate}}_0\) therefore does not alter either the calibrated initialization or its implicit prehistory, while subsequent driving rates are applied dynamically from \(t>0\) onward.
The resulting \(\hq^{\text{stock}}_t\) is returned directly when
rental_valued=True. Otherwise, the method returns the contemporaneous deterioration of \(\hq^{\text{stock}}_{t-1}\), as prescribed by Eq.285. The two settings thus expose the exact same underlying stock trajectory, respectively as stock levels and as the volumes lost through deterioration over successive considered intervals.- Parameters
available_volumes (numpy.ndarray) – \((\hbq_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcL| \times |\mcI_j|\)
available_volumes’s slice.available_volumes_drates (numpy.ndarray) – \((\hbq^{\text{drate}}_k)_{k \in \mcI_j}\), i.e. a \(j\)th \(|\mcL| \times |\mcI_j|\) slice of
available_volumes_drates.ordinal_volumes (numpy.ndarray) – \((\bmfq_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcL| \times |\mcI_j|\) slice of
ordinal_volumes.dyears (numpy.ndarray) – Number of years between successive time indices, i.e. \((y_t - y_{t-1})_t\) for \(t > 0\), with the first element set to
numpy.infsince the initial recurrence period is inherently unknown to the serving system, i.e.iamax, and therefore supplied through the instantiation argumentdyear0. Cf.dyears.t (int) – Year-targeting integer index. Cf.
t, i.e. a_ilocalizations’s integer element.
Important
Since
tis invoked, non-scalar arguments all consist of column-bound time series. Following the rules explained there, the first and third columns respectively refer to \(\hq\) and \(\mfq\), while the second refers to \(\hq^{\text{drate}}\).At the lower temporal bound, \(\mfq_{-1}\) is represented by the first stored contributory-flow value, so that the
-1index denotes its role in the initialization equations rather than an additional stored observation. Quantities required further below this bound follow the relative prehistory calibrated bycompute_calibrand_0(), withdyear0retained as the recurrence interval throughout this implicit range and no transformation byavailable_volumes_drates.This temporal convention also determines the indexing of
dyears.dyears[t']represents \(y_{t'}-y_{t'-1}\) and is therefore indexed by the destination of the corresponding stock transition. Hencedyear0applies to the transition from \(t=-1\) to \(t=0\) and, by convention, to still earlier implicit transitions. Att=1it substitutes for the unavailabledyears[0]value when recovering the preceding transition, whereas for \(t>1\) this interval is directly given bydyears[t-1]. In particular, att=2the preceding transition runs from \(t=0\) to \(t=1\) and therefore usesdyears[1], even though its originating stock is indexed byt-2=0.When
rental_valued=False, this local recovery of the underlying stock from a formerly computed deterioration volume additionally requires both non-null deterioration and survival over the corresponding period. Under strictly positive recurrence periods, this amounts to \(0 < \delta < 1\): null deterioration leaves the underlying stock unidentified from its deterioration volume, while complete deterioration makes the backward recurrence non-invertible.Note
This method is vectorization friendly over the
-3th axis, if any.- Example
Let’s first define the arrays awaited by the current method. We start with empty
available_volumes>>> avols = np.zeros((3, 1, 2)) >>> avols array([[[0., 0.]], [[0., 0.]], [[0., 0.]]])
and null companion driving rates, so that contributory flows are left untransformed.
>>> avols_drates = np.zeros_like(avols) >>> avols_drates array([[[0., 0.]], [[0., 0.]], [[0., 0.]]])
Finally, let’s consider the following contributory flows, assumed to derive from
ordinal_volumes.>>> ovols = np.array([ ... [[0., 280.]], ... [[0., 336.]], ... [[0., 0.]], ... ]) >>> ovols array([[[ 0., 280.]], [[ 0., 336.]], [[ 0., 0.]]])
Let’s consider irregular recurrence intervals, with a half-year first transition followed by a two-year one:
>>> dyears = np.array([np.inf, .5, 2.]) >>> dyears array([inf, 0.5, 2. ])
Let’s first compute
available_volumesas stock volumes. With a \(20\%\) annual deterioration rate and an \(8\%\) annual growth potential, the initial effective perpetuity rate amounts to \(28\%\), hence an underlying initial stock of \(280 / .28 = 1000\).Since the calls below bypass
iamax, let’s first manually provide the cross-section that the latter would serve tocompute_calibrand_0()during calibration:>>> ds = DynamicStock(delta=.2, grpot=.08).compute_calibrand_0( ... ordinal_volumes_transpose=ovols[0, ..., 1:], ... ) >>> for t in range(3): ... avols[t, ..., 0] = ds.available_volume_computer( ... available_volumes=avols, ... available_volumes_drates=avols_drates, ... ordinal_volumes=ovols, dyears=dyears, t=t, ... ) >>> avols array([[[1000. , 0. ]], [[1174.43, 0. ]], [[1087.63, 0. ]]])
Setting
rental_valuedtoFalseleaves this underlying stock trajectory unchanged but exposes the corresponding fixed-capital-consumption volumes instead.>>> favols = np.zeros_like(avols) >>> fds = DynamicStock( ... delta=.2, grpot=.08, rental_valued=False ... ).compute_calibrand_0( ... ordinal_volumes_transpose=ovols[0, ..., 1:] ... ) >>> for t in range(3): ... favols[t, ..., 0] = fds.available_volume_computer( ... available_volumes=favols, ... available_volumes_drates=avols_drates, ... ordinal_volumes=ovols, dyears=dyears, t=t, ... ) >>> favols array([[[180. , 0. ]], [[105.57, 0. ]], [[422.79, 0. ]]])
From
t=1onward, these fixed-capital-consumption volumes can be recovered directly from the formerly computed tock-valued available volumes using the deterioration factor orresponding to each irregular interval:>>> avols[:-1, ..., 0] * (1. - np.power(.8, dyears[1:, None])) array([[105.57], [422.79]]) >>> favols[1:, ..., 0] array([[105.57], [422.79]])
The same deterioration rule applies at initialization. There, however, the initial fixed-capital-consumption volume derives from the implicit \(\hq^{\text{stock}}_{-1}\) calibrated by
compute_calibrand_0(). Since this predecessor lies outside the stored trajectory, no explicit \(t=-1\) observation needs to be supplied.Conversely, when formerly computed available volumes are stored as fixed-capital-consumption volumes, the preceding underlying stock is recovered according to Eq.291. The common stock recurrence then locally recovers \(\hq^{\text{stock}}_{t-1}\) according to Eq.292, without reconstructing the complete stock trajectory from initialization onward.
Let’s finally vectorize the example over both valuation representations. The first trajectory remains stock-valued, while the second consists of one tenth of the fixed-capital-consumption trajectory.
>>> avols[2, ..., 0] = 0. >>> favols[2, ..., 0] = 0. >>> (vavols := np.stack([avols, .1*favols]).swapaxes(1, 0)) array([[[[1000. , 0. ]], [[ 18. , 0. ]]], [[[1174.43, 0. ]], [[ 10.56, 0. ]]], [[[ 0. , 0. ]], [[ 0. , 0. ]]]]) >>> (vovols := np.stack([ovols, .1*ovols]).swapaxes(1, 0)) array([[[[ 0. , 280. ]], [[ 0. , 28. ]]], [[[ 0. , 336. ]], [[ 0. , 33.6]]], [[[ 0. , 0. ]], [[ 0. , 0. ]]]]) >>> (vavols_drates := np.stack(2*[avols_drates]).swapaxes(1, 0)) array([[[[0., 0.]], [[0., 0.]]], [[[0., 0.]], [[0., 0.]]], [[[0., 0.]], [[0., 0.]]]])
Every instantiation parameter can likewise be vectorized:
>>> vds = DynamicStock( ... delta=np.array([[[.2]], [[.2]]]), ... grpot=np.array([[[.08]], [[.08]]]), ... dyear0=np.array([[[1.]], [[1.]]]), ... rental_valued=np.array([[[True]], [[False]]]), ... ).compute_calibrand_0( ... ordinal_volumes_transpose=vovols[0, ..., 1:], ... ) >>> _t_ = 2 >>> navols = vds.available_volume_computer( ... available_volumes=vavols, ... available_volumes_drates=vavols_drates, ... ordinal_volumes=vovols, dyears=dyears, t=_t_, ... ) >>> navols array([[[1087.63]], [[ 42.28]]]) >>> vavols[(_t_, ((0,), (1,)), ..., 0)] = navols >>> vavols array([[[[1000. , 0. ]], [[ 18. , 0. ]]], [[[1174.43, 0. ]], [[ 10.56, 0. ]]], [[[1087.63, 0. ]], [[ 42.28, 0. ]]]])
-
class
iamax.library.OPrDynamicStock¶ 
Price-augmented version of
DynamicStock.The dynamic quantity representation is inherited unchanged from
DynamicStock. The present augmentation only supplies its output price from the lagged price of the contributory flow entering the stock dynamics.See also
-
static
output_price_computer(ordinal_prices_transpose_lagged: float)¶ Return the lagged contributory-flow price unchanged.
The price attached to the available quantity is therefore inherited directly from the flow whose successive contributions generate the underlying stock. No additional price transformation is performed here.
- Parameters
ordinal_prices_transpose_lagged (numpy.ndarray) – \((\bmfp^{T}_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
ordinal_prices_transpose.
-
static
-
class
iamax.library.UOPrDynamicStock(*args, **kwargs)¶ 
Value-closure augmentation of
OPrDynamicStock.In addition to the inherited dynamic quantity and price mappings, the class retains both the currently exposed available quantity and its underlying stock quantity, and provides a calibration-period root condition linking the available value to its contributory fund.
The stock initialization, implicit prehistory, temporal conventions and alternative available-quantity representations are exactly those of
DynamicStockand are not redefined here.See also
DynamicStock,OPrDynamicStock,compute_qois(),fund_crooter().-
compute_qois(self, *, available_volumes: np.ndarray, available_volumes_drates: np.ndarray, ordinal_volumes: np.ndarray, dyears: np.ndarray, t: int)¶ Compute and retain both available and underlying stock quantities.
The exposed available quantity is computed exactly as prescribed by
available_volume_computer(). The corresponding underlying stock, already recovered internally by that computation, is retained alongside it from_x_t.This distinction only matters when the selected representation does not itself expose the stock quantity. No additional stock dynamics are introduced by the present method.
- Parameters
available_volumes (numpy.ndarray) – \((\hbq_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcL| \times |\mcI_j|\)
available_volumes’s slice.available_volumes_drates (numpy.ndarray) – \((\hbq^{\text{drate}}_k)_{k \in \mcI_j}\), i.e. a \(j\)th \(|\mcL| \times |\mcI_j|\) slice of
available_volumes_drates.ordinal_volumes (numpy.ndarray) – \((\bmfq_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcL| \times |\mcI_j|\) slice of
ordinal_volumes.dyears (numpy.ndarray) – Number of years between successive time indices, i.e. \((y_t - y_{t-1})_t\) for \(t > 0\), with the first element set to
numpy.infsince the initial recurrence period is inherently unknown to the serving system, i.e.iamax, and therefore supplied through the instantiation argumentdyear0. Cf.dyears.t (int) – Year-targeting integer index. Cf.
t, i.e. a_ilocalizations’s integer element.
- Example
For illustration only, consider the quantities below as an investment flow feeding a productive stock. We deliberately request the deterioration-valued representation so that the exposed quantity differs from its underlying stock.
>>> avols = np.zeros((1, 1, 2)) >>> avols_drates = np.zeros_like(avols) >>> ovols = np.array([[[0., 2.8]]]) >>> dyears = np.array([np.inf])
With a \(20\%\) annual deterioration rate and an \(8\%\) growth potential, the initial perpetuity rate is \(28\%\), hence the contributory flow above implies an initial underlying stock of \(2.8/.28=10\).
>>> ds = UOPrDynamicStock( ... delta=.2, grpot=.08, rental_valued=False ... ).compute_calibrand_0( ... ordinal_volumes_transpose=ovols[0, ..., 1:] ... ) >>> _ = ds.compute_qois( ... available_volumes=avols, ... available_volumes_drates=avols_drates, ... ordinal_volumes=ovols, ... dyears=dyears, ... t=0, ... )
The exposed initial quantity is the deterioration of the implicit predecessor stock, whereas the underlier remains the resulting initial stock itself.
>>> ds.available_volume_computer() array([[1.8]]) >>> ds.available_volume_underlier_computer() array([[10.]])
-
fund_crooter(self, available_value: np.ndarray, disposable_incomes_transpose_lagged: np.ndarray)¶ Root the initial contributory fund against the available value.
Let \(\hv_j\) denote the value of the available quantity exposed by
DynamicStock, and let \(\rho\) and \(\gamma_0\) respectively denote the effective initial perpetuity rate and survival factor defined inDynamicStock.Merging Eq.278, Eq.279 and Eq.280 implies the initial fund relationship
(294)¶\[\begin{split}\mcr_j = \hv_j \begin{cases} \rho, & \text{if is rental-valued}, \\[6pt] \displaystyle \frac{\rho\gamma_0}{(1-\rho)(1-\gamma_0)}, & \text{otherwise}. \end{cases}\end{split}\]The first branch follows immediately from \(\hq^{\mathrm{stock}}_0=\mfq_{-1}/\rho\). The second additionally accounts for the fact that the alternative initial representation is based on deterioration of the implicit predecessor stock, not on the contemporaneous stock itself. The returned relative distance is therefore null exactly when the supplied contributory fund satisfies the calibration relationship above, representation-consistent.
- Parameters
available_value (numpy.ndarray) – \(\hv_j\), i.e. the \(j\)th \(1 \times 1\)
available_values’s element.disposable_incomes_transpose_lagged (numpy.ndarray) – \((\bmcr^{T}_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of the lagged version of
disposable_incomes_transpose.
Important
All admissibility requirements attached to the corresponding quantity representation remain those described in
DynamicStock. The second branch additionally requires \(1-\rho \neq 0\) for its multiplicative value-conversion factor to remain finite.- Example
For illustration only, interpret the contributory flow as investment expenditure and the available quantity as a productive-stock representation. With
\[\delta=.2,\ g=.08,\ dyear0=1,\]one obtains \(\rho=.28\) and \(\gamma_0=.8\).
Under the stock-valued representation, an available value of
10therefore corresponds to a fund of2.8.>>> ds = UOPrDynamicStock( ... delta=.2, grpot=.08, rental_valued=True ... ) >>> avalue = np.array([[10.]]) >>> fund = np.array([[2.8]]) >>> ds.fund_crooter(avalue, fund) array([[1.12e-16]])
Under the deterioration-valued representation, the same calibration has an exposed quantity of
1.8when the common price is one. Its value must nevertheless reconcile with the same contributory fund.>>> fds = UOPrDynamicStock( ... delta=.2, grpot=.08, rental_valued=False ... ) >>> fds._ργ_0 1.555555555555556 >>> avalue = np.array([[1.8]]) >>> fund = np.array([[2.8]]) >>> fds.fund_crooter(avalue, fund) array([[2.24e-16]])
-
available_volume_computer(self)¶ Return the available quantity retained by
compute_qois().Its representation is exactly the one selected by
DynamicStock; this accessor performs no further computation.
-
available_volume_underlier_computer(self)¶ Return the underlying stock retained by
compute_qois().Contrary to
available_volume_computer(), this accessor always returns the stock quantity underlying the selected representation.
-
-
class
iamax.library.L1NzIntDrivenDemands¶ 
Class that abstracts the idea of Hicksian-like demands whose price and level characteristics are derived from their L1 normalized
ioq_intensitieswith respect to a good located an arbitrary number of permutations away in the consumption space.-
static
input_volumes_computer(output_volume: np.ndarray, ioq_intensities: np.ndarray)¶ s/e.
- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.ioq_intensities (numpy.ndarray) – \((\balpha_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
ioq_intensities’s slice.
-
static
-
class
iamax.library.O2STxRateDrivenSTxRate¶ 
Sales tax rate whose value is determined by that of a good being two permutations away in the consumption space.
(295)¶\[\frac{\ttau^{o_0}_t}{1 + \ttau^{o_0}_t} = \frac{\ttau^{o_0}_0}{1 + \ttau^{o_0}_0} - \zeta^{o_2}_t \left( \frac{\ttau^{o_2}_t}{1 + \ttau^{o_2}_t} - \frac{\ttau^{o_2}_0}{1 + \ttau^{o_2}_0} \right)\]where \(\ttau^{o_0}\) is the so-driven sales tax markup rate, \(\ttau^{o_2}\) is the two-permutation-away good’s rate of interest and \(\zeta^{o_2}\) the relevant order \(2\) input/output value intensity.
-
compute_calibrand_0(self, *, sales_taxes_totals_rates: float, t: int = 0)¶ Compute (and save) the \(t=0\)’s margin (and markup) rates.
- Parameters
sales_taxes_totals_rates (numpy.ndarray) – \((\hbtau_{\Sigma, k})_{k \in \{j\}\cup\mcI_j}\), i.e. a \(j\)-th \(|\mcL| \times |\{j\}\cup\mcI_j|\) slice of
sales_taxes_totals_rates.t (int) – Year-targeting integer index. Cf.
t, i.e. a_ilocalizations’s integer element.
Important
This method relies on the structure of its argument.
Note
Argument
tis mobilized as a trick to request the sales tax rate of the entity under edition.- Example
>>> so = O2STxRateDrivenSTxRate() >>> so.compute_calibrand_0( ... sales_taxes_totals_rates=np.array([[ ... 0.023105133651252, # self related ... 0.150641610514566, # order-2 away rate ... ]]) ... ) >>> so.o0_markup_sales_tax_total_rate_0 0.023105133651252 >>> so.o0_margin_sales_tax_total_rate_0 0.02258334250439593 >>> so.o2_markup_sales_tax_total_rate_0 0.150641610514566 >>> so.o2_margin_sales_tax_total_rate_0 0.13091966181129083
-
sales_tax_total_rate_computer(self, *, sales_tax_total_rate: float, iov_intensity_order2: float)¶ s/e.
- Parameters
sales_tax_total_rate (float) – Cf.
sales_taxes_totals_rates(as markup rate).iov_intensity_order2 (float) – Cf.
iov_intensities_order2.
- Example
>>> so = O2STxRateDrivenSTxRate() >>> so.compute_calibrand_0( ... sales_taxes_totals_rates=np.array([[ ... 0.023105133651252, # self related ... 0.150641610514566, # order-2 away rate ... ]]) ... ) >>> so.sales_tax_total_rate_computer( ... sales_tax_total_rate=0.540874848689871, ... iov_intensity_order2=0.0426989104641244, ... ).item() 0.01336155939770362
-
-
class
iamax.library.O2STxRateDrivenCTxRate¶ 
Contributive tax rate whose value is determined by the sales taxe rate of a good being two permutations away in the consumption space.
(296)¶\[\otau^{o_0}_t = \otau^{o_0}_0 - \zeta^{o_2}_t \left( \frac{\ttau^{o_2}_t}{1 + \ttau^{o_2}_t} - \frac{\ttau^{o_2}_0}{1 + \ttau^{o_2}_0} \right)\]where \(\otau^{o_0}\) is the so-driven contributive tax margin rate, \(\ttau^{o_2}\) is the two-permutation-away good’s sales tax rate of interest and \(\zeta^{o_2}\) the relevant order \(2\) input/output value intensity.
-
compute_calibrand_0(self, *, contrib_tax_rate: float, sales_tax_total_rate: float)¶ Compute (and save) the \(t=0\)’s margin (and markup) rates.
- Parameters
contrib_tax_rate (float) – A \(j\)-targeted
contrib_taxes_rates’s scalar.sales_tax_total_rate (float) – \((\hbtau_{\Sigma, k})_{k \in \mcI_j}\), i.e. a \(j\)-th \(1 \times |\mcI_j|\) slice of
sales_taxes_totals_rates.
Note
\(\mcI_j\) is assumed to be a singleton.
- Example
>>> so = O2STxRateDrivenCTxRate() >>> so.compute_calibrand_0( ... contrib_tax_rate=0.0225833425043962, ... sales_tax_total_rate=0.150641610514566, ... ) >>> so.o0_margin_contrib_tax_rate_0 0.0225833425043962 >>> so.o2_markup_sales_tax_total_rate_0 0.150641610514566 >>> so.o2_margin_sales_tax_total_rate_0.item() 0.13091966181129083
-
contrib_tax_rate_computer(self, *, sales_tax_total_rate: float, iov_intensity_order2: float)¶ s/e.
- Parameters
sales_tax_total_rate (float) – Cf.
sales_taxes_totals_rates(as markup rate).iov_intensity_order2 (float) – Cf.
iov_intensities_order2.
- Example
>>> so = O2STxRateDrivenCTxRate() >>> so.compute_calibrand_0( ... contrib_tax_rate=0.0225833425043962, ... sales_tax_total_rate=0.150641610514566, ... ) >>> so.contrib_tax_rate_computer( ... sales_tax_total_rate=0.540874848689871, ... iov_intensity_order2=0.0426989104641244, ... ).item() 0.013185382131176756
-
-
class
iamax.library.OLabor¶ 
Example case-denominated composite sector’s labor.
-
class
iamax.library.OKLProducer¶ 
Example case-denominated domestic (intermediary) composite-&-KL good producer.
-
class
iamax.library.OKLEProducer¶ 
Example case-denominated domestic (intermediary) composite-&-KLE good producer.
-
class
iamax.library.ODProducer¶ 
Example case-denominated domestic composite good producer.
-
class
iamax.library.OAProducer¶ 
Example case-denominated armington composite good producer.
-
class
iamax.library.ELabor¶ 
Example case-denominated energy sector’s labor.
-
class
iamax.library.EKLProducer¶ 
Example case-denominated domestic (intermediary) energy-&-KL good producer.
-
class
iamax.library.EKLEProducer¶ 
Example case-denominated domestic (intermediary) energy-&-KLE good producer.
-
class
iamax.library.EDProducer¶ 
Example case-denominated domestic energy producer.
-
class
iamax.library.EAProducer¶ 
Example case-denominated armington energy producer.
-
class
iamax.library.Consumer¶ 
Example case-denominated final consumers.
-
class
iamax.library.Ordinaler¶ Class that abstracts the idea of an underlying capital stock being calculated based on an assumed rental price, and an investment volume being adjusted accordingly.
-
static
ordinal_volume_computer(input_volumes: np.ndarray)¶ Perceived index, \(1 \times 1\).
- Parameters
input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.
See also
-
static
-
class
iamax.library.AdditiveOrdinaler¶ s/e.
-
static
ordinal_volume_computer(input_volumes: np.ndarray)¶ Perceived index, \(1 \times 1\), denoted as
(297)¶\[\mfq_j = \sum_{k \in \mcI_j} q_k\]- Parameters
input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.
See also
-
static
-
class
iamax.library.Government¶ 
Example case-denominated public administration.
-
class
iamax.library.Investor¶ 
Example case-denominated investors.
-
class
iamax.library.ImplicitLeontief¶ s/e.
-
compute_calibrand_0(self, *, input_volumes: np.ndarray)¶ s/e.
- Parameters
input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.
-
compute_calibrand_0_star(self, *, additive_input_volumes_shares_drates: np.ndarray)¶ s/e.
- Parameters
additive_input_volumes_shares_drates (numpy.ndarray) – \((\bQ^\text{drate}_{\%,k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
additive_input_volumes_shares_drates.
-
input_volumes_computer(self, *, ordinal_volume: float)¶ s/e.
- Parameters
ordinal_volume (float) – \(\mfq_j\), i.e. the \(j\)th \(1 \times 1\)
ordinal_volumes’s element.
-
-
class
iamax.library.OImplicitLeontief¶ 
s/e.
-
class
iamax.library.MarshallianILeo¶ 
s/e.
-
class
iamax.library.LaspeyresianGFL(negated_mask: bool = False)¶ Class that abstracts the idea of economic agents who anchor their consumption decisions to the initial period’s expenditure shares, mirroring the “fixed-weight” logic of the Laspeyres framework. This class moreover allows one to restrict (in a generalized manner) the set of trade-offs being forced.
- Parameters
negated_mask (bool) – Whether the mask passed as argument
input_volumes_drates2of the methodcompute_calibrand_0is to be negated. Argumentinput_volumes_drates2indeed boolean-specifies the goods being freely subject to trade-off by default. Set toFalseby default.
-
compute_calibrand_0(self, *, budget_constraint: float, input_values: np.ndarray, input_volumes_drates2: np.ndarray)¶ s/e.
- Parameters
budget_constraint (float) – \(r_j\), i.e. the \(j\)th \(1 \times 1\)
budget_constraints’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.input_volumes_drates2 (numpy.ndarray) – \((\bQ^\text{drate}_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes_drates2’s slice. This variable is coerced into boolean and used as mask.
- Example
>>> budc = 200. >>> ivals = np.array([[110., 80., 10.]]) >>> imsks = np.array([[1, 1, 1]])
>>> c = LaspeyresianGFL(negated_mask=False).compute_calibrand_0( ... budget_constraint=budc, input_values=ivals, ... input_volumes_drates2=imsks ... ) >>> c.calibrand_0 array([[0.55, 0.4 , 0.05]])
Let’s then illustrate how such calculation can be vectorized.
>>> vbudc = np.array([[[budc]], [[budc]]]) >>> vivals = np.stack((ivals, ivals)) >>> vimsks = np.stack((imsks, np.array([[1, 0, 1]]))) >>> c.compute_calibrand_0( ... budget_constraint=vbudc, input_values=vivals, ... input_volumes_drates2=vimsks ... ).calibrand_0 array([[[0.55, 0.4 , 0.05]], [[0.92, 0. , 0.08]]])
-
compute_calibrand_0_star(self, input_values_shares_drates: np.ndarray = 0.0)¶ s/e.
Input demands, \(1 \times |\mcI_j|\)
- Parameters
budget_constraint (float) – \(r_j\), i.e. the \(j\)th \(1 \times 1\)
budget_constraints’s element.input_values (numpy.ndarray) – \((\bmcV_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_values’s slice.
- Example
>>> ivals = np.array([[110., 60., 20., 10.]]) >>> budc = ivals.sum() >>> c1111 = LaspeyresianGFL( ... negated_mask=False ... ).compute_calibrand_0( ... budget_constraint=budc, input_values=ivals, ... input_volumes_drates2=np.array([[1, 1, 1, 1]]) ... ) >>> c1111.calibrand_0 array([[0.55, 0.3 , 0.1 , 0.05]]) >>> c1001 = LaspeyresianGFL( ... negated_mask=False ... ).compute_calibrand_0( ... budget_constraint=budc, input_values=ivals, ... input_volumes_drates2=np.array([[1, 0, 0, 1]]) ... ) >>> c1001.calibrand_0 array([[0.92, 0. , 0. , 0.08]])
>>> ivals *= np.array([[1, 5/6, 3/2, 1]]) >>> budc = ivals.sum() >>> c1111.input_values_shares_rooter( ... budget_constraint=budc, input_values=ivals, ... ) array([[ 0. , -0.13, 0.27, 0. ]]) >>> c1001.input_values_shares_rooter( ... budget_constraint=budc, input_values=ivals, ... ) array([[0., 0., 0., 0.]])
-
class
iamax.library.EExporter¶ 
Example case-denominated exporters of energy goods.
-
class
iamax.library.OExporter¶ 
Example case-denominated exporters of composite goods.
-
class
iamax.library.OneToOne(intensity_factor: float = 1.0)¶ Abstraction that grants the properties (defined by the methods below) of one entity to another.
- Parameters
intensity_factor (float) – S/e. set to
1by default.
-
input_volume_computer(self, *, output_volume: float)¶ Identity function (to within a multiplicative
intensity_factor).- Parameters
output_volume (float) – \(q_j\), i.e. the \(j\)th \(1 \times 1\)
output_volumes’s element.- Example
>>> OneToOne().input_volume_computer(output_volume=.5) 0.5 >>> OneToOne(2).input_volume_computer(output_volume=.5) 1.0
-
class
iamax.library.AOneToOne¶ 
Augmented version of
OneToOnethat deals with prices followingAccountant’s approach.
-
class
iamax.library.OnBoard¶ 
Free-on-board (FOB) to Cost-Insurance-and-Freight (CIF).
-
compute_calibrand_0(self, *, producer_net_price_drate: np.ndarray, purchaser_prices: np.ndarray)¶ s/e.
Important
This method relies on the structure of its argument, with the transported good volume being the first arrays’ component.
- Example
>>> oprc = 0.038 >>> pprcs = np.array([[0.774, 0.68]]) >>> ob = OnBoard() >>> ob.compute_calibrand_0( ... producer_net_price_drate=oprc, ... purchaser_prices=pprcs ... ) >>> ob.calibrand_0 array([[0.04]])
Let’s vectorize the above example.
>>> voprc = np.array([[[oprc]], [[2*oprc]]]) >>> vpprcs = np.stack((pprcs, 2*pprcs)) >>> ob.compute_calibrand_0( ... producer_net_price_drate=voprc, ... purchaser_prices=vpprcs ... ) >>> ob.calibrand_0 array([[[0.04]], [[0.09]]])
-
input_volumes_computer(self, *, output_volume: float)¶ s/e.
Important
This method relies on the structure of its argument, with the transported good volume being the first arrays’ component.
- Example
>>> oprc = 0.038 >>> pprcs = np.array([[0.774, 0.68]]) >>> ob = OnBoard() >>> ob.compute_calibrand_0( ... producer_net_price_drate=oprc, ... purchaser_prices=pprcs ... )
>>> ovol = 197432.592 >>> ivols = ob.input_volumes_computer( ... output_volume=ovol ... ) >>> ivols array([[197432.59, 8539.54]]) >>> ivols.shape (1, 2)
Let’s vectorize the above example.
>>> voprc = np.array([[[oprc]], [[2*oprc]]]) >>> vpprcs = np.stack((pprcs, 2*pprcs)) >>> ob.compute_calibrand_0( ... producer_net_price_drate=voprc, ... purchaser_prices=vpprcs ... ) >>> vovol = np.array([[[ovol]], [[2*ovol]]]) >>> vivols = ob.input_volumes_computer( ... output_volume=vovol ... ) >>> vivols array([[[197432.59, 8539.54]], [[394865.18, 34158.16]]]) >>> vivols.shape (2, 1, 2)
-
-
class
iamax.library.IOnBoard¶ 
Transport-intensity calibrated version of
OnBoard-
compute_calibrand_0(self, *, input_volumes: np.ndarray)¶ s/e.
Important
This method relies on the structure of its argument, with the transported good volume being the first arrays’ component.
- Example
>>> ivols = np.array([[3., 6.]]) >>> ob = IOnBoard() >>> ob.compute_calibrand_0( ... input_volumes=ivols ... ) >>> ob.calibrand_0 array([[2.]])
Let’s vectorize the above example.
>>> vivols = np.stack((ivols, [[3., .0]])) >>> ob.compute_calibrand_0( ... input_volumes=vivols ... ) >>> ob.calibrand_0 array([[[2.]], [[0.]]])
-
-
class
iamax.library.CorrTrader¶ Trader abstraction whose optimal demands derive from a portfolio correlated allocation problem.
-
compute_calibrand_0(self, *, input_volumes: np.ndarray, input_prices: np.ndarray, ordinal_volumes: np.ndarray, ordinal_prices: np.ndarray)¶ Calibrate the quantity transformation.
- Parameters
input_volumes (numpy.ndarray) – \((\bQ_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_volumes’s slice.input_prices (numpy.ndarray) – \((\tbP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\)
input_prices’s slice.ordinal_volumes (numpy.ndarray) – \((\bmfq_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
ordinal_volumes.ordinal_prices (numpy.ndarray) – \((\bmfp_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 \times |\mcI_j|\) slice of
ordinal_prices.
- Example
>>> iprcs = np.identity(3) * np.array((1.5, 2.5, 6.)) >>> ivols = np.identity(3) * np.array((2., .8, .25)) >>> oprcs = np.array((2., 2.5, 5.))[None, :] >>> ovols = np.diag(ivols * iprcs)[None, :] / oprcs
>>> ct = CorrTrader() >>> ct.compute_calibrand_0( ... input_volumes=ivols, ... input_prices=iprcs, ... ordinal_volumes=ovols, ... ordinal_prices=oprcs, ... )._kappa array([[1.]]) >>> ct._beta array([[1.33, 0. , 0. ], [0. , 1. , 0. ], [0. , 0. , 0.83]])
Let’s now illustrate the matter when the accounting equation does not hold because of ordinal volumes being, well, too ordinal. Such a discrepancy is captured by
~._kappanot being equal to 1.>>> ct = CorrTrader().compute_calibrand_0( ... input_volumes=ivols, ... input_prices=iprcs, ... ordinal_volumes=3*ovols, # <--- ... ordinal_prices=oprcs, ... ) >>> ct._kappa array([[3.]]) >>> ct._omega array([[0.46, 0.31, 0.23]]) >>> ct._beta array([[0.44, 0. , 0. ], [0. , 0.33, 0. ], [0. , 0. , 0.28]])
Let’s now make a vectorized example.
>>> (vivols := np.stack((ivols, 1.5*ivols))) array([[[2. , 0. , 0. ], [0. , 0.8 , 0. ], [0. , 0. , 0.25]], [[3. , 0. , 0. ], [0. , 1.2 , 0. ], [0. , 0. , 0.38]]]) >>> (viprcs := np.stack((iprcs, 4*iprcs))) array([[[ 1.5, 0. , 0. ], [ 0. , 2.5, 0. ], [ 0. , 0. , 6. ]], [[ 6. , 0. , 0. ], [ 0. , 10. , 0. ], [ 0. , 0. , 24. ]]]) >>> (vovols := np.stack((ovols, 6*ovols))) array([[[1.5, 0.8, 0.3]], [[9. , 4.8, 1.8]]]) >>> (voprcs := np.stack(2*(oprcs,))) array([[[2. , 2.5, 5. ]], [[2. , 2.5, 5. ]]])
>>> vct = CorrTrader().compute_calibrand_0( ... input_volumes=vivols, input_prices=viprcs, ... ordinal_volumes=vovols, ordinal_prices=voprcs ... ) >>> vct._beta array([[[1.33, 0. , 0. ], [0. , 1. , 0. ], [0. , 0. , 0.83]], [[0.33, 0. , 0. ], [0. , 0.25, 0. ], [0. , 0. , 0.21]]]) >>> vct._omega array([[[0.46, 0.31, 0.23]], [[0.46, 0.31, 0.23]]])
-
compute_qois(self, *, budget_constraints: np.ndarray, input_prices: np.ndarray, ordinal_volumes_drates: np.ndarray = 0.0)¶ Compute ordinal capital flows and physical input demands.
- Parameters
budget_constraints (numpy.ndarray) – \((mcr_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(1 imes |\mcI_j|\)
budget_constraints’s slice.input_prices (numpy.ndarray) – \(( bP_{k,j})_{k \in \mcI_j}\), i.e. the \(j\)th \(1 imes |\mcI_j|\)
input_prices’s slice.ordinal_volumes_drates (numpy.ndarray) – \((mfq^{ ext{drate}}_k)_{k \in \mcI_j}\), i.e. the \(j\)th \(|\mcL| imes |\mcI_j|\) slice of
ordinal_volumes_drates. To.0by default.
- Example
>>> (iprcs := np.identity(3) * np.array((1.5, 2.5, 6.))) array([[1.5, 0. , 0. ], [0. , 2.5, 0. ], [0. , 0. , 6. ]]) >>> (ivols := np.identity(3) * np.array((2., .8, .25))) array([[2. , 0. , 0. ], [0. , 0.8 , 0. ], [0. , 0. , 0.25]]) >>> (oprcs := np.array((4., 5., 10.))[None, :]) array([[ 4., 5., 10.]]) >>> ( ... ovols := 2. * np.diag(ivols * iprcs)[None, :] / oprcs ... ) # Breaks the accounting equation array([[1.5, 0.8, 0.3]])
>>> ct = CorrTrader().compute_calibrand_0( ... input_volumes=ivols, input_prices=iprcs, ... ordinal_volumes=ovols, ordinal_prices=oprcs, ... ) >>> ct._kappa array([[2.]]) >>> ct._beta array([[1.33, 0. , 0. ], [0. , 1. , 0. ], [0. , 0. , 0.83]])
>>> (bcons := np.diag(ivols * iprcs)[None, :]) array([[3. , 2. , 1.5]]) >>> ct.compute_qois( ... budget_constraints=bcons, input_prices=iprcs, ... ).input_volumes_computer() array([[2. , 0. , 0. ], [0. , 0.8 , 0. ], [0. , 0. , 0.25]]) >>> ct.ordinal_volumes_computer() array([[1.5, 0.8, 0.3]]) >>> ct.ordinal_prices_computer() array([[2. , 2.5, 5. ]])
Let’s vectorize the above example.
>>> (viprcs := np.stack((iprcs, 4*iprcs))) array([[[ 1.5, 0. , 0. ], [ 0. , 2.5, 0. ], [ 0. , 0. , 6. ]], [[ 6. , 0. , 0. ], [ 0. , 10. , 0. ], [ 0. , 0. , 24. ]]]) >>> (vivols := np.stack((ivols, 1.5*ivols))) array([[[2. , 0. , 0. ], [0. , 0.8 , 0. ], [0. , 0. , 0.25]], [[3. , 0. , 0. ], [0. , 1.2 , 0. ], [0. , 0. , 0.38]]]) >>> (voprcs := np.stack(2*(oprcs,))) array([[[ 4., 5., 10.]], [[ 4., 5., 10.]]]) >>> (vovols := np.stack((.5*ovols, 6*ovols))) array([[[0.75, 0.4 , 0.15]], [[9. , 4.8 , 1.8 ]]])
>>> vct = CorrTrader().compute_calibrand_0( ... input_volumes=vivols, input_prices=viprcs, ... ordinal_volumes=vovols, ordinal_prices=voprcs ... ) >>> vct._kappa array([[[1.]], [[2.]]]) >>> vct._beta array([[[2.67, 0. , 0. ], [0. , 2. , 0. ], [0. , 0. , 1.67]], [[0.33, 0. , 0. ], [0. , 0.25, 0. ], [0. , 0. , 0.21]]])
>>> (vbcons := np.stack((bcons, 6*bcons))) array([[[ 3. , 2. , 1.5]], [[18. , 12. , 9. ]]]) >>> vct.compute_qois( ... budget_constraints=vbcons, input_prices=viprcs ... ).input_volumes_computer() array([[[2. , 0. , 0. ], [0. , 0.8 , 0. ], [0. , 0. , 0.25]], [[3. , 0. , 0. ], [0. , 1.2 , 0. ], [0. , 0. , 0.38]]]) >>> vct.ordinal_volumes_computer() array([[[0.75, 0.4 , 0.15]], [[9. , 4.8 , 1.8 ]]]) >>> vct.ordinal_prices_computer() array([[[ 4. , 5. , 10. ]], [[ 2. , 2.5, 5. ]]])
Let’s now turn to full matrices. Rows represent goods and services, while columns represent the sectors whose productive available volumes are being built. Each column therefore describes the basket of goods required by one capacity-building sector.
The supplied ordinal prices are defined directly from the dual relation, so the accounting equation holds by construction.
>>> iprcs = np.array([ ... [1., .5, 3.], ... [2., 2., 1.], ... [1., 2., 2.], ... ]) >>> ivols = np.array([ ... [2., 1., .5], ... [.25, 1., .5], ... [.25, .125, .75], ... ]) >>> ovols = np.array([2., 1., .5])[None, :] >>> (oprcs := (iprcs * ivols / ovols).sum(axis=-2, keepdims=True)) array([[1.38, 2.75, 7. ]])
>>> ct = CorrTrader().compute_calibrand_0( ... input_volumes=ivols, input_prices=iprcs, ... ordinal_volumes=ovols, ordinal_prices=oprcs, ... ) >>> ct._kappa array([[1.]]) >>> ct._beta array([[1. , 1. , 1. ], [0.12, 1. , 1. ], [0.12, 0.12, 1.5 ]]) >>> np.linalg.matrix_rank(ct._beta) 3 >>> iprcs * ct._beta array([[1. , 0.5 , 3. ], [0.25, 2. , 1. ], [0.12, 0.25, 3. ]]) >>> ct._omega array([[0.31, 0.31, 0.39]])
>>> (bcons := oprcs * ovols) array([[2.75, 2.75, 3.5 ]]) >>> ct.compute_qois( ... budget_constraints=bcons, input_prices=iprcs, ... ).input_volumes_computer() array([[2. , 1. , 0.5 ], [0.25, 1. , 0.5 ], [0.25, 0.12, 0.75]]) >>> ct.ordinal_volumes_computer() array([[2. , 1. , 0.5]]) >>> ct.ordinal_prices_computer() array([[1.38, 2.75, 7. ]]) >>> ct.input_volumes_computer().sum( ... axis=-1, keepdims=True, ... ) array([[3.5 ], [1.75], [1.12]])
Let’s now vectorize this full-matrix example. The second slice triples physical prices, doubles physical volumes and quadruples ordinal volumes. Its calibrated transformation is therefore one half of the first, its dual ordinal prices are multiplied by 1.5 and its budget constraints are multiplied by six.
>>> (viprcs := np.stack((iprcs, 3*iprcs))) array([[[1. , 0.5, 3. ], [2. , 2. , 1. ], [1. , 2. , 2. ]], [[3. , 1.5, 9. ], [6. , 6. , 3. ], [3. , 6. , 6. ]]]) >>> (vivols := np.stack((ivols, 2*ivols))) array([[[2. , 1. , 0.5 ], [0.25, 1. , 0.5 ], [0.25, 0.12, 0.75]], [[4. , 2. , 1. ], [0.5 , 2. , 1. ], [0.5 , 0.25, 1.5 ]]]) >>> (vovols := np.stack((ovols, 4*ovols))) array([[[2. , 1. , 0.5]], [[8. , 4. , 2. ]]]) >>> ( ... voprcs := np.sum( ... viprcs * vivols / vovols, ... axis=-2, keepdims=True, ... ) ... ) array([[[ 1.38, 2.75, 7. ]], [[ 2.06, 4.12, 10.5 ]]])
>>> vct = CorrTrader().compute_calibrand_0( ... input_volumes=vivols, input_prices=viprcs, ... ordinal_volumes=vovols, ordinal_prices=voprcs, ... ) >>> vct._kappa array([[[1.]], [[1.]]]) >>> vct._beta array([[[1. , 1. , 1. ], [0.12, 1. , 1. ], [0.12, 0.12, 1.5 ]], [[0.5 , 0.5 , 0.5 ], [0.06, 0.5 , 0.5 ], [0.06, 0.06, 0.75]]]) >>> np.linalg.matrix_rank(vct._beta) array([3, 3], dtype=int64) >>> vct._omega array([[[0.31, 0.31, 0.39]], [[0.31, 0.31, 0.39]]])
>>> (vbcons := voprcs * vovols) array([[[ 2.75, 2.75, 3.5 ]], [[16.5 , 16.5 , 21. ]]]) >>> vct.compute_qois( ... budget_constraints=vbcons, input_prices=viprcs, ... ).input_volumes_computer() array([[[2. , 1. , 0.5 ], [0.25, 1. , 0.5 ], [0.25, 0.12, 0.75]], [[4. , 2. , 1. ], [0.5 , 2. , 1. ], [0.5 , 0.25, 1.5 ]]]) >>> vct.ordinal_volumes_computer() array([[[2. , 1. , 0.5]], [[8. , 4. , 2. ]]]) >>> vct.ordinal_prices_computer() array([[[ 1.38, 2.75, 7. ]], [[ 2.06, 4.12, 10.5 ]]]) >>> vct.input_volumes_computer().sum( ... axis=-1, keepdims=True, ... ) array([[[3.5 ], [1.75], [1.12]], [[7. ], [3.5 ], [2.25]]])
-
input_volumes_computer(self)¶ s/e.
-
ordinal_volumes_computer(self)¶ s/e.
-
ordinal_prices_computer(self)¶ s/e.
-