Skip to content

Commit

Permalink
add bounds to chi2 raking
Browse files Browse the repository at this point in the history
  • Loading branch information
ADucellierIHME committed Nov 28, 2024
1 parent 34f9050 commit 179e907
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 29 deletions.
18 changes: 6 additions & 12 deletions src/raking/inequality_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ def inequality_infant_mortality(
Returns
-------
C : np.ndarray
2I * 2I constraints matrix
I * 2I constraints matrix
c : np.ndarray
length 2I inequality vector vector
length I inequality vector vector
"""
assert isinstance(
n1, np.ndarray
Expand All @@ -51,21 +51,15 @@ def inequality_infant_mortality(
assert isinstance(
t1, float
), "The time interval between 0 and 1 month must be a float."
assert isinstance(
assert isinstance(
t2, float
), "The time interval between 0 and 1 year must be a float."
assert (
assert (
t2 > t1
), "The time interval between 0 and 1 year must be larger than the time interval between 0 and a month."

I = len(n1)
C = np.concatenate(
(
np.concatenate((np.diag(t1 / n1), np.zeros((I, I))), axis=1),
np.concatenate((np.zeros((I, I)), np.diag(- t2 / n2)), axis=1),
),
axis=0,
)
c = np.zeros(2 * I)
C = np.concatenate((np.diag(t1 / n1), np.diag(- t2 / n2)), axis=1)
c = np.zeros(I)
return (C, c)

82 changes: 73 additions & 9 deletions src/raking/raking_inequality.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,92 @@

import numpy as np

from scipy.optimize import Bounds
from scipy.optimize import LinearConstraint
from scipy.optimize import OptimizeResult
from scipy.optimize import minimize

def raking_chi2_inequality(
y: np.ndarray,
A: np.ndarray,
s: np.ndarray,
C: np.ndarray,
c: np.ndarray
) -> tuple[np.ndarray, np.ndarray]:
c: np.ndarray,
q: np.ndarray,
l: np.ndarray = None,
h: np.ndarray = None
) -> OptimizeResult:

equality = LinearConstraint(A, s, s)
inequality = LinearConstraint(C, np.repeat(-np.inf, len(c)), c)
if (l is not None) and (h is not None):
bounds = Bounds(l, h)
else:
bounds = None

def distance(x):
return np.sum(np.square(x - y) / (2.0 * y))
def jacobian(x):
return x / y - 1.0
def hessian(x):
return np.diag(1.0 / y)
def distance(beta):
return np.sum(np.square(beta - y) / (2.0 * q * y))
def jacobian(beta):
return (beta / y - 1.0) / q
def hessian(beta):
return np.diag(1.0 / (q * y))

res = minimize(distance, y, method='trust-constr', \
if (l is not None) and (h is not None):
res = minimize(fun=distance, x0=y, method='trust-constr', \
jac=jacobian, hess=hessian, constraints=[equality, inequality], bounds=bounds)
else:
res = minimize(fun=distance, x0=y, method='trust-constr', \
jac=jacobian, hess=hessian, constraints=[equality, inequality])
return res


def raking_entropic_inequality(
y: np.ndarray,
A: np.ndarray,
s: np.ndarray,
C: np.ndarray,
c: np.ndarray,
q: np.ndarray
) -> OptimizeResult:

equality = LinearConstraint(A, s, s)
inequality = LinearConstraint(C, np.repeat(-np.inf, len(c)), c)

def distance(beta):
return np.sum((beta * np.log(beta / y) - beta + y) / q)
def jacobian(beta):
return (np.log(beta / y)) / q
def hessian(beta):
return np.diag(1.0 / (q * beta))

res = minimize(fun=distance, x0=y, method='trust-constr', \
jac=jacobian, hess=hessian, constraints=[equality, inequality])
return res


def raking_logit_inequality(
y: np.ndarray,
A: np.ndarray,
s: np.ndarray,
C: np.ndarray,
c: np.ndarray,
q: np.ndarray,
l: np.ndarray,
h: np.ndarray
) -> OptimizeResult:

equality = LinearConstraint(A, s, s)
inequality = LinearConstraint(C, np.repeat(-np.inf, len(c)), c)

def distance(beta):
return np.sum(((beta - l) * np.log((beta - l) / (y - l)) + \
(h - beta) * np.log((h - beta) / (h - y))) / q)
def jacobian(beta):
return (np.log((beta - l) / (y - l)) + np.log((h - beta) / (h - y))) / q
def hessian(beta):
return np.diag((1.0 / ( beta - l) - 1.0 / (h - beta)) / y)

res = minimize(fun=distance, x0=y, method='trust-constr', \
jac=jacobian, hess=hessian, constraints=[equality, inequality])
return res

31 changes: 23 additions & 8 deletions src/raking/set_inequality_problems.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Module with methods to set up the problems with enequality constraints"""
"""Module with methods to set up the problems with inequality constraints"""

import numpy as np

Expand All @@ -14,8 +14,14 @@ def set_infant_mortality(
y1: np.ndarray,
y2: np.ndarray,
s1: float,
s2: float
) -> tuple[np.ndarray, np.ndarray]:
s2: float,
q1: np.ndarray,
q2: np.ndarray,
l1: np.ndarray = None,
l2: np.ndarray = None,
h1: np.ndarray = None,
h2: np.ndarray = None
) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""Set up the optimization problem for the infant mortality problem.
We need to define the problem:
Expand All @@ -40,18 +46,27 @@ def set_infant_mortality(
C
c
"""
I = len(y1
I = len(y1)
y = np.concatenate((y1, y2))
(A1, s1) = constraints_1D(s1, I)
(A2, s2) = constraints_1D(s2, I)
A = np.concatenate(
(
np.concatenate((A1, np.zeros(I)), axis=1),
np.concatenate((np.zeros(I), A2), axis=1),
np.concatenate((A1, np.zeros((1, I))), axis=1),
np.concatenate((np.zeros((1, I)), A2), axis=1),
),
axis=0,
)
s = np.array([s1, s2])
s = np.concatenate((s1, s2))
(C, c) = inequality_infant_mortality(n1, n2, t1, t2)
return (y, A, s, C, c)
q = np.concatenate((q1, q2))
if (l1 is not None) and (l2 is not None):
l = np.concatenate((l1, l2))
else:
l = None
if (h1 is not None) and (h2 is not None):
h = np.concatenate((h1, h2))
else:
h = None
return (y, A, s, C, c, q, l, h)

0 comments on commit 179e907

Please sign in to comment.