owlplanner 2025.4.7__py3-none-any.whl → 2025.4.26__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 CHANGED
@@ -304,8 +304,8 @@ class Plan(object):
304
304
  self.myRothX_in = np.zeros((self.N_i, self.N_n))
305
305
  self.kappa_ijn = np.zeros((self.N_i, self.N_j, self.N_n))
306
306
 
307
- # Previous 2 years for Medicare.
308
- self.prevMAGI = np.zeros((2))
307
+ # Previous 3 years for Medicare.
308
+ self.prevMAGI = np.zeros((3))
309
309
 
310
310
  # Default slack on profile.
311
311
  self.lambdha = 0
@@ -1087,15 +1087,10 @@ class Plan(object):
1087
1087
  Tau1_ijn = 1 + tau_ijn
1088
1088
  Tauh_ijn = 1 + tau_ijn / 2
1089
1089
 
1090
- if "units" in options:
1091
- units = u.getUnits(options["units"])
1092
- else:
1093
- units = 1000
1094
-
1095
- bigM = 5e6
1096
- if "bigM" in options:
1097
- # No units for bigM.
1098
- bigM = options["bigM"]
1090
+ units = u.getUnits(options.get("units", "k"))
1091
+ # No units for bigM.
1092
+ bigM = options.get("bigM", 5e6)
1093
+ assert isinstance(bigM, (int, float)), f"bigM {bigM} is not a number."
1099
1094
 
1100
1095
  ###################################################################
1101
1096
  # Inequality constraint matrix with upper and lower bound vectors.
@@ -1668,16 +1663,13 @@ class Plan(object):
1668
1663
  if objective == "maxSpending" and "bequest" not in myoptions:
1669
1664
  self.mylog.vprint("Using bequest of $1.")
1670
1665
 
1671
- self.prevMAGI = np.zeros(2)
1666
+ self.prevMAGI = np.zeros(3)
1672
1667
  if "previousMAGIs" in myoptions:
1673
1668
  magi = myoptions["previousMAGIs"]
1674
- if len(magi) != 2:
1675
- raise ValueError("previousMAGIs must have two values.")
1669
+ if len(magi) != 3:
1670
+ raise ValueError("previousMAGIs must have 3 values.")
1676
1671
 
1677
- if "units" in options:
1678
- units = u.getUnits(options["units"])
1679
- else:
1680
- units = 1000
1672
+ units = u.getUnits(options.get("units", "k"))
1681
1673
  self.prevMAGI = units * np.array(magi)
1682
1674
 
1683
1675
  self.lambdha = 0
@@ -1722,7 +1714,7 @@ class Plan(object):
1722
1714
  objFac = -1 / self.gamma_n[-1]
1723
1715
 
1724
1716
  # mip_rel_gap smaller than 1e-6 can lead to oscillatory solutions.
1725
- milpOptions = {"disp": False, "mip_rel_gap": 1e-6}
1717
+ milpOptions = {"disp": False, "mip_rel_gap": 1e-7}
1726
1718
 
1727
1719
  it = 0
1728
1720
  absdiff = np.inf
owlplanner/tax2025.py CHANGED
@@ -90,16 +90,17 @@ def mediCosts(yobs, horizons, magi, prevmagi, gamma_n, Nn):
90
90
  Ni = len(yobs)
91
91
  costs = np.zeros(Nn)
92
92
  for n in range(Nn):
93
+ status = 0 if Ni == 1 else 1 if n < horizons[0] and n < horizons[1] else 0
93
94
  for i in range(Ni):
94
95
  if thisyear + n - yobs[i] >= 65 and n < horizons[i]:
95
96
  # Start with the (indexed) basic Medicare part B premium.
96
97
  costs[n] += gamma_n[n] * irmaaFees[0]
97
- if n < 2:
98
+ if n < 3:
98
99
  mymagi = prevmagi[n]
99
100
  else:
100
101
  mymagi = magi[n - 2]
101
102
  for q in range(1, 6):
102
- if mymagi > gamma_n[n] * irmaaBrackets[Ni - 1][q]:
103
+ if mymagi > gamma_n[n] * irmaaBrackets[status][q]:
103
104
  costs[n] += gamma_n[n] * irmaaFees[q]
104
105
 
105
106
  return costs
owlplanner/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2025.04.07"
1
+ __version__ = "2025.04.26"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.4.7
3
+ Version: 2025.4.26
4
4
  Summary: Owl: Retirement planner with great wisdom
5
5
  Project-URL: HomePage, https://github.com/mdlacasse/owl
6
6
  Project-URL: Repository, https://github.com/mdlacasse/owl
@@ -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=F6GS3n02VeFX0GCVeM4J7Ra0in4N632W6TZIXk7Yj2w,12519
4
4
  owlplanner/logging.py,sha256=tYMw04O-XYSzjTj36fmKJGLcE1VkK6k6oJNeqtKXzuc,2530
5
- owlplanner/plan.py,sha256=obzXmEJhtkIhmTFOR02Q6g1deigUkFnufyv54EqvD5o,117672
5
+ owlplanner/plan.py,sha256=X__wXxR0teB8RfkfV1BMgo_F_uxNYEBWsVnYHJtifW0,117550
6
6
  owlplanner/progress.py,sha256=8jlCvvtgDI89zXVNMBg1-lnEyhpPvKQS2X5oAIpoOVQ,384
7
7
  owlplanner/rates.py,sha256=gJaoe-gJqWCQV5qVLlHp-Yn9TSJs-PJzeTbOwMCbqWs,15682
8
- owlplanner/tax2025.py,sha256=HEXfL0HfwUvZOQRjivXO2jFeoVZ5m_yk_hoMiVi-hR0,7745
8
+ owlplanner/tax2025.py,sha256=JDBtFFAf2bWtKUMuE3W5F0nBhYaKBjmdJj0iayM2iGA,7829
9
9
  owlplanner/timelists.py,sha256=tYieZU67FT6TCcQQis36JaXGI7dT6NqD7RvdEjgJL4M,4026
10
10
  owlplanner/utils.py,sha256=WpJgn79YZfH8UCkcmhd-AZlxlGuz1i1-UDBRXImsY6I,2485
11
- owlplanner/version.py,sha256=FPy7IEsRPBEknOcrDUo7NESyU6IKoRY8pe0GXqxDOTc,28
11
+ owlplanner/version.py,sha256=UZqcSzscXDdd_zdDICloqhxdi1jWHPfAWPlpO1-9dSA,28
12
12
  owlplanner/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  owlplanner/data/rates.csv,sha256=6fxg56BVVORrj9wJlUGFdGXKvOX5r7CSca8uhUbbuIU,3734
14
- owlplanner-2025.4.7.dist-info/METADATA,sha256=IwB3uWgLwMizW1VVyuL5lSGFtKZmBzf2syDspcf6qOA,53926
15
- owlplanner-2025.4.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- owlplanner-2025.4.7.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
- owlplanner-2025.4.7.dist-info/RECORD,,
14
+ owlplanner-2025.4.26.dist-info/METADATA,sha256=3jihkQ5yNqbYpnyzZpImLUwYsyf9KnDu0Rn8HIewhu8,53927
15
+ owlplanner-2025.4.26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ owlplanner-2025.4.26.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
17
+ owlplanner-2025.4.26.dist-info/RECORD,,