import%20marimo%0A%0A__generated_with%20%3D%20%220.14.13%22%0Aapp%20%3D%20marimo.App()%0A%0Awith%20app.setup%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20from%20cvxcla%20import%20CLA%2C%20FactorCovariance%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%23%20From%20Marchenko-Pastur%20to%20Woodbury%0A%0A%20%20%20%20We%20trace%20the%20**exact**%20efficient%20frontier%20of%20an%20RMT-cleaned%20covariance%0A%20%20%20%20without%20ever%20forming%20an%20%24n%20%5Ctimes%20n%24%20matrix.%0A%0A%20%20%20%201.%20Simulate%20returns%20with%20a%20latent%20factor%20structure.%0A%20%20%20%202.%20Clip%20the%20sample%20eigenvalues%20at%20the%20Marchenko-Pastur%20edge.%0A%20%20%20%203.%20The%20cleaned%20covariance%20is%20diagonal-plus-low-rank%2C%0A%20%20%20%20%20%20%20%24%5CSigma%20%3D%20%5Cbar%7Bd%7D%5C%2C%20I%20%2B%20V_k%20(%5CLambda_k%20-%20%5Cbar%7Bd%7D%20I)%20V_k%5E%5Ctop%24%2C%0A%20%20%20%20%20%20%20which%20is%20exactly%20what%20%60FactorCovariance%60%20solves%20via%20the%20Woodbury%0A%20%20%20%20%20%20%20identity%20in%20%24O(nk)%24%20memory.%0A%20%20%20%204.%20Hand%20it%20to%20%60CLA%60%20and%20plot%20the%20frontier.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20n_slider%20%3D%20mo.ui.slider(100%2C%201000%2C%20step%3D100%2C%20value%3D500%2C%20label%3D%22Number%20of%20assets%22)%0A%20%20%20%20n_slider%0A%20%20%20%20return%20(n_slider%2C)%0A%0A%0A%40app.function(hide_code%3DTrue)%0Adef%20simulate_returns(rng%2C%20t%2C%20n%2C%20k_true%3D10)%3A%0A%20%20%20%20%22%22%22Simulate%20t%20observations%20of%20n%20asset%20returns%20with%20k_true%20latent%20factors.%22%22%22%0A%20%20%20%20exposures%20%3D%20rng.standard_normal((n%2C%20k_true))%20*%200.3%0A%20%20%20%20factor_returns%20%3D%20rng.standard_normal((t%2C%20k_true))%0A%20%20%20%20idiosyncratic%20%3D%20rng.standard_normal((t%2C%20n))%0A%20%20%20%20return%20factor_returns%20%40%20exposures.T%20%2B%20idiosyncratic%0A%0A%0A%40app.function(hide_code%3DTrue)%0Adef%20clip_covariance(returns)%3A%0A%20%20%20%20%22%22%22Clean%20the%20sample%20covariance%20by%20Marchenko-Pastur%20eigenvalue%20clipping.%0A%0A%20%20%20%20Eigenvalues%20above%20the%20MP%20upper%20edge%20are%20kept%3B%20the%20remainder%20are%20replaced%0A%20%20%20%20by%20their%20average%2C%20preserving%20the%20trace.%20The%20result%20is%20the%0A%20%20%20%20diagonal-plus-low-rank%20model%20d%20*%20I%20%2B%20U%20%40%20diag(delta)%20%40%20U.T.%0A%20%20%20%20%22%22%22%0A%20%20%20%20t%2C%20n%20%3D%20returns.shape%0A%20%20%20%20sample%20%3D%20returns.T%20%40%20returns%20%2F%20t%0A%20%20%20%20eigenvalues%2C%20eigenvectors%20%3D%20np.linalg.eigh(sample)%0A%0A%20%20%20%20%23%20Marchenko-Pastur%20upper%20edge%20for%20variance%20sigma%5E2%20and%20aspect%20ratio%20n%2Ft%0A%20%20%20%20noise_variance%20%3D%20np.median(eigenvalues)%20%2F%20(1%20-%20np.sqrt(n%20%2F%20t))%20**%202%0A%20%20%20%20edge%20%3D%20noise_variance%20*%20(1%20%2B%20np.sqrt(n%20%2F%20t))%20**%202%0A%0A%20%20%20%20keep%20%3D%20eigenvalues%20%3E%20edge%0A%20%20%20%20d_bar%20%3D%20float(eigenvalues%5B~keep%5D.mean())%0A%0A%20%20%20%20u%20%3D%20eigenvectors%5B%3A%2C%20keep%5D%0A%20%20%20%20delta%20%3D%20eigenvalues%5Bkeep%5D%20-%20d_bar%0A%20%20%20%20return%20FactorCovariance(d%3Dnp.full(n%2C%20d_bar)%2C%20u%3Du%2C%20delta%3Ddelta)%0A%0A%0A%40app.cell%0Adef%20_(n_slider)%3A%0A%20%20%20%20rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20n%20%3D%20n_slider.value%0A%20%20%20%20returns%20%3D%20simulate_returns(rng%2C%20t%3D2%20*%20n%2C%20n%3Dn)%0A%20%20%20%20covariance%20%3D%20clip_covariance(returns)%0A%20%20%20%20mo.md(f%22Kept%20**%7Bcovariance.k%7D**%20factors%20out%20of%20%7Bn%7D%20sample%20eigenvalues.%22)%0A%20%20%20%20return%20covariance%2C%20n%2C%20rng%0A%0A%0A%40app.cell%0Adef%20_(covariance%2C%20n%2C%20rng)%3A%0A%20%20%20%20frontier%20%3D%20CLA(%0A%20%20%20%20%20%20%20%20mean%3Drng.uniform(0.0%2C%200.1%2C%20n)%2C%0A%20%20%20%20%20%20%20%20covariance%3Dcovariance%2C%0A%20%20%20%20%20%20%20%20lower_bounds%3Dnp.zeros(n)%2C%0A%20%20%20%20%20%20%20%20upper_bounds%3Dnp.ones(n)%2C%0A%20%20%20%20%20%20%20%20a%3Dnp.ones((1%2C%20n))%2C%0A%20%20%20%20%20%20%20%20b%3Dnp.ones(1)%2C%0A%20%20%20%20).frontier%0A%20%20%20%20mo.md(f%22The%20exact%20frontier%20has%20**%7Blen(frontier)%7D**%20turning%20points.%22)%0A%20%20%20%20return%20(frontier%2C)%0A%0A%0A%40app.cell%0Adef%20_(frontier)%3A%0A%20%20%20%20frontier.plot(volatility%3DTrue)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
26c3294b6272be66f840036cf13b557c2445a186ff2d598cd3ed84ebf769186d