owlplanner 2025.3.15__py3-none-any.whl → 2025.3.27__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- owlplanner/plan.py +23 -4
- owlplanner/rates.py +3 -0
- owlplanner/version.py +1 -1
- {owlplanner-2025.3.15.dist-info → owlplanner-2025.3.27.dist-info}/METADATA +1 -1
- {owlplanner-2025.3.15.dist-info → owlplanner-2025.3.27.dist-info}/RECORD +7 -7
- {owlplanner-2025.3.15.dist-info → owlplanner-2025.3.27.dist-info}/WHEEL +0 -0
- {owlplanner-2025.3.15.dist-info → owlplanner-2025.3.27.dist-info}/licenses/LICENSE +0 -0
owlplanner/plan.py
CHANGED
|
@@ -307,6 +307,9 @@ class Plan(object):
|
|
|
307
307
|
# Previous 2 years for Medicare.
|
|
308
308
|
self.prevMAGI = np.zeros((2))
|
|
309
309
|
|
|
310
|
+
# Default slack on profile.
|
|
311
|
+
self.lambdha = 0
|
|
312
|
+
|
|
310
313
|
# Scenario starts at the beginning of this year and ends at the end of the last year.
|
|
311
314
|
s = ["", "s"][self.N_i - 1]
|
|
312
315
|
self.mylog.vprint(f"Preparing scenario of {self.N_n} years for {self.N_i} individual{s}.")
|
|
@@ -1071,6 +1074,9 @@ class Plan(object):
|
|
|
1071
1074
|
Cx = self.C["x"]
|
|
1072
1075
|
Cz = self.C["z"]
|
|
1073
1076
|
|
|
1077
|
+
spLo = 1 - self.lambdha
|
|
1078
|
+
spHi = 1 + self.lambdha
|
|
1079
|
+
|
|
1074
1080
|
tau_ijn = np.zeros((Ni, Nj, Nn))
|
|
1075
1081
|
for i in range(Ni):
|
|
1076
1082
|
for j in range(Nj):
|
|
@@ -1191,7 +1197,7 @@ class Plan(object):
|
|
|
1191
1197
|
# Account for time elapsed in the current year.
|
|
1192
1198
|
spending *= units * self.yearFracLeft
|
|
1193
1199
|
# self.mylog.vprint('Maximizing bequest with desired net spending of:', u.d(spending))
|
|
1194
|
-
A.addNewRow({_q1(Cg, 0): 1}, spending, spending)
|
|
1200
|
+
A.addNewRow({_q1(Cg, 0): 1}, spLo * spending, spHi * spending)
|
|
1195
1201
|
|
|
1196
1202
|
# Set initial balances through constraints.
|
|
1197
1203
|
for i in range(Ni):
|
|
@@ -1297,8 +1303,10 @@ class Plan(object):
|
|
|
1297
1303
|
|
|
1298
1304
|
# Impose income profile.
|
|
1299
1305
|
for n in range(1, Nn):
|
|
1300
|
-
rowDic = {_q1(Cg, 0, Nn): -self.xiBar_n[n], _q1(Cg, n, Nn): self.xiBar_n[0]}
|
|
1301
|
-
A.addNewRow(rowDic, zero,
|
|
1306
|
+
rowDic = {_q1(Cg, 0, Nn): -spLo * self.xiBar_n[n], _q1(Cg, n, Nn): self.xiBar_n[0]}
|
|
1307
|
+
A.addNewRow(rowDic, zero, inf)
|
|
1308
|
+
rowDic = {_q1(Cg, 0, Nn): spHi * self.xiBar_n[n], _q1(Cg, n, Nn): -self.xiBar_n[0]}
|
|
1309
|
+
A.addNewRow(rowDic, zero, inf)
|
|
1302
1310
|
|
|
1303
1311
|
# Taxable ordinary income.
|
|
1304
1312
|
for n in range(Nn):
|
|
@@ -1362,7 +1370,9 @@ class Plan(object):
|
|
|
1362
1370
|
# Now build a solver-neutral objective vector.
|
|
1363
1371
|
c = abc.Objective(self.nvars)
|
|
1364
1372
|
if objective == "maxSpending":
|
|
1365
|
-
c.setElem(_q1(Cg, 0, Nn), -1)
|
|
1373
|
+
# c.setElem(_q1(Cg, 0, Nn), -1)
|
|
1374
|
+
for n in range(Nn):
|
|
1375
|
+
c.setElem(_q1(Cg, n, Nn), -1/self.gamma_n[n])
|
|
1366
1376
|
elif objective == "maxBequest":
|
|
1367
1377
|
for i in range(Ni):
|
|
1368
1378
|
c.setElem(_q3(Cb, i, 0, Nn, Ni, Nj, Nn + 1), -1)
|
|
@@ -1608,6 +1618,7 @@ class Plan(object):
|
|
|
1608
1618
|
"units",
|
|
1609
1619
|
"maxRothConversion",
|
|
1610
1620
|
"netSpending",
|
|
1621
|
+
"spendingSlack",
|
|
1611
1622
|
"bequest",
|
|
1612
1623
|
"bigM",
|
|
1613
1624
|
"noRothConversions",
|
|
@@ -1642,6 +1653,7 @@ class Plan(object):
|
|
|
1642
1653
|
if objective == "maxSpending" and "bequest" not in myoptions:
|
|
1643
1654
|
self.mylog.vprint("Using bequest of $1.")
|
|
1644
1655
|
|
|
1656
|
+
self.prevMAGI = np.zeros(2)
|
|
1645
1657
|
if "previousMAGIs" in myoptions:
|
|
1646
1658
|
magi = myoptions["previousMAGIs"]
|
|
1647
1659
|
if len(magi) != 2:
|
|
@@ -1653,6 +1665,13 @@ class Plan(object):
|
|
|
1653
1665
|
units = 1000
|
|
1654
1666
|
self.prevMAGI = units * np.array(magi)
|
|
1655
1667
|
|
|
1668
|
+
self.lambdha = 0
|
|
1669
|
+
if "spendingSlack" in myoptions:
|
|
1670
|
+
lambdha = myoptions["spendingSlack"]
|
|
1671
|
+
if lambdha < 0 or lambdha > 50:
|
|
1672
|
+
raise ValueError(f"Slack value out of range {lambdha}.")
|
|
1673
|
+
self.lambdha = lambdha / 100
|
|
1674
|
+
|
|
1656
1675
|
self._adjustParameters()
|
|
1657
1676
|
|
|
1658
1677
|
if "solver" in options:
|
owlplanner/rates.py
CHANGED
|
@@ -110,6 +110,9 @@ def getRatesDistributions(frm, to, mylog=None):
|
|
|
110
110
|
# Build correlation matrix by dividing by the stdev for each column and row.
|
|
111
111
|
corr = covar / stdev[:, None]
|
|
112
112
|
corr = corr.T / stdev[:, None]
|
|
113
|
+
# Fold round-off errors in proper bounds.
|
|
114
|
+
corr[corr > 1] = 1
|
|
115
|
+
corr[corr < -1] = -1
|
|
113
116
|
mylog.print("correlation matrix: \n\t\t%s" % str(corr).replace("\n", "\n\t\t"))
|
|
114
117
|
|
|
115
118
|
return means, stdev, corr, covar
|
owlplanner/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2025.03.
|
|
1
|
+
__version__ = "2025.03.27"
|
|
@@ -2,16 +2,16 @@ owlplanner/__init__.py,sha256=QqrdT0Qks20osBTg7h0vJHAxpP9lL7DA99xb0nYbtw4,254
|
|
|
2
2
|
owlplanner/abcapi.py,sha256=LbzW_KcNy0IeHp42MUHwGu_H67B2h_e1_vu-c2ACTkQ,6646
|
|
3
3
|
owlplanner/config.py,sha256=uJ6jZ9Rx2CB2P5cFRscsUCXOW6uml7I4pta2ozjW0uo,12263
|
|
4
4
|
owlplanner/logging.py,sha256=tYMw04O-XYSzjTj36fmKJGLcE1VkK6k6oJNeqtKXzuc,2530
|
|
5
|
-
owlplanner/plan.py,sha256=
|
|
5
|
+
owlplanner/plan.py,sha256=F243hFv85IIanKtnyjgbGJ1W0Mz8uBBeHBBwW5b9u0k,116830
|
|
6
6
|
owlplanner/progress.py,sha256=8jlCvvtgDI89zXVNMBg1-lnEyhpPvKQS2X5oAIpoOVQ,384
|
|
7
|
-
owlplanner/rates.py,sha256=
|
|
7
|
+
owlplanner/rates.py,sha256=gJaoe-gJqWCQV5qVLlHp-Yn9TSJs-PJzeTbOwMCbqWs,15682
|
|
8
8
|
owlplanner/tax2025.py,sha256=B-A5eU3wxdcAaxRCbT3qI-JEKoD_ZeNbg_86XhNdQEI,7745
|
|
9
9
|
owlplanner/timelists.py,sha256=tYieZU67FT6TCcQQis36JaXGI7dT6NqD7RvdEjgJL4M,4026
|
|
10
10
|
owlplanner/utils.py,sha256=WpJgn79YZfH8UCkcmhd-AZlxlGuz1i1-UDBRXImsY6I,2485
|
|
11
|
-
owlplanner/version.py,sha256=
|
|
11
|
+
owlplanner/version.py,sha256=eT4mV245NLOvKScOuf87I7NOI5wxmOs9MVCyrVUkZeQ,28
|
|
12
12
|
owlplanner/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
owlplanner/data/rates.csv,sha256=6fxg56BVVORrj9wJlUGFdGXKvOX5r7CSca8uhUbbuIU,3734
|
|
14
|
-
owlplanner-2025.3.
|
|
15
|
-
owlplanner-2025.3.
|
|
16
|
-
owlplanner-2025.3.
|
|
17
|
-
owlplanner-2025.3.
|
|
14
|
+
owlplanner-2025.3.27.dist-info/METADATA,sha256=hBZoDMbIKBNeQ2vnRLzDovLileZGC05aTXDzo4BxJ04,53801
|
|
15
|
+
owlplanner-2025.3.27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
16
|
+
owlplanner-2025.3.27.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
|
17
|
+
owlplanner-2025.3.27.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|