owlplanner 2025.8.1__py3-none-any.whl → 2025.9.15__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/config.py CHANGED
@@ -296,6 +296,10 @@ def readConfig(file, *, verbose=True, logstreams=None, readContributions=True):
296
296
  # Solver Options.
297
297
  p.solverOptions = diconf["Solver Options"]
298
298
 
299
+ # Address legacy case files.
300
+ if diconf["Solver Options"].get("withMedicare", None) is True:
301
+ p.solverOptions["withMedicare"] = "loop"
302
+
299
303
  # Check consistency of noRothConversions.
300
304
  name = p.solverOptions.get("noRothConversions", "None")
301
305
  if name != "None" and name not in p.inames:
owlplanner/plan.py CHANGED
@@ -1021,7 +1021,7 @@ class Plan(object):
1021
1021
  Refer to companion document for explanations.
1022
1022
  All binary variables must be lumped at the end of the vector.
1023
1023
  """
1024
- medi = options.get("optimizeMedicare", False)
1024
+ medi = options.get("withMedicare", "loop") == "optimize"
1025
1025
 
1026
1026
  # Stack all variables in a single block vector with all binary variables at the end.
1027
1027
  C = {}
@@ -1386,7 +1386,7 @@ class Plan(object):
1386
1386
  self.B.setRange(_q3(self.C["zx"], i, n, 1, self.N_i, self.N_n, self.N_zx), 0, 0)
1387
1387
 
1388
1388
  def _configure_Medicare_binary_variables(self, options):
1389
- if not options.get("optimizeMedicare", False):
1389
+ if options.get("withMedicare", "loop") != "optimize":
1390
1390
  return
1391
1391
 
1392
1392
  bigM = options.get("bigM", 5e6)
@@ -1444,7 +1444,7 @@ class Plan(object):
1444
1444
  self.A.addRow(row2, -np.inf, rhs2)
1445
1445
 
1446
1446
  def _add_Medicare_costs(self, options):
1447
- if not options.get("optimizeMedicare", False):
1447
+ if options.get("withMedicare", "loop") != "optimize":
1448
1448
  return
1449
1449
 
1450
1450
  for n in range(self.nm):
@@ -1627,7 +1627,7 @@ class Plan(object):
1627
1627
  "netSpending",
1628
1628
  "noRothConversions",
1629
1629
  "oppCostX",
1630
- "optimizeMedicare",
1630
+ "withMedicare",
1631
1631
  "previousMAGIs",
1632
1632
  "solver",
1633
1633
  "spendingSlack",
@@ -1635,7 +1635,6 @@ class Plan(object):
1635
1635
  "units",
1636
1636
  "xorConstraints",
1637
1637
  "withSCLoop",
1638
- "withMedicare", # Ignore keyword.
1639
1638
  ]
1640
1639
  # We might modify options if required.
1641
1640
  options = {} if options is None else options
@@ -1713,7 +1712,7 @@ class Plan(object):
1713
1712
  """
1714
1713
  Self-consistent loop, regardless of solver.
1715
1714
  """
1716
- optimizeMedicare = options.get("optimizeMedicare", False)
1715
+ includeMedicare = options.get("withMedicare", "loop") == "loop"
1717
1716
  withSCLoop = options.get("withSCLoop", True)
1718
1717
 
1719
1718
  if objective == "maxSpending":
@@ -1724,7 +1723,7 @@ class Plan(object):
1724
1723
  it = 0
1725
1724
  old_x = np.zeros(self.nvars)
1726
1725
  old_objfns = [np.inf]
1727
- self._computeNLstuff(None, optimizeMedicare)
1726
+ self._computeNLstuff(None, includeMedicare)
1728
1727
  while True:
1729
1728
  objfn, xx, solverSuccess, solverMsg = solverMethod(objective, options)
1730
1729
 
@@ -1735,7 +1734,7 @@ class Plan(object):
1735
1734
  if not withSCLoop:
1736
1735
  break
1737
1736
 
1738
- self._computeNLstuff(xx, optimizeMedicare)
1737
+ self._computeNLstuff(xx, includeMedicare)
1739
1738
 
1740
1739
  delta = xx - old_x
1741
1740
  absSolDiff = np.sum(np.abs(delta), axis=0)/100
@@ -1955,7 +1954,7 @@ class Plan(object):
1955
1954
 
1956
1955
  return J_n
1957
1956
 
1958
- def _computeNLstuff(self, x, optimizeMedicare):
1957
+ def _computeNLstuff(self, x, includeMedicare):
1959
1958
  """
1960
1959
  Compute MAGI, Medicare costs, long-term capital gain tax rate, and
1961
1960
  net investment income tax (NIIT).
@@ -1972,7 +1971,7 @@ class Plan(object):
1972
1971
  self.J_n = self._computeNIIT(self.MAGI_n, self.I_n, self.Q_n)
1973
1972
  self.psi_n = tx.capitalGainTaxRate(self.N_i, self.MAGI_n, self.gamma_n[:-1], self.n_d, self.N_n)
1974
1973
  # Compute Medicare through self-consistent loop.
1975
- if not optimizeMedicare:
1974
+ if includeMedicare:
1976
1975
  self.M_n = tx.mediCosts(self.yobs, self.horizons, self.MAGI_n, self.prevMAGI, self.gamma_n[:-1], self.N_n)
1977
1976
 
1978
1977
  return None
owlplanner/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2025.08.01"
1
+ __version__ = "2025.09.15"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.8.1
3
+ Version: 2025.9.15
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
@@ -744,7 +744,7 @@ Look at *Basic capabilities* below for more detail.
744
744
  One can certainly have a savings plan, but due to the volatility of financial investments,
745
745
  it is impossible to have a certain asset earnings plan. This does not mean one cannot make decisions.
746
746
  These decisions need to be guided with an understanding of the sensitivity of the parameters.
747
- This is exactly where this tool fits it. Given your savings capabilities and spending desires,
747
+ This is exactly where this tool fits in. Given your savings capabilities and spending desires,
748
748
  it can generate different future realizations of
749
749
  your strategy under different market assumptions, helping to better understand your financial situation.
750
750
 
@@ -1,14 +1,14 @@
1
1
  owlplanner/__init__.py,sha256=hJ2i4m2JpHPAKyQLjYOXpJzeEsgcTcKD-Vhm0AIjjWg,592
2
2
  owlplanner/abcapi.py,sha256=rtg7d0UbftinokR9VlB49VUjDjzUq3ONnJbhMXVIrgo,6879
3
- owlplanner/config.py,sha256=JJOtS6HyqA4qUHUZydSGG_RMWaCfVMRSOAfWbt4evMI,12461
3
+ owlplanner/config.py,sha256=UF2Dy6E9PiX6Ua8B1R0aYCNUoIYmY46up8awf_36B_Q,12615
4
4
  owlplanner/mylogging.py,sha256=OVGeDFO7LIZG91R6HMpZBzjno-B8PH8Fo00Jw2Pdgqw,2558
5
- owlplanner/plan.py,sha256=keKC9-XeQxza9--D7TaQfcZCLkGDy5yVV9D5pN25MHg,115211
5
+ owlplanner/plan.py,sha256=pIKULy5GFo_8xOZByZ9_CXrHx9TcXQpaob8cblK46N8,115180
6
6
  owlplanner/progress.py,sha256=dUUlFmSAKUei36rUj2BINRY10f_YEUo_e23d0es6nrc,530
7
7
  owlplanner/rates.py,sha256=9Nmo8AKsyi5PoCUrzhr06phkSlNTv-TXzj5iYFU76AY,14113
8
8
  owlplanner/tax2025.py,sha256=2Jb_UbPT6ye-znRjA0nSaF8T8M17QW4MoRPDoW9XJ8s,10833
9
9
  owlplanner/timelists.py,sha256=Q4kBt9kKAa5qxsvOe9wfyUtCQVgiwPmJXTwXUPRBBv8,4066
10
10
  owlplanner/utils.py,sha256=afAjeO6Msf6Rn4jwz_7Ody9rHGWlBR7iQFqe1xzLNQc,2513
11
- owlplanner/version.py,sha256=Or3KaHd8BXidAsAkScGwQRvtWIF5uufpsnfgNdR-Kpw,28
11
+ owlplanner/version.py,sha256=zy-IhWuHFT4sXG7yuvz7mQvMfgQ6BwWFA7KrAtVvwYg,28
12
12
  owlplanner/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  owlplanner/data/rates.csv,sha256=6fxg56BVVORrj9wJlUGFdGXKvOX5r7CSca8uhUbbuIU,3734
14
14
  owlplanner/plotting/__init__.py,sha256=uhxqtUi0OI-QWNOO2LkXgQViW_9yM3rYb-204Wit974,250
@@ -16,7 +16,7 @@ owlplanner/plotting/base.py,sha256=UimGKpMTV-dVm3BX5Apr_Ltorc7dlDLCRPRQ3RF_v7c,2
16
16
  owlplanner/plotting/factory.py,sha256=EDopIAPQr9zHRgemObko18FlCeRNhNCoLNNFAOq-X6s,1030
17
17
  owlplanner/plotting/matplotlib_backend.py,sha256=AOEkapD94U5hGNoS0EdbRoe8mgdMHH4oOvkXADZS914,17957
18
18
  owlplanner/plotting/plotly_backend.py,sha256=AO33GxBHGYG5osir_H1iRRtGxdhs4AjfLV2d_xm35nY,33138
19
- owlplanner-2025.8.1.dist-info/METADATA,sha256=9WRoRbNMdk2kxbT4-Coq912VJixT9rlF1Cv48Po4VJw,54044
20
- owlplanner-2025.8.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
- owlplanner-2025.8.1.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
22
- owlplanner-2025.8.1.dist-info/RECORD,,
19
+ owlplanner-2025.9.15.dist-info/METADATA,sha256=yacvHpuuPAtZ4fvLHH2UcbIdtkWwgVc0zwIvtOBNw64,54045
20
+ owlplanner-2025.9.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
+ owlplanner-2025.9.15.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
22
+ owlplanner-2025.9.15.dist-info/RECORD,,