import%20marimo%0A%0A__generated_with%20%3D%20%220.15.2%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22!%5BMOSEK%20ApS%5D(https%3A%2F%2Fwww.mosek.com%2Fstatic%2Fimages%2Fbranding%2Fwebgraphmoseklogocolor.png%20)%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%20Data-driven%20distributionally%20robust%20optimization%20(%5BMohajerin%20Esfahani%20and%20Kuhn%2C%202018%5D(https%3A%2F%2Frdcu.be%2FcbBoC))%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20This%20notebook%20illustrates%20%3Ci%3Eparameterization%3C%2Fi%3E%20in%20MOSEK's%20%5BFusion%20API%20for%20python%5D(https%3A%2F%2Fdocs.mosek.com%2F9.2%2Fpythonfusion%2Fintro_info.html)%2C%20by%20implementing%20the%20numerical%20experiments%20presented%20in%20a%20paper%20titled%20%3Ci%3E%20%22Data-driven%20distributionally%20robust%20optimization%20using%20the%20Wasserstein%20metric%3A%20performance%20guarantees%20and%20tractable%20reformulations%22%3C%2Fi%3E%20(%5BMohajerin%20Esfahani%20and%20Kuhn%5D(https%3A%2F%2Frdcu.be%2FcbBoC)%20hereafter)%2C%20authored%20by%20%5BPeyman%20Mohajerin%20Esfahani%5D(https%3A%2F%2Fscholar.google.co.in%2Fcitations%3Fuser%3DZTan-7YAAAAJ%26hl%3Den)%20and%20%5BDaniel%20Kuhn%5D(https%3A%2F%2Fscholar.google.com%2Fcitations%3Fuser%3DRqnXytkAAAAJ%26hl%3Den).%20%0A%0A%20%20%20%20%23%23%23%23%20Contents%3A%0A%20%20%20%201.%20%5BData-driven%20stochastic%20programming%20(Paper%20summary)%5D(%23Data-driven-stochastic-programming-(Paper-summary))%20%20%0A%20%20%20%20%20%20%20-%20%5BChoice%20of%20the%20ambiguity%20set%5D(%23Choice-of-the-ambiguity-set-%24%5Cwidehat%7B%5Cmathcal%7BP%7D%7D_N%24)%0A%20%20%20%20%20%20%20-%20%5BConvex%20reduction%20of%20the%20worst-case%20expectation%20problem%5D(%23Convex-reduction-of-the-worst-case-expectation-problem)%0A%0A%0A%20%20%20%202.%20%5BMean%20risk%20portfolio%20optimization%20with%20Fusion%20API%5D(%23Mean-risk-Portfolio-Optimization-(Section-7.1-in-paper))%20%20%0A%20%20%20%20%20%20%20-%20%5BParameterized%20Fusion%20model%5D(%23Parameterized-Fusion-model)%0A%20%20%20%20%20%20%20-%20%5BMarket%20setup%5D(%23Market-setup)%0A%0A%0A%20%20%20%203.%20%5BSimulations%20and%20results%5D(%23Simulations-and-results)%0A%0A%20%20%20%20%20%20%20-%20%5BImpact%20of%20the%20Wasserstein%20radius%5D(%23Impact-of-the-Wasserstein-radius)%0A%20%20%20%20%20%20%20-%20%5BPortflios%20driven%20by%20out-of-sample%20performance%5D(%23Portfolios-driven-by-out-of-sample-performance)%0A%20%20%20%20%20%20%20%20%20%20%20-%20%5BHoldout%20method%5D(%23Holdout-method)%0A%20%20%20%20%20%20%20%20%20%20%20-%20%5Bk-fold%20cross%20validation%20method%5D(%23k-fold-cross-validation-method)%0A%20%20%20%20%20%20%20-%20%5BPortfolios%20driven%20by%20reliability%5D(%23Portfolios-driven-by-reliability)%0A%20%20%20%20%20%20%20-%20%5BImpact%20of%20sample%20size%20on%20Wasserstein%20radius%5D(%23Impact-of-sample-size-on-Wasserstein-radius)%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%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%20Data-driven%20stochastic%20programming%20(Paper%20summary)%0A%0A%20%20%20%20Consider%20a%20loss%20function%20%24h(x%2C%5Cxi)%24%20which%20depends%20on%20the%20decision%20variables%20%24x%24%20and%20uncertain%20parameters%20%24%5Cxi%24.%20The%20goal%20is%20to%20minimize%20the%20%3Ci%3Eexpected%20value%3C%2Fi%3E%20of%20%24h(x%2C%5Cxi)%24%20for%20all%20%24x%5Cin%20%5Cmathbb%7BX%7D%24%2C%20where%20%24%5Cmathbb%7BX%7D%20%5Csubset%20%5Cmathbb%7BR%7D%5En%24.%20The%20expected%20value%20is%20calculated%20over%20%24%5Cmathbb%7BP%7D(%5Cxi)%24%2C%20which%20is%20the%20probability%20distribution%20of%20the%20random%20vector%20%24%5Cxi%20%5Cin%20%5Cmathbb%7BR%7D%5Em%24.%20This%20distribution%20is%20supported%20on%20the%20%3Ci%3Euncertainty%20set%3C%2Fi%3E%20%24%5CXi%24.%20The%20problem%20statement%20is%20written%20as%20in%20*Equation(1)*.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Bequation%7D%0A%20%20%20%20J%5E%5Cstar%20%3A%3D%20%5Cunderset%7Bx%5Cin%20%5Cmathbb%7BX%7D%7D%7B%5Cinf%7D%20%5Cbigg%5C%7B%20%5Cmathbb%7BE%7D%5E%7B%5Cmathbb%7BP%7D%7D%5Cbig%5B%20h(x%2C%5Cxi)%20%5Cbig%5D%20%3D%20%5Cint_%7B%5CXi%7D%20h(x%2C%5Cxi)%5Cmathbb%7BP%7D(d%5Cxi)%5Cbigg%5C%7D%0A%20%20%20%20%5Ctag%7B1%7D%0A%20%20%20%20%5Cend%7Bequation%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20In%20practice%2C%20however%2C%20the%20probability%20distribution%20is%20often%20unknown.%20Instead%2C%20one%20usually%20has%20access%20to%20a%20set%20%24%5Cwidehat%7B%5CXi%7D_N%20%3A%3D%20%5C%7B%5Cwidehat%7B%5Cxi%7D_i%20%5C%7D_%7Bi%5Cleq%20N%7D%24%2C%20that%20contains%20%24N%24%20historic%20realizations%20of%20the%20%24%5Cxi%24%20vector.%20A%20%3Ci%3Edata-driven%3C%2Fi%3E%20solution%20%24%5Cwidehat%7Bx%7D_N%24%20can%20be%20constructed%20by%20using%20some%20approximation%20of%20the%20true%20probability%20distribution.%20A%20natural%20choice%20for%20such%20an%20approximation%20is%20based%20on%20%24%5Cwidehat%7B%5CXi%7D_N%24%2C%20and%20it%20is%20given%20by%20the%20%3Ci%3Ediscrete%20empirical%3C%2Fi%3E%20probability%20distribution%2C%20as%20shown%20in%20*Equation(2)*%24.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Bequation%7D%0A%20%20%20%20%5Cmathbb%7B%5Cwidehat%7BP%7D%7D_N%20%3A%3D%20%5Cfrac%7B1%7D%7BN%7D%5Csum%5E%7BN%7D_%7Bi%20%3D%201%7D%20%5Cdelta_%7B%5Cwidehat%7B%5Cxi%7D_i%7D%0A%20%20%20%20%5Ctag%7B2%7D%0A%20%20%20%20%5Cend%7Bequation%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20%3Ci%3Esample-average-approximation%3C%2Fi%3E%2C%20which%20is%20obtained%20by%20replacing%20%24%5Cmathbb%7BP%7D%24%20with%20%24%5Cmathbb%7B%5Cwidehat%7BP%7D%7D_N%24%20in%20*Equation(1)*%2C%20is%20usually%20easier%20to%20solve%20but%20shows%20poor%20%3Ci%3Eout-of-sample%3C%2Fi%3E%20performance.%20Out-of-sample%20performance%20of%20a%20data-driven%20solution%20%24%5Cwidehat%7Bx%7D_N%24%20is%20the%20expected%20loss%20for%20that%20decision%20under%20the%20%3Ci%3Etrue%3C%2Fi%3E%20probability%20distribution.%20To%20obtain%20better%20out-of-sample%20performance%2C%20%5BMohajerin%20Esfahani%20and%20Kuhn%5D(https%3A%2F%2Frdcu.be%2FcbBoC)%20solve%20the%20robust%20optimization%20problem%20stated%20in%20*Equation(3)*.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Bequation%7D%0A%20%20%20%20%5Cwidehat%7BJ%7D_N%20%3A%3D%20%5Cunderset%7Bx%5Cin%20%5Cmathbb%7BX%7D%7D%7B%5Cinf%7D%20%5Cunderset%7B%5Cmathbb%7BQ%7D%5Cin%20%5Cmathcal%7B%5Cwidehat%7BP%7D%7D_N%7D%5Csup%20%5Cmathbb%7BE%7D%5E%5Cmathbb%7BQ%7D%5Cbig%5B%20h(x%2C%20%5Cxi)%5Cbig%5D%0A%20%20%20%20%5Ctag%7B3%7D%0A%20%20%20%20%5Cend%7Bequation%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20%3Ci%3E%3Cb%3E%20distributionally%3C%2Fb%3E%20robust%3C%2Fi%3E%20problem%20stated%20in%20*Equation(3)*%20is%20conceptually%20similar%20to%20*Equation(1)*%2C%20%3Ci%3Ebut%3C%2Fi%3E%20it%20compensates%20for%20the%20unknown%20%24%5Cmathbb%7BP%7D%24%20by%20%3Ci%3Emaximizing%3C%2Fi%3E%20the%20expected%20value%20over%20all%20probability%20distributions%20%24%5Cmathbb%7BQ%7D%24%20inside%20an%20ambiguity%20set%20%24%5Cwidehat%7B%5Cmathcal%7BP%7D%7D_N%24.%20Maximization%20is%20done%20in%20order%20to%20obtain%20the%20worst-case%20estimate.%0A%0A%20%20%20%20If%20%24%5Cwidehat%7Bx%7D_N%24%20is%20an%20optimal%20decision%20vector%20for%20the%20distributionally%20robust%20program%2C%20then%20the%20authors%20associate%20performance%20guarantees%20to%20%24%5Cwidehat%7Bx%7D_N%24%20of%20the%20type%20shown%20in%20*Equation(4)*.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Bequation%7D%0A%20%20%20%20%5Cmathbb%7BP%7D%5EN%20%5Cbigg%5C%7B%20%5Cwidehat%7B%5CXi%7D_N%20%3A%20%5Cmathbb%7BE%7D%5E%5Cmathbb%7BP%7D%5Cbig%5B%20h(%5Cwidehat%7Bx%7D_N%2C%20%5Cxi)%20%5Cbig%5D%20%5Cleq%20%5Cwidehat%7BJ%7D_N%20%5Cbigg%20%5C%7D%20%5Cgeq%201%20-%20%5Cbeta%0A%20%20%20%20%5Ctag%7B4%7D%0A%20%20%20%20%5Cend%7Bequation%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Here%2C%20%24%5Cmathbb%7BP%7D%5EN%24%20is%20a%20probability%20distribution%20that%20governs%20the%20realization%20of%20the%20set%20%24%5Cwidehat%7B%5CXi%7D_N%24.%20The%20expression%20in%20*Equation(4)*%20states%20that%20%24%5Cwidehat%7BJ%7D_N%24%20provides%20an%20upper%20bound%20to%20the%20out-of-sample%20performance%20of%20%24%5Cwidehat%7Bx%7D_N%24%20with%20at%20least%20%241-%5Cbeta%24%20probability.%20Thus%2C%20%24%5Cwidehat%7BJ%7D_N%24%20is%20a%20%3Ci%3Ecertificate%3C%2Fi%3E%20of%20out-of-sample%20performance%20and%20the%20probability%20on%20the%20left%20side%20is%20the%20%3Ci%3Ereliability%3C%2Fi%3E%20of%20this%20certificate.%0A%0A%20%20%20%20%23%23%23%20Choice%20of%20the%20ambiguity%20set%20%24%5Cwidehat%7B%5Cmathcal%7BP%7D%7D_N%24%0A%0A%20%20%20%20The%20ambiguity%20set%20resides%20within%20a%20space%20of%20probability%20distributions%20and%20is%20chosen%20to%20be%20a%20%3Ci%3Eball%3C%2Fi%3E%20of%20radius%20%24%5Cepsilon%24%20centered%20at%20%24%5Cwidehat%7B%5Cmathbb%7BP%7D%7D_N%24.%20The%20metric%20of%20choice%20is%20the%20%5BWasserstein%20metric%5D(http%3A%2F%2Fnbviewer.jupyter.org%2Fgithub%2FMOSEK%2FTutorials%2Fblob%2Fmaster%2Fwasserstein%2Fwasserstein-bary.ipynb).%20Mathematically%2C%20the%20ambiguity%20set%20is%20defined%20as%20shown%20in%20*Equation(5)*.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Bequation%7D%0A%20%20%20%20%5Cmathbb%7BB%7D_%5Cepsilon(%5Cmathbb%7B%5Cwidehat%7BP%7D%7D_N)%20%3A%3D%20%5Cbig%5C%7B%20%5Cmathbb%7BQ%7D%20%5Cin%20%5Cmathcal%7BM%7D(%5CXi)%20%3A%20d_W%20(%5Cmathbb%7B%5Cwidehat%7BP%7D%7D_N%2C%20%5Cmathbb%7BQ%7D)%20%5Cleq%20%5Cepsilon%20%5Cbig%5C%7D%0A%20%20%20%20%5Ctag%7B5%7D%0A%20%20%20%20%5Cend%7Bequation%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20As%20proved%20in%20section%203%20of%20the%20paper%2C%20solving%20*Equation(3)*%20with%20%24%5Cmathcal%7B%5Cwidehat%7BP%7D%7D_N%24%20set%20to%20%24%5Cmathbb%7BB%7D_%5Cepsilon(%5Cmathbb%7B%5Cwidehat%7BP%7D%7D_N)%24%20will%20provide%20%3Ci%3Efinite%20sample%20performance%20guarantees%3C%2Fi%3E%20of%20the%20type%20seen%20in%20*Equation(4)*.%20Furthermore%2C%20given%20certain%20assumptions%20(see%20paper)%2C%20as%20%24N%5Cto%5Cinfty%24%2C%20the%20certificate%20%24%5Cwidehat%7BJ%7D_N%24%20approaches%20%24J%5E%5Cstar%24%20(optimal%20value%20of%20*Equation(1)*)%20and%20the%20data-driven%20decision%20%24%5Cwidehat%7Bx%7D_N%24%20approaches%20the%20true%20optimal%20decision%20%24x%5E%5Cstar%24.%0A%0A%20%20%20%20%23%23%23%20Convex%20reduction%20of%20the%20worst-case%20expectation%20problem%0A%0A%20%20%20%20The%20infinite%20dimensional%20maximization%20problem%20within%20*Equation(3)*%20can%20be%20reduced%20to%20a%20computationally%20tractable%20finite-dimensional%20convex%20program%2C%20given%20the%20following%20requirements%20are%20met%3A%0A%0A%20%20%20%201.)%20The%20uncertainty%20set%20%24%5CXi%24%20is%20convex%20and%20closed.%0A%0A%20%20%20%202.)%20The%20loss%20function%20is%20a%20point-wise%20maximum%20of%20more%20elementary%20functions%2C%20i.e.%20%24l(%5Cxi)%20%3A%3D%20%5Cunderset%7Bk%5Cleq%20K%7D%7B%5Cmax%7D%20l_k(%5Cxi)%24%2C%20where%20%24-l_k(%5Cxi)%24%20are%20proper%2C%20convex%2C%20and%20lower%20semi-continuous%20for%20all%20%24k%5Cleq%20K%24.%20%3Ci%3ENote%20the%20suppression%20of%20the%20loss%20function's%20dependence%20on%20%24x%24%3C%2Fi%3E.%0A%0A%20%20%20%20For%20problems%20that%20satisfy%20these%20requirements%2C%20the%20convex%20reduction%20is%20given%20in%20*Equation(6)*.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cinf_%7B%5Clambda%2C%20s_i%2C%20z_%7Bik%7D%2C%20%5Cnu_%7Bik%7D%7D%20%0A%20%20%20%20%5C%3B%20%5Clambda%20%5Cepsilon%20%2B%20%5Cfrac%7B1%7D%7BN%7D%5Csum_%7Bi%3D1%7D%5E%7BN%7Ds_i%20%0A%20%20%20%20%24%24%0A%0A%20%20%20%20subject%20to%20%20%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5B-l_k%5D%5E*(z_%7Bik%7D%20-%20%5Cnu_%7Bik%7D)%20%2B%20%5Csigma_%7B%5CXi%7D(%5Cnu_%7Bik%7D)%20-%20%5Clangle%20z_%7Bik%7D%2C%5Cwidehat%7B%5Cxi%7D_i%5Crangle%20%5Cleq%20s_i%2C%20%0A%20%20%20%20%5Cquad%20%5Cforall%20i%20%5Cleq%20N%2C%20%5C%3B%20%5Cforall%20k%20%5Cleq%20K%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5C%7Cz_%7Bik%7D%5C%7C_*%20%5Cleq%20%5Clambda%2C%20%0A%20%20%20%20%5Cquad%20%5Cforall%20i%20%5Cleq%20N%2C%20%5C%3B%20%5Cforall%20k%20%5Cleq%20K%0A%20%20%20%20%24%24%0A%0A%0A%20%20%20%20where%20%24%5B-l_k%5D%5E*%24%20denotes%20the%20conjugate%20of%20the%20negative%20%24k%5E%7B%5Ctext%7Bth%7D%7D%24%20component%20of%20the%20loss%20function%2C%20%24%5C%7Cz_%7Bik%7D%5C%7C_*%24%20is%20the%20dual%20norm%20corresponding%20to%20the%20norm%20used%20in%20defining%20the%20Wasserstein%20ball%20and%20%24%5Csigma_%5CXi%24%20is%20the%20support%20function%20for%20the%20uncertainty%20set.%0A%0A%20%20%20%20%23%20Mean%20risk%20Portfolio%20Optimization%20(Section%207.1%20in%20paper)%0A%0A%20%20%20%20Consider%20a%20market%20that%20forbids%20short-selling%20and%20has%20%24m%24%20assets.%20Yearly%20returns%20of%20these%20assets%20are%20given%20by%20the%20random%20vector%20%24%5Cxi%20%3D%20%5B%5Cxi_1%2C%20...%2C%20%5Cxi_m%5D%5ET%24.%20The%20%3Ci%3Epercentage%20weights%3C%2Fi%3E%20(of%20the%20total%20capital)%20invested%20in%20each%20asset%20are%20given%20by%20the%20decision%20vector%20%24x%20%3D%20%5Bx_1%2C%20...%2C%20x_m%5D%5ET%24%20where%20%24x%24%20belongs%20to%20%24%5Cmathbb%7BX%7D%20%3D%20%5C%7Bx%20%5Cin%20%5Cmathbb%7BR%7D_%2B%5Em%20%3A%20%5Csum%5E%7Bm%7D_%7Bi%3D1%7Dx_i%20%3D%201%5C%7D%24.%20We%20have%20to%20solve%20the%20problem%20stated%20in%20*Equation(7)*.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Bequation%7D%0A%20%20%20%20J%5E%5Cstar%20%3D%20%5Cunderset%7Bx%5Cin%20%5Cmathbb%7BX%7D%7D%7B%5Cinf%7D%20%5Cbig%5C%7B%20%5Cmathbb%7BE%7D%5E%7B%5Cmathbb%7BP%7D%7D%5B-%5Clangle%20x%2C%20%5Cxi%20%5Crangle%5D%20%2B%20%5Crho%20%5Cmathbb%7BP%7D%5Ctext%7B-CVaR%7D_%5Calpha%20%5Cbig(-%5Clangle%20x%2C%20%5Cxi%5Crangle%5Cbig)%5Cbig%5C%7D%0A%20%20%20%20%5Ctag%7B7%7D%0A%20%20%20%20%5Cend%7Bequation%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20which%20amounts%20to%20minimizing%20a%20weighted%20sum%20of%20the%20expected%20value%20and%20the%20conditional%20value-at-risk%20(see%20also%3A%20%5BFusion%20notebook%20on%20stochastic%20risk%20measures%5D(https%3A%2F%2Fnbviewer.jupyter.org%2Fgithub%2FMOSEK%2FTutorials%2Fblob%2Fmaster%2Fstochastic-risk%2Fstochastic-risk-measures.ipynb))%20of%20the%20portfolio%20loss%2C%20%24-%20%5Clangle%20x%2C%20%5Cxi%20%5Crangle%24.%20Using%20the%20definition%20of%20conditional%20value-at-risk%20(%5BOptimization%20of%20conditional%20value-at-risk%5D(https%3A%2F%2Fwww.ise.ufl.edu%2Furyasev%2Ffiles%2F2011%2F11%2FCVaR1_JOR.pdf)%20by%20R.%20T.%20Rockafellar%20and%20S.%20Uryasev)%2C%20*Equation(7)*%20can%20be%20written%20as%20a%20%3Ci%3Emaximum%20of%20%24K%3D2%24%20affine%20loss%20functions%3C%2Fi%3E%20(*Equation(8)*).%0A%0A%20%20%20%20%24%24%0A%20%20%20%20J%5E%5Cstar%20%3D%20%5Cinf_%7Bx%20%5Cin%20%5Cmathbb%7BX%7D%2C%20%5C%3B%20%5Ctau%20%5Cin%20%5Cmathbb%7BR%7D%7D%20%0A%20%20%20%20%5C%3B%20%5Cmathbb%7BE%7D%5E%7B%5Cmathbb%7BP%7D%7D%5C!%5Cleft%5B%5Cmax_%7Bk%20%5Cleq%20K%7D%20%5C%3B%20a_k%20%5Clangle%20x%2C%20%5Cxi%20%5Crangle%20%2B%20b_k%20%5Ctau%20%5Cright%5D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20where%20%20%0A%0A%20%20%20%20%24%24%0A%20%20%20%20a%20%3D%20%5Cleft(-1%2C%20%5C%3B%20-1-%5Ctfrac%7B%5Crho%7D%7B%5Calpha%7D%5Cright)%2C%20%0A%20%20%20%20%5Cquad%20%0A%20%20%20%20b%20%3D%20%5Cleft(%5Crho%2C%20%5C%3B%20%5Crho-%5Ctfrac%7B%5Crho%7D%7B%5Calpha%7D%5Cright)%0A%20%20%20%20%24%24%0A%0A%20%20%20%20If%20the%20uncertainty%20set%20is%20a%20polytope%20of%20the%20form%20%24%5CXi%20%3D%20%5C%7B%20%5Cxi%20%5Cin%20%5Cmathbb%7BR%7D%5Em%20%3A%20C%5Cxi%20%5Cleq%20d%20%5C%7D%24%2C%20then%20the%20distributionally%20robust%20counterpart%20of%20the%20program%20in%20*Equation(8)*%20will%20have%20a%20convex%20reduction%20as%20shown%20in%20*Equation(9)*.%20%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Balign%7D%0A%20%20%20%20%26%20%5Cunderset%7Bx%2C%5Ctau%2C%5Clambda%2Cs_i%2C%20%5Cgamma_%7Bik%7D%7D%7B%5Cinf%7D%20%26%20%26%20%5Clambda%20%5Cepsilon%20%2B%20%5Cfrac%7B1%7D%7BN%7D%5Csum%5E%7BN%7D_%7Bi%3D1%7Ds_i%20%26%20%5Cnonumber%20%5C%5C%0A%20%20%20%20%26%5Ctext%7Bs.t.%7D%20%26%20%26%20b_k%20%5Ctau%20%2B%20a_k%20%5Clangle%20x%2C%20%5Cwidehat%7B%5Cxi%7D_i%20%5Crangle%20%2B%20%5Clangle%20%5Cgamma_%7Bik%7D%2C%20d%20-%20C%5Cwidehat%7B%5Cxi%7D_i%5Crangle%20%5Cleq%20s_i%20%26%20%5Cforall%20i%5Cleq%20N%2C%20%5Cforall%20k%5Cleq%20K%20%5Ctag%7B9%7D%5C%5C%0A%20%20%20%20%26%20%26%20%26%5C%7C%20C%5ET%20%5Cgamma_%7Bik%7D%20-%20a_k%20x%5C%7C_*%20%5Cleq%20%5Clambda%20%26%20%5Cforall%20i%5Cleq%20N%2C%20%5Cforall%20k%5Cleq%20K%20%26%5Cnonumber%20%5C%5C%0A%20%20%20%20%26%20%26%20%26%20%5Cgamma_%7Bik%7D%20%5Cgeq%200%20%26%20%5Cforall%20i%20%5Cleq%20N%2C%20%5Cforall%20k%20%5Cleq%20K%20%26%20%5Cnonumber%20%5C%5C%0A%20%20%20%20%26%20%26%20%26%20x%20%5Cin%20%5Cmathbb%7BX%7D%20%26%20%5Cnonumber%20%5C%5C%0A%20%20%20%20%5Cend%7Balign%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%23%23%23%20Parameterized%20Fusion%20model%0A%0A%20%20%20%20Finally%2C%20we%20make%20a%20%5BFusion%5D(https%3A%2F%2Fdocs.mosek.com%2F9.2%2Fpythonfusion%2Fapi-reference.html)%20model%20for%20the%20program%20in%20*Equation(9)*.%20The%20following%20code%20cell%20defines%20%60DistributionallyRobustPortfolio%60%2C%20a%20wrapper%20class%20%20(around%20our%20fusion%20model)%20with%20some%20convenience%20methods.%20The%20key%20steps%20in%20the%20Fusion%20model%20implementation%20are%20(see%20%60portfolio_model%60%20method%20in%20class)%3A%0A%0A%20%20%20%20-%20%60M%20%3D%20Model('DistRobust_m%7B0%7D_N%7B1%7D'.format(m%2C%20N))%60%3A%20instantiate%20a%20Fusion%20%60Model%60%20object.%0A%0A%0A%20%20%20%20-%20%60dat%20%3D%20M.parameter('TrainData'%2C%20%5BN%2C%20m%5D)%60%20and%20%60eps%20%3D%20M.parameter('WasRadius')%60%3A%20declare%20a%20Fusion%20%60parameter%60%20object%20named%20%22TrainData%22%20and%20a%20parameter%20for%20the%20Wasserstein%20Radius%2C%20called%20%22WasRadius%22.%20%22TrainData%22%20represents%20the%20past%20%60N%60%20realizations%20of%20the%20%60m%60%20sized%20random%20vector%2C%20%24%5Cxi%24.%20%0A%0A%0A%20%20%20%20-%20%60a_k%20%3D%20%5B-1%2C%20-51%5D%60%20and%20%60b_k%20%3D%20%5B10%2C%20-40%5D%60%3A%20lists%20that%20are%20defined%20as%20in%20*Equation(8)*.%20All%20experiments%20that%20follow%20have%20the%20same%20%24a_k%24%20and%20%24b_k%24%2C%20therefore%20we%20use%20lists.%20However%2C%20with%20minor%20modifications%20these%20lists%20can%20be%20replaced%20with%20Fusion%20parameters.%20%0A%0A%0A%20%20%20%20-%20%60x%20%3D%20M.variable('Weights'%2C%20m%2C%20Domain.greaterThan(0.0))%60%3A%20declare%20Fusion%20variables%20for%20all%20the%20optimization%20variables%20involved%20in%20*Equation(9)*%2C%20%3Ci%3Eexcept%3C%2Fi%3E%20%24%5Cgamma%24%2C%20which%20is%20excluded%20as%20%24%5CXi%20%5Cin%20%5Cmathbb%7BR%7D%5Em%24%20(%5Bsee%20the%20market%20setup%20below%5D(%23Market-setup)).%0A%0A%0A%20%20%20%20-%20%60M.objective('J_N(e)'%2C%20ObjectiveSense.Minimize%2C%20certificate)%60%3A%20declare%20the%20objective%20sense%20and%20the%20expression%20of%20the%20objective.%20Here%20%60certificate%60%20is%20an%20%60Expr%60%20object%20that%20evaluates%20to%20the%20objective%20in%20*Equation(9)*.%0A%0A%0A%20%20%20%20-%20%60self.M.constraint('C1'%2CExpr.add(%5Be1%2C%20e2%2C%20Expr.neg(Expr.repeat(s%2C%202%2C%201))%5D)%2C%20Domain.lessThan(0.0))%60%3A%20defining%20the%20constraints.%20Here%20%60e1%60%20and%20%60e2%60%20are%20%60Expr%60%20objects%20that%20evaluate%20to%20the%20relevant%20terms%20in%20the%20first%20constraint%20in%20*Equation(9)*.%20Constraints%20%22C2_pos%22%20and%20%22C2_neg%22%20correspond%20to%20the%20second%20constraint%20and%20finally%20%22C3%22%20ensures%20that%20%24x%20%5Cin%20%5Cmathbb%7BX%7D%24.%0A%0A%0A%20%20%20%20-%20%60self.M.setSolverParam('optimizer'%2C'freeSimplex')%60%3A%20use%20the%20%5Bsimplex%20optimizer%5D(https%3A%2F%2Fdocs.mosek.com%2F9.2%2Fpythonfusion%2Fsolving-linear.html%23the-simplex-optimizer).%20By%20default%2C%20MOSEK%20will%20use%20its%20interior%20point%20optmizer.%20However%2C%20we%20plan%20to%20re-solve%20a%20linear%20model%20many%20times%20over%20and%20it%20is%20therefore%20imperative%20to%20exploit%20the%20warm-start%20capabilities%20of%20the%20simplex%20optimizer.%0A%0A%20%20%20%20%3Cb%3ENote%3C%2Fb%3E%3A%20More%20details%20regarding%20the%20code%20can%20be%20found%20within%20comments.%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_(Domain%2C%20Expr%2C%20Model%2C%20ObjectiveSense%2C%20np)%3A%0A%20%20%20%20class%20DistributionallyRobustPortfolio%3A%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20m%2C%20N)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.m%2C%20self.N%20%3D%20m%2C%20N%0A%20%20%20%20%20%20%20%20%20%20%20%20self.M%20%3D%20self.portfolio_model(m%2C%20N)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.x%20%3D%20self.M.getVariable('Weights')%0A%20%20%20%20%20%20%20%20%20%20%20%20self.t%20%3D%20self.M.getVariable('Tau')%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dat%20%3D%20self.M.getParameter('TrainData')%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eps%20%3D%20self.M.getParameter('WasRadius')%0A%20%20%20%20%20%20%20%20%20%20%20%20self.sol_time%20%3D%20%5B%5D%0A%0A%20%20%20%20%20%20%20%20def%20portfolio_model(self%2C%20m%2C%20N)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Parameterized%20Fusion%20model%20for%20program%20in%209.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20M%20%3D%20Model('DistRobust_m%7B0%7D_N%7B1%7D'.format(m%2C%20N))%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%20PARAMETERS%20%23%23%23%23%23%0A%20%20%20%20%20%20%20%20%20%20%20%20dat%20%3D%20M.parameter('TrainData'%2C%20%5BN%2C%20m%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20eps%20%3D%20M.parameter('WasRadius')%0A%20%20%20%20%20%20%20%20%20%20%20%20a_k%20%3D%20%5B-1%2C%20-51%5D%20%20%23%20Alternative%3A%20Fusion%20parameters.%0A%20%20%20%20%20%20%20%20%20%20%20%20b_k%20%3D%20%5B10%2C%20-40%5D%20%20%23%20Alternative%3A%20Fusion%20parameters.%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%20VARIABLES%20%23%23%23%23%23%0A%20%20%20%20%20%20%20%20%20%20%20%20x%20%3D%20M.variable('Weights'%2C%20m%2C%20Domain.greaterThan(0.0))%0A%20%20%20%20%20%20%20%20%20%20%20%20s%20%3D%20M.variable('s_i'%2C%20N)%0A%20%20%20%20%20%20%20%20%20%20%20%20l%20%3D%20M.variable('Lambda')%0A%20%20%20%20%20%20%20%20%20%20%20%20t%20%3D%20M.variable('Tau')%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%20OBJECTIVE%20%23%23%23%23%23%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20certificate%20%3D%20lamda*epsilon%20%2B%20sum(s)%2FN%0A%20%20%20%20%20%20%20%20%20%20%20%20certificate%20%3D%20eps%20*%20l%20%2B%20Expr.sum(s)%20%2F%20N%0A%20%20%20%20%20%20%20%20%20%20%20%20M.objective('J_N(e)'%2C%20ObjectiveSense.Minimize%2C%20certificate)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%20CONSTRAINTS%20%23%23%23%23%23%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20b_k*t%0A%20%20%20%20%20%20%20%20%20%20%20%20e1%20%3D%20Expr.repeat(t%20*%20b_k%2C%20N%2C%201).T%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20a_k*%3Cx%2Cxi%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20e2%20%3D%20Expr.hstack(%5Ba_k%5Bi%5D%20*%20(dat%20%40%20x)%20for%20i%20in%20range(2)%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20b_k*t%20%2B%20a_k*%3Cx%2Cxi%3E%20%3C%3D%20s%0A%20%20%20%20%20%20%20%20%20%20%20%20M.constraint('C1'%2C%20e1%20%2B%20e2%20%3C%3D%20Expr.repeat(s%2C%202%2C%201))%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20a_k*x%0A%20%20%20%20%20%20%20%20%20%20%20%20e3%20%3D%20Expr.hstack(%5Ba_k%5Bi%5D%20*%20x%20for%20i%20in%20range(2)%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20e4%20%3D%20Expr.repeat(Expr.repeat(l%2C%20m%2C%200)%2C%202%2C%201)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%7C%7Ca_k*x%7C%7C_infty%20%3C%3D%20lambda%0A%20%20%20%20%20%20%20%20%20%20%20%20M.constraint('C2_pos'%2C%20e4%20%3E%3D%20e3)%0A%20%20%20%20%20%20%20%20%20%20%20%20M.constraint('C2_neg'%2C%20e4%20%3E%3D%20-e3)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20x%20%5Cin%20X%0A%20%20%20%20%20%20%20%20%20%20%20%20M.constraint('C3'%2C%20Expr.sum(x)%20%3D%3D%201)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Use%20the%20simplex%20optimizer%0A%20%20%20%20%20%20%20%20%20%20%20%20M.setSolverParam('optimizer'%2C%20'freeSimplex')%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20M%0A%0A%20%20%20%20%20%20%20%20def%20sample_average(self%2C%20x%2C%20t%2C%20data)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Calculate%20the%20sample%20average%20approximation%20for%20given%20x%20and%20tau.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20l%20%3D%20np.matmul(data%2C%20x)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20np.mean(np.maximum(-l%20%2B%2010*t%2C%20-51*l%20-%2040*t))%0A%0A%20%20%20%20%20%20%20%20def%20iter_data(self%2C%20data_sets)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Generator%20method%20for%20iterating%20through%20values%20for%20the%20%0A%20%20%20%20%20%20%20%20%20%20%20%20TrainData%20parameter.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20data%20in%20data_sets%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20yield%20self.simulate(data)%0A%0A%20%20%20%20%20%20%20%20def%20iter_radius(self%2C%20epsilon_range)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Generator%20for%20iterating%20through%20values%20for%20the%20WasRadius%0A%20%20%20%20%20%20%20%20%20%20%20%20parameter.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20epsilon%20in%20epsilon_range%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20yield%20self.solve(epsilon)%0A%0A%20%20%20%20%20%20%20%20def%20simulate(self%2C%20data)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Tentative%20goal%20of%20this%20method%20is%20to%20set%20a%20value%20for%20the%0A%20%20%20%20%20%20%20%20%20%20%20%20data%20parameter%2C%20and%20solve%20the%20model%20for%20the%20same.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Define%20in%20child%20classes.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20pass%0A%0A%20%20%20%20%20%20%20%20def%20solve(self%2C%20epsilon)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Tentative%20goal%20of%20this%20method%20is%20to%20set%20a%20value%20for%20the%20%0A%20%20%20%20%20%20%20%20%20%20%20%20radius%20parameter%2C%20and%20solve%20the%20model%20for%20the%20same.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Define%20in%20child%20classes.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20pass%0A%20%20%20%20return%20(DistributionallyRobustPortfolio%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%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%23%23%20Market%20setup%0A%0A%20%20%20%20The%20simulation%20results%20presented%20in%20the%20paper%20are%20based%20on%20a%20market%20with%20%24m%20%3D%2010%24%20assets.%20Each%20asset's%20return%20is%20expressed%20as%20%24%5Cxi_i%20%3D%20%5Cpsi%20%2B%20%5Czeta_i%24%2C%20where%20%24%5Cpsi%20%5Csim%20%5Cmathcal%7BN%7D(0%2C%200.02)%24%20is%20the%20systematic%20risk%20factor%20and%20%24%5Czeta_i%20%5Csim%20%5Cmathcal%7BN%7D(0.03%5Ctimes%20i%2C%200.025%5Ctimes%20i)%24%20is%20the%20idiosyncratic%20risk%20factor.%20By%20construction%2C%20assets%20with%20higher%20indices%20have%20higher%20risk%20as%20well%20as%20higher%20returns.%20The%20uncertainty%20set%20is%20%24%5CXi%20%5Cin%20%5Cmathbb%7BR%7D%5Em%24%2C%20thus%20%3Cb%3E%24C%24%20and%20%24d%24%20are%20set%20to%20zero%3C%2Fb%3E.%20%241%24-norm%20is%20used%20to%20define%20the%20Wasserstein%20ball%2C%20therefore%20the%20dual%20norm%20will%20be%20the%20%24%5Cinfty%24-norm.%20Lastly%2C%20%24%5Calpha%20%3D%2020%5C%25%24%20and%20%24%5Crho%20%3D%2010%24%20are%20used%20within%20the%20loss%20function.%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_(np)%3A%0A%20%20%20%20%23%20Function%20to%20generate%20N%20samples%20of%20the%20m-shaped%20random%20vector%20xi.%0A%20%20%20%20def%20normal_returns(m%2C%20N)%3A%0A%20%20%20%20%20%20%20%20R%20%3D%20np.vstack(%5Bnp.random.normal(%0A%20%20%20%20%20%20%20%20%20%20%20%20i*0.03%2C%20np.sqrt((0.02**2%2B(i*0.025)**2))%2C%20N)%20for%20i%20in%20range(1%2C%20m%2B1)%5D)%0A%20%20%20%20%20%20%20%20return%20(R.transpose())%0A%20%20%20%20return%20(normal_returns%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%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%20Simulations%20and%20results%0A%0A%20%20%20%20The%20concluding%20section%20of%20this%20notebook%20reproduces%20the%20results%20provided%20in%20sections%207.2%20of%20%5BMohajerin%20Esfahani%20and%20Kuhn%5D(https%3A%2F%2Frdcu.be%2FcbBoC).%20We%20do%20not%20pursue%20details%20of%20the%20design%20of%20these%20simulations%2C%20instead%20we%20focus%20primarily%20on%20implementing%20them%20with%20the%20models%20constructed%20above.%20The%20reader%20will%20find%20details%2Fhints%20about%20the%20code%20within%20the%20in-code%20comments.%0A%0A%20%20%20%20%23%23%20Impact%20of%20the%20Wasserstein%20radius%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%20import%20numpy%20as%20np%0A%20%20%20%20from%20mosek.fusion%20import%20Model%2C%20Expr%2C%20Domain%2C%20ObjectiveSense%0A%20%20%20%20import%20mosek.fusion.pythonic%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20from%20scipy.special%20import%20erfinv%0A%20%20%20%20from%20sklearn.model_selection%20import%20train_test_split%0A%20%20%20%20from%20sklearn.utils%20import%20resample%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20Domain%2C%0A%20%20%20%20%20%20%20%20Expr%2C%0A%20%20%20%20%20%20%20%20Model%2C%0A%20%20%20%20%20%20%20%20ObjectiveSense%2C%0A%20%20%20%20%20%20%20%20erfinv%2C%0A%20%20%20%20%20%20%20%20np%2C%0A%20%20%20%20%20%20%20%20plt%2C%0A%20%20%20%20%20%20%20%20resample%2C%0A%20%20%20%20%20%20%20%20train_test_split%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell%0Adef%20_(DistributionallyRobustPortfolio%2C%20erfinv%2C%20np)%3A%0A%20%20%20%20%23%20Inherits%20from%20the%20portfolio%20class%20defined%20above.%0A%20%20%20%20class%20SimSet1(DistributionallyRobustPortfolio)%3A%0A%20%20%20%20%20%20%20%20%23%20Market%20setup%0A%20%20%20%20%20%20%20%20m%20%3D%2010%0A%20%20%20%20%20%20%20%20mu%20%3D%20np.arange(1%2C%2011)*0.03%0A%20%20%20%20%20%20%20%20var%20%3D%200.02%20%2B%20(np.arange(1%2C%2011)*0.025)%0A%0A%20%20%20%20%20%20%20%20%23%20Constants%20for%20CVaR%20calculation.%0A%20%20%20%20%20%20%20%20beta%2C%20rho%20%3D%200.8%2C%2010%0A%20%20%20%20%20%20%20%20c2_beta%20%3D%201%2F(np.sqrt(2*np.pi)*(np.exp(erfinv(2*beta%20-%201))**2)*(1-beta))%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20N%2C%20eps_range)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eps_range%20%3D%20eps_range%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Fusion%20model%20instance%0A%20%20%20%20%20%20%20%20%20%20%20%20super().__init__(SimSet1.m%2C%20N)%0A%0A%20%20%20%20%20%20%20%20def%20simulate(self%2C%20data)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20This%20method%20is%20called%20within%20the%20generator%20method%20called%20iter_data%2C%20which%20%0A%20%20%20%20%20%20%20%20%20%20%20%20was%20defined%20in%20the%20parent%20class.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%0A%20%20%20%20%20%20%20%20%20%20%20%20wts%3A%20optimal%20asset%20weights%20for%20each%20radius%0A%20%20%20%20%20%20%20%20%20%20%20%20perf%3A%20analytic%20out-of-sample%20performance%20for%20each%20radius%0A%20%20%20%20%20%20%20%20%20%20%20%20rel%3A%20reliability%20for%20each%20radius%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20TrainData%20parameter%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dat.setValue(data)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Iterate%20through%20range%20of%20Wasserstein%20radii%20(see%20solve%20method%20below)%0A%20%20%20%20%20%20%20%20%20%20%20%20wts%2C%20perf%2C%20rel%20%3D%20zip(*%5B(_w%2C%20_p%2C%20_r)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20_w%2C%20_p%2C%20_r%20in%20self.iter_radius(self.eps_range)%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20wts%2C%20perf%2C%20rel%0A%0A%20%20%20%20%20%20%20%20def%20solve(self%2C%20epsilon)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20This%20method%20is%20used%20within%20the%20generator%20method%20called%20iter_radius%2C%20which%0A%20%20%20%20%20%20%20%20%20%20%20%20was%20defined%20in%20the%20parent%20class.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20x_sol%3A%20asset%20weights%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%3A%20analytica%20out-of-sample%20performance%0A%20%20%20%20%20%20%20%20%20%20%20%20rel%3A%20reliability%20for%20the%20certificate%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20WasRadius%20parameter%20(TrainData%20is%20already%20set)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eps.setValue(epsilon)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Solve%20the%20Fusion%20model%0A%20%20%20%20%20%20%20%20%20%20%20%20self.M.solve()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.sol_time.append(self.M.getSolverDoubleInfo('optimizerTime'))%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Portfolio%20weights%0A%20%20%20%20%20%20%20%20%20%20%20%20x_sol%20%3D%20self.x.level()%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Analytical%20out-of-sample%20performance%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%20%3D%20self.analytic_out_perf(x_sol)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20x_sol%2C%20out_perf%2C%20(out_perf%20%3C%3D%20self.M.primalObjValue())%0A%0A%20%20%20%20%20%20%20%20def%20analytic_out_perf(self%2C%20x_sol)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20to%20calculate%20the%20analytical%20value%20for%20the%20out-of-sample%20performance.%0A%20%20%20%20%20%20%20%20%20%20%20%20%5Bsee%20Rockafellar%20and%20Uryasev%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20mean_loss%20%3D%20-np.dot(x_sol%2C%20SimSet1.mu)%0A%20%20%20%20%20%20%20%20%20%20%20%20sd_loss%20%3D%20np.sqrt(np.dot(x_sol**2%2C%20SimSet1.var))%0A%20%20%20%20%20%20%20%20%20%20%20%20cVaR%20%3D%20mean_loss%20%2B%20(sd_loss*SimSet1.c2_beta)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20mean_loss%20%2B%20(SimSet1.rho*cVaR)%0A%0A%20%20%20%20%20%20%20%20def%20run_sim(self%2C%20data_sets)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20to%20iterate%20over%20several%20datasets%20and%20record%20the%20results.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20wts%2C%20perf%2C%20rel%20%3D%20zip(*self.iter_data(data_sets))%0A%20%20%20%20%20%20%20%20%20%20%20%20self.weights%20%3D%20np.mean(wts%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.perf_mu%20%3D%20np.mean(perf%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.perf_20%20%3D%20np.quantile(perf%2C%200.2%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.perf_80%20%3D%20np.quantile(perf%2C%200.8%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.reliability%20%3D%20np.mean(rel%2C%20axis%3D0)%0A%20%20%20%20return%20(SimSet1%2C)%0A%0A%0A%40app.cell%0Adef%20_(SimSet1%2C%20normal_returns%2C%20np)%3A%0A%20%20%20%20%23%20Cardinality%0A%20%20%20%20N%20%3D%20300%0A%20%20%20%20%23%20Number%20of%20simulations%0A%20%20%20%20num_sim%20%3D%20200%0A%0A%20%20%20%20%23%20Range%20of%20Wasserstein%20radii%20to%20consider%0A%20%20%20%20epsilon_range%20%3D%20np.append(np.concatenate(%0A%20%20%20%20%20%20%20%20%5Bnp.arange(1%2C%2010)*10.0**(i)%20for%20i%20in%20range(-4%2C%200)%5D)%2C%201.0)%0A%0A%20%20%20%20%23%20Making%20200%20independent%20datasets%0A%20%20%20%20sim_data%20%3D%20%5Bnormal_returns(10%2C%20N)%20for%20i%20in%20range(num_sim)%5D%0A%0A%20%20%20%20%23%20Instantiate%20SimSet1%20class%0A%20%20%20%20sim1%20%3D%20SimSet1(N%2C%20epsilon_range)%0A%0A%20%20%20%20%23%20200%20simulations...%0A%20%20%20%20sim1.run_sim(sim_data)%0A%0A%20%20%20%20print(%22Time%20taken%20in%20initial%20solve%20of%20model%20with%20N%3D%7B0%7D%3A%20%7B1%3A.4f%7D%20s%22.format(%0A%20%20%20%20%20%20%20%20N%2C%20sim1.sol_time%5B0%5D))%0A%20%20%20%20print(%22Mean%20time%20to%20solve%20a%20model%20with%20N%3D%7B0%7D%3A%20%7B1%3A.4f%7D%20s%22.format(%0A%20%20%20%20%20%20%20%20N%2C%20np.mean(sim1.sol_time)))%0A%20%20%20%20print(%22Total%20time%20to%20solve%20200%20models%20with%20N%3D%7B0%7D%3A%20%7B1%3A.4f%7D%20s%22.format(%0A%20%20%20%20%20%20%20%20N%2C%20np.sum(sim1.sol_time)))%0A%20%20%20%20return%20N%2C%20epsilon_range%2C%20sim1%0A%0A%0A%40app.cell%0Adef%20_(N%2C%20epsilon_range%2C%20np%2C%20plt%2C%20sim1)%3A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(ncols%3D2%2C%20figsize%3D(10%2C%204)%2C%20dpi%3D150%2C%20gridspec_kw%3D%7B'wspace'%3A%200.3%7D)%0A%20%20%20%20_fig.suptitle('N%20%3D%20%7B%7D'.format(N))%0A%20%20%20%20for%20i%20in%20range(1%2C%2011)%3A%0A%20%20%20%20%20%20%20%20_ax%5B0%5D.fill_between(epsilon_range%2C%20np.sum(sim1.weights%5B%3A%2C%20%3Ai%20-%201%5D%2C%20axis%3D1)%2C%20np.sum(sim1.weights%5B%3A%2C%20%3Ai%5D%2C%20axis%3D1)%2C%20color%3Dplt.cm.RdYlBu(1%20-%20i%20%2F%2011))%0A%20%20%20%20%20%20%20%20_ax%5B0%5D.plot(epsilon_range%2C%20np.sum(sim1.weights%5B%3A%2C%20%3Ai%5D%2C%20axis%3D1)%2C%20color%3D'black'%2C%20linewidth%3D1.0)%0A%20%20%20%20_ax%5B0%5D.set_xscale('log')%0A%20%20%20%20_ax%5B0%5D.set_xlabel('%24%5C%5Cepsilon%24')%0A%20%20%20%20_ax%5B0%5D.set_xlim(10%20**%20(-3)%2C%201)%0A%20%20%20%20_ax%5B0%5D.set_ylim(0%2C%201)%0A%20%20%20%20_ax%5B0%5D.set_ylabel('Mean%20portfolio%20weights')%0A%20%20%20%20_ax%5B1%5D.plot(epsilon_range%2C%20sim1.perf_mu%2C%20color%3D'blue')%0A%20%20%20%20_ax%5B1%5D.fill_between(epsilon_range%2C%20sim1.perf_20%2C%20sim1.perf_80%2C%20color%3D'blue'%2C%20alpha%3D0.4)%0A%20%20%20%20_ax%5B1%5D.set_xscale('log')%0A%20%20%20%20_ax%5B1%5D.set_xlabel('%24%5C%5Cepsilon%24')%0A%20%20%20%20_ax%5B1%5D.set_xlim(10%20**%20(-4)%2C%201.0)%0A%20%20%20%20_ax%5B1%5D.set_ylabel('Out-of-sample%20performance'%2C%20color%3D'blue')%0A%20%20%20%20_ax%5B1%5D.set_yticks(np.arange(-1.4%2C%20-0.8%2C%200.1))%0A%20%20%20%20_ax%5B1%5D.grid(which%3D'major'%2C%20alpha%3D0.4)%0A%20%20%20%20_ax%5B1%5D.grid(which%3D'minor'%2C%20alpha%3D0.3)%0A%20%20%20%20ax2%20%3D%20_ax%5B1%5D.twinx()%0A%20%20%20%20ax2.set_ylabel('Reliability'%2C%20color%3D'red')%0A%20%20%20%20ax2.plot(epsilon_range%2C%20sim1.reliability%2C%20color%3D'red')%0A%20%20%20%20ax2.set_yticks(np.arange(0%2C%201.2%2C%200.2))%0A%20%20%20%20ax2.set_ylim(0%2C%201)%0A%20%20%20%20plt.savefig('sim1_N%7B%7D.jpg'.format(N)%2C%20dpi%3D150%2C%20bbox_inches%3D'tight')%0A%20%20%20%20plt.show()%0A%20%20%20%20plt.show()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%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%23%20Portfolios%20driven%20by%20out-of-sample%20performance%0A%0A%20%20%20%20%23%23%23%20Holdout%20method%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_(DistributionallyRobustPortfolio%2C%20normal_returns%2C%20np%2C%20train_test_split)%3A%0A%20%20%20%20class%20SimSet2_Holdout(DistributionallyRobustPortfolio)%3A%0A%20%20%20%20%20%20%20%20%23%20Market%20setup%0A%20%20%20%20%20%20%20%20m%20%3D%2010%0A%0A%20%20%20%20%20%20%20%20%23%20Radius%20range%20(see%20page%20156%20in%20Mohajerin%20Esfahani%20and%20Kuhn)%0A%20%20%20%20%20%20%20%20eps_range%20%3D%20np.concatenate(%5Bnp.arange(1%2C%2010)*10.0**(i)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20i%20in%20range(-3%2C%200)%5D)%0A%0A%20%20%20%20%20%20%20%20%23%20Validation%20data%20set%20of%202*10**5%20samples%20(page%20158%20in%20paper)%0A%20%20%20%20%20%20%20%20valids%20%3D%20normal_returns(10%2C%202*10**5)%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20N%2C%20k%3D5)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%201%2Fk%20sized%20split%20for%20the%20test%20data.%0A%20%20%20%20%20%20%20%20%20%20%20%20self.k%20%3D%20k%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Fusion%20model%20for%20(train)%20data%20size%20N*(k-1)%2Fk%20(see%20holdout%20method)%0A%20%20%20%20%20%20%20%20%20%20%20%20super().__init__(SimSet2_Holdout.m%2C%20np.rint(N*(k-1)%2Fk).astype(np.int32))%0A%0A%20%20%20%20%20%20%20%20def%20validate(self%2C%20data_sets)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20to%20iterate%20over%20a%20list%20of%20independent%20datasets%20via%20the%20iter_data%0A%20%20%20%20%20%20%20%20%20%20%20%20generator%20method%20so%20as%20to%20apply%20the%20holdout%20technique%20to%20each%20dataset%20%0A%20%20%20%20%20%20%20%20%20%20%20%20and%20then%20save%20the%20results.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20self.perf%2C%20self.cert%2C%20radii%20%3D%20zip(*self.iter_data(data_sets))%0A%20%20%20%20%20%20%20%20%20%20%20%20self.rel%20%3D%20np.mean(np.array(self.perf)%20%3C%3D%20np.array(self.cert)%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.radius%20%3D%20np.mean(radii%2C%20axis%3D0)%0A%0A%20%20%20%20%20%20%20%20def%20simulate(self%2C%20data)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20called%20within%20the%20iter_data%20generator.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%3A%20out-of-sample%20performance%20calculated%20with%20validation%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20cert%3A%20performance%20certificate%20(optimal%20objective%20for%20M)%0A%20%20%20%20%20%20%20%20%20%20%20%20eps_holdout%3A%20radius%20selected%20from%20holdout%20method%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Split%20data%20into%20test%20and%20train%0A%20%20%20%20%20%20%20%20%20%20%20%20train%2C%20self.test%20%3D%20train_test_split(data%2C%20test_size%3D1%2Fself.k)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20the%20TrainData%20parameter%20to%20train%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dat.setValue(train)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Iterate%20through%20a%20range%20of%20Wasserstein%20radii%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf_test%2C%20x%2C%20t%2C%20J_N%20%3D%20zip(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20*self.iter_radius(SimSet2_Holdout.eps_range))%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Index%20of%20eps_holdout%20in%20the%20eps_range.%0A%20%20%20%20%20%20%20%20%20%20%20%20min_arg%20%3D%20np.argmin(out_perf_test)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Out-of-sample%20performance%20for%20x_N(eps_holdout)%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%20%3D%20self.sample_average(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%5Bmin_arg%5D%2C%20t%5Bmin_arg%5D%2C%20SimSet2_Holdout.valids)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20J_N(eps_holdout)%0A%20%20%20%20%20%20%20%20%20%20%20%20cert%20%3D%20J_N%5Bmin_arg%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20out_perf%2C%20cert%2C%20SimSet2_Holdout.eps_range%5Bmin_arg%5D%0A%0A%20%20%20%20%20%20%20%20def%20solve(self%2C%20epsilon)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20called%20within%20the%20iter_radius%20generator.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%3A%20SA-approx%20of%20out-of-sample%20performance%20using%20test%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3A%20Portfolio%20weights%0A%20%20%20%20%20%20%20%20%20%20%20%20t%3A%20Tau%0A%20%20%20%20%20%20%20%20%20%20%20%20self.M.primalObjValue()%3A%20performance%20certificate%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20the%20WasRadius%20parameter%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eps.setValue(epsilon)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Solve%20the%20Fusion%20model%0A%20%20%20%20%20%20%20%20%20%20%20%20self.M.solve()%0A%20%20%20%20%20%20%20%20%20%20%20%20self.sol_time.append(self.M.getSolverDoubleInfo('optimizerTime'))%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Weights%20and%20Tau%20optimal%20values%0A%20%20%20%20%20%20%20%20%20%20%20%20x%2C%20t%20%3D%20self.x.level()%2C%20self.t.level()%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20SAA%20of%20out-of-sample%20performance%20based%20on%20test%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%20%3D%20self.sample_average(x%2C%20t%2C%20self.test)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20out_perf%2C%20x%2C%20t%2C%20self.M.primalObjValue()%0A%20%20%20%20return%20(SimSet2_Holdout%2C)%0A%0A%0A%40app.cell%0Adef%20_(SimSet2_Holdout%2C%20normal_returns%2C%20np)%3A%0A%20%20%20%20N_range%20%3D%20np.append(np.concatenate(%5Bnp.arange(1%2C%2010)%20*%2010%20**%20i%20for%20i%20in%20range(1%2C%203)%5D)%2C%201000)%0A%20%20%20%20holdout_results%20%3D%20%5B%5D%0A%20%20%20%20for%20N_1%20in%20N_range%3A%0A%20%20%20%20%20%20%20%20_n_data%20%3D%20%5Bnormal_returns(10%2C%20N_1)%20for%20i%20in%20range(200)%5D%0A%20%20%20%20%20%20%20%20hld%20%3D%20SimSet2_Holdout(N_1)%0A%20%20%20%20%20%20%20%20hld.validate(_n_data)%0A%20%20%20%20%20%20%20%20holdout_results.append(hld)%0A%20%20%20%20return%20(holdout_results%2C)%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt)%3A%0A%20%20%20%20def%20N_plot(results%2C%20title%2C%20save_name%2C%20y_l%3D%5B%5B-1.5%2C%200.5%5D%2C%20%5B-2.5%2C%2010%5D%2C%20%5B0%2C%201%5D%5D)%3A%0A%20%20%20%20%20%20%20%20N_range%20%3D%20np.append(np.concatenate(%5Bnp.arange(1%2C%2010)%20*%2010%20**%20i%20for%20i%20in%20range(1%2C%203)%5D)%2C%201000)%0A%20%20%20%20%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(nrows%3D1%2C%20ncols%3D3%2C%20figsize%3D(13%2C%203)%2C%20dpi%3D150)%0A%20%20%20%20%20%20%20%20_fig.suptitle(title)%0A%20%20%20%20%20%20%20%20_ax%5B0%5D.fill_between(N_range%2C%20%5Bnp.quantile(r.perf%2C%200.2%2C%20axis%3D0)%20for%20r%20in%20results%5D%2C%20%5Bnp.quantile(r.perf%2C%200.8%2C%20axis%3D0)%20for%20r%20in%20results%5D%2C%20alpha%3D0.4)%0A%20%20%20%20%20%20%20%20_ax%5B0%5D.plot(N_range%2C%20%5Bnp.mean(r.perf%2C%20axis%3D0)%20for%20r%20in%20results%5D%2C%20marker%3D'%3E')%0A%20%20%20%20%20%20%20%20_ax%5B1%5D.fill_between(N_range%2C%20%5Bnp.quantile(r.cert%2C%200.2%2C%20axis%3D0)%20for%20r%20in%20results%5D%2C%20%5Bnp.quantile(r.cert%2C%200.8%2C%20axis%3D0)%20for%20r%20in%20results%5D%2C%20alpha%3D0.4)%0A%20%20%20%20%20%20%20%20_ax%5B1%5D.plot(N_range%2C%20%5Bnp.mean(r.cert%2C%20axis%3D0)%20for%20r%20in%20results%5D%2C%20marker%3D'%3E')%0A%20%20%20%20%20%20%20%20_ax%5B2%5D.plot(N_range%2C%20%5Br.rel%20for%20r%20in%20results%5D%2C%20marker%3D'%3E')%0A%20%20%20%20%20%20%20%20y_n%20%3D%20%5B'Out-of-sample%20performance'%2C%20'Certificate'%2C%20'Reliability'%5D%0A%20%20%20%20%20%20%20%20for%20i%20in%20range(3)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax%5Bi%5D.set_ylabel(y_n%5Bi%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax%5Bi%5D.set_ylim(y_l%5Bi%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax%5Bi%5D.grid(which%3D'major'%2C%20alpha%3D0.4)%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax%5Bi%5D.grid(which%3D'minor'%2C%20alpha%3D0.3)%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax%5Bi%5D.set_xscale('log')%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax%5Bi%5D.set_xlabel('N')%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax%5Bi%5D.set_xlim(%5B10%2C%201000%5D)%0A%20%20%20%20%20%20%20%20_ax%5B0%5D.set_yticks(%5B-1.5%2C%20-1%2C%20-0.5%2C%200%2C%200.5%5D)%0A%20%20%20%20%20%20%20%20plt.savefig(save_name%2C%20dpi%3D150%2C%20bbox_inches%3D'tight')%0A%20%20%20%20%20%20%20%20plt.show()%0A%20%20%20%20return%20(N_plot%2C)%0A%0A%0A%40app.cell%0Adef%20_(N_plot%2C%20holdout_results)%3A%0A%20%20%20%20N_plot(holdout_results%2C%20'Holdout%20Method'%2C%20'sim2_holdout.jpg')%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%23%23%20k-fold%20cross%20validation%20method%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(SimSet2_Holdout%2C%20np%2C%20train_test_split)%3A%0A%20%20%20%20%23%20IMPORTANT%3A%20sub-class%20of%20the%20SimSet2_Holdout%20class!%0A%20%20%20%20class%20SimSet2_kFold(SimSet2_Holdout)%3A%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20N%2C%20k%3D5)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.k%20%3D%20k%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Object%20for%20holdout%20method%20(k-holdouts)%0A%20%20%20%20%20%20%20%20%20%20%20%20super().__init__(N%2C%20k%3Dk)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Fusion%20model%20for%20N-size%20dataset%20(results)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.M_N%20%3D%20self.portfolio_model(SimSet2_Holdout.m%2C%20N)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dat_N%20%3D%20self.M_N.getParameter('TrainData')%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eps_N%20%3D%20self.M_N.getParameter('WasRadius')%0A%20%20%20%20%20%20%20%20%20%20%20%20self.x_N%20%3D%20self.M_N.getVariable('Weights')%0A%20%20%20%20%20%20%20%20%20%20%20%20self.t_N%20%3D%20self.M_N.getVariable('Tau')%0A%0A%20%20%20%20%20%20%20%20def%20simulate(self%2C%20data)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20called%20within%20the%20iter_data%20generator.%20This%20method%20overwrites%0A%20%20%20%20%20%20%20%20%20%20%20%20the%20one%20defined%20in%20the%20SimSet2_Holdout%20class.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%3A%20out-of-sample%20performance%20calculated%20with%20validation%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20cert%3A%20performance%20certificate%20(optimal%20objective%20for%20M_N)%0A%20%20%20%20%20%20%20%20%20%20%20%20eps_kFold%3A%20radius%20selected%20from%20k-Fold%20method%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20TrainData%20paremeter%20for%20M_N%20to%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dat_N.setValue(data)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Perform%20the%20holdout%20method%20k%20times%20and%20calculate%20eps_kFold%0A%20%20%20%20%20%20%20%20%20%20%20%20eps_kFold%20%3D%20np.mean(%5Bself._simulate(data)%20for%20i%20in%20range(self.k)%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20WasRadius%20to%20mean%20from%20k%20holdout%20runs%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eps_N.setValue(eps_kFold)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Solve%20the%20M_N%20model.%0A%20%20%20%20%20%20%20%20%20%20%20%20self.M_N.solve()%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Out-of-sample%20performance%20for%20x_N(eps_kFold)%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%20%3D%20self.sample_average(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.x_N.level()%2C%20self.t_N.level()%2C%20SimSet2_Holdout.valids)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20J_N(eps_kFold)%0A%20%20%20%20%20%20%20%20%20%20%20%20cert%20%3D%20self.M_N.primalObjValue()%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20out_perf%2C%20cert%2C%20eps_kFold%0A%0A%20%20%20%20%20%20%20%20def%20_simulate(self%2C%20data)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20to%20perform%20the%20holdout%20technique%20for%20a%20given%20dataset.%20This%20%0A%20%20%20%20%20%20%20%20%20%20%20%20is%20called%20k%20times%20within%20each%20call%20to%20the%20simulate%20method.%20Works%0A%20%20%20%20%20%20%20%20%20%20%20%20analogously%20to%20the%20simulate%20method%20of%20SimSet2_Holdout%20class.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20eps_holdout%3A%20WasRadius%20selected%20in%20one%20holdout%20run%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Split%20data%20into%20test%20and%20train%0A%20%20%20%20%20%20%20%20%20%20%20%20train%2C%20self.test%20%3D%20train_test_split(data%2C%20test_size%3D1%2Fself.k)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20TrainData%20parameter%20for%20the%20N*(k-1)%2Fk%20model%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dat.setValue(train)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Solve%20N*(k-1)%2Fk%20model%20iteratively%20for%20a%20range%20of%20radii%0A%20%20%20%20%20%20%20%20%20%20%20%20saa%2C%20x%2C%20t%2C%20J_N%20%3D%20zip(*self.iter_radius(SimSet2_Holdout.eps_range))%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Select%20Wasserstein%20radius%20that%20minimizes%20out-of-sample%20perf%0A%20%20%20%20%20%20%20%20%20%20%20%20min_arg%20%3D%20np.argmin(saa)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20SimSet2_Holdout.eps_range%5Bmin_arg%5D%0A%20%20%20%20return%20(SimSet2_kFold%2C)%0A%0A%0A%40app.cell%0Adef%20_(SimSet2_kFold%2C%20normal_returns%2C%20np)%3A%0A%20%20%20%20N_range_1%20%3D%20np.append(np.concatenate(%5Bnp.arange(1%2C%2010)%20*%2010%20**%20i%20for%20i%20in%20range(1%2C%203)%5D)%2C%201000)%0A%20%20%20%20kFold_results%20%3D%20%5B%5D%0A%20%20%20%20for%20N_2%20in%20N_range_1%3A%0A%20%20%20%20%20%20%20%20_n_data%20%3D%20%5Bnormal_returns(10%2C%20N_2)%20for%20i%20in%20range(200)%5D%0A%20%20%20%20%20%20%20%20kFld%20%3D%20SimSet2_kFold(N_2)%0A%20%20%20%20%20%20%20%20kFld.validate(_n_data)%0A%20%20%20%20%20%20%20%20kFold_results.append(kFld)%0A%20%20%20%20return%20(kFold_results%2C)%0A%0A%0A%40app.cell%0Adef%20_(N_plot%2C%20kFold_results)%3A%0A%20%20%20%20N_plot(kFold_results%2C%20'k-fold%20cross%20validation%20method'%2C%20'sim2_kcross.jpg')%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%23%20Portfolios%20driven%20by%20reliability%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20DistributionallyRobustPortfolio%2C%0A%20%20%20%20normal_returns%2C%0A%20%20%20%20np%2C%0A%20%20%20%20resample%2C%0A%20%20%20%20train_test_split%2C%0A)%3A%0A%20%20%20%20class%20SimSet3(DistributionallyRobustPortfolio)%3A%0A%20%20%20%20%20%20%20%20m%20%3D%2010%0A%20%20%20%20%20%20%20%20eps_range%20%3D%20np.concatenate(%5Bnp.arange(1%2C%2010)*10.0**(i)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20i%20in%20range(-3%2C%200)%5D)%0A%20%20%20%20%20%20%20%20valids%20%3D%20normal_returns(10%2C%202*10**5)%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20beta%2C%20N%2C%20k%3D50)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Number%20of%20resamples%0A%20%20%20%20%20%20%20%20%20%20%20%20self.k%20%3D%20k%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Reliability%20threshold%0A%20%20%20%20%20%20%20%20%20%20%20%20self.beta%20%3D%20beta%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Instantiate%20Fusion%20model%0A%20%20%20%20%20%20%20%20%20%20%20%20super().__init__(SimSet3.m%2C%20N)%0A%0A%20%20%20%20%20%20%20%20def%20bootstrap(self%2C%20data_sets)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20to%20iterate%20over%20a%20list%20of%20independent%20datasets%20via%20the%20iter_data%0A%20%20%20%20%20%20%20%20%20%20%20%20generator%20method%20so%20as%20to%20apply%20the%20bootstrap%20technique%20to%20each%20dataset%0A%20%20%20%20%20%20%20%20%20%20%20%20and%20then%20save%20the%20results.%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20self.perf%2C%20self.cert%2C%20radii%20%3D%20zip(*self.iter_data(data_sets))%0A%20%20%20%20%20%20%20%20%20%20%20%20self.rel%20%3D%20np.mean(np.array(self.perf)%20%3C%3D%20np.array(self.cert)%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.radii%20%3D%20np.mean(radii%2C%20axis%3D0)%0A%0A%20%20%20%20%20%20%20%20def%20simulate(self%2C%20data)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20called%20within%20the%20iter_data%20generator.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%3A%20out-of-sample%20performance%20calculated%20with%20validation%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20cert%3A%20performance%20certificate%20(optimal%20objective%20for%20M)%0A%20%20%20%20%20%20%20%20%20%20%20%20eps_btstrp%3A%20radius%20selected%20from%20holdout%20method%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20List%20to%20store%20reliability%0A%20%20%20%20%20%20%20%20%20%20%20%20rel%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Perform%20k%20resamples%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20i%20in%20range(self.k)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Split%20data%20into%20test%20and%20train%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20train%2C%20self.test%20%3D%20train_test_split(data%2C%20test_size%3D1%2F3)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Resample%20train%20data%20up-to%20size%20N%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20train%20%3D%20resample(train%2C%20n_samples%3Dself.N)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20TrainData%20parameter%20to%20train%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.dat.setValue(train)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Iterate%20through%20a%20range%20of%20Wasserstein%20radii%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rel.append(list(self.iter_radius(SimSet3.eps_range)))%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Sum%20reliability%20over%20all%20resamples%20(for%20each%20epsilon)%0A%20%20%20%20%20%20%20%20%20%20%20%20rel%20%3D%20np.sum(rel%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Smallest%20radius%20that%20has%20reliability%20over%201-beta%0A%20%20%20%20%20%20%20%20%20%20%20%20_id%20%3D%20next(i%20for%20i%2C%20r%20in%20enumerate(rel)%20if%20r%20%3E%3D%20self.k*(1-self.beta))%0A%20%20%20%20%20%20%20%20%20%20%20%20eps_btstrp%20%3D%20SimSet3.eps_range%5B_id%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20TrainData%20parameter%20to%20data%0A%20%20%20%20%20%20%20%20%20%20%20%20self.dat.setValue(data)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20WasRadius%20parameter%20to%20eps_btstrp%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eps.setValue(eps_btstrp)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.M.solve()%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Out-of-sample%20performance%20for%20x_N(eps_btstrp)%0A%20%20%20%20%20%20%20%20%20%20%20%20out_perf%20%3D%20self.sample_average(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.x.level()%2C%20self.t.level()%2C%20SimSet3.valids)%0A%20%20%20%20%20%20%20%20%20%20%20%20cert%20%3D%20self.M.primalObjValue()%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20out_perf%2C%20cert%2C%20eps_btstrp%0A%0A%20%20%20%20%20%20%20%20def%20solve(self%2C%20epsilon)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20called%20within%20the%20iter_radius%20generator.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%0A%20%20%20%20%20%20%20%20%20%20%20%20reliability%3A%20SAA%20of%20out-of-sample%20performance%20%3C%3D%20certificate(epsilon)%0A%20%20%20%20%20%20%20%20%20%20%20%20'''%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Set%20WasRadius%20parameter%20to%20epsilon%20and%20solve%0A%20%20%20%20%20%20%20%20%20%20%20%20self.eps.setValue(epsilon)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.M.solve()%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Calculate%20out-of-sample%20performance%20SAA%20estimator%20using%20test%0A%20%20%20%20%20%20%20%20%20%20%20%20saa%20%3D%20self.sample_average(self.x.level()%2C%20self.t.level()%2C%20self.test)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Boolean%20to%20state%20if%20the%20certificate%20is%20greater%20than%20SAA%20estimate%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20saa%20%3C%3D%20self.M.primalObjValue()%0A%20%20%20%20return%20(SimSet3%2C)%0A%0A%0A%40app.cell%0Adef%20_(SimSet3%2C%20normal_returns%2C%20np)%3A%0A%20%20%20%20N_range_2%20%3D%20np.append(np.concatenate(%5Bnp.arange(1%2C%2010)%20*%2010%20**%20i%20for%20i%20in%20range(1%2C%203)%5D)%2C%201000)%0A%20%20%20%20beta%20%3D%200.1%0A%20%20%20%20bootstrap_results%20%3D%20%5B%5D%0A%20%20%20%20for%20N_3%20in%20N_range_2%3A%0A%20%20%20%20%20%20%20%20_n_data%20%3D%20%5Bnormal_returns(10%2C%20N_3)%20for%20i%20in%20range(200)%5D%0A%20%20%20%20%20%20%20%20btstrp%20%3D%20SimSet3(beta%2C%20N_3)%0A%20%20%20%20%20%20%20%20btstrp.bootstrap(_n_data)%0A%20%20%20%20%20%20%20%20bootstrap_results.append(btstrp)%0A%20%20%20%20return%20N_range_2%2C%20beta%2C%20bootstrap_results%0A%0A%0A%40app.cell%0Adef%20_(N_plot%2C%20beta%2C%20bootstrap_results)%3A%0A%20%20%20%20N_plot(bootstrap_results%2C%20%221%20-%20%24%5C%5Cbeta%24%20%3D%20%7B%7D%22.format(1-beta)%2C%20'sim3_90.jpg'%2C%0A%20%20%20%20%20%20%20%20%20%20%20y_l%20%3D%20%5B%5B-1.5%2C%201.5%5D%2C%20%5B-2.5%2C%2010%5D%2C%20%5B0%2C%201%5D%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%23%20Impact%20of%20sample%20size%20on%20Wasserstein%20radius%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(N_range_2%2C%20bootstrap_results%2C%20holdout_results%2C%20kFold_results%2C%20plt)%3A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(5%2C%204)%2C%20dpi%3D150)%0A%20%20%20%20_fig.suptitle('Impact%20of%20sample%20size%20on%20Wasserstein%20radius')%0A%20%20%20%20_ax.plot(N_range_2%2C%20%5Bh.radius%20for%20h%20in%20holdout_results%5D%2C%20color%3D'blue'%2C%20linestyle%3D'--'%2C%20label%3D'%24%5C%5Cwidehat%7B%5C%5Cepsilon%7D%5E%7Bhm%7D_N%24%20Holdout')%0A%20%20%20%20_ax.plot(N_range_2%2C%20%5Bk.radius%20for%20k%20in%20kFold_results%5D%2C%20color%3D'green'%2C%20marker%3D'%3E'%2C%20label%3D'%24%5C%5Cwidehat%7B%5C%5Cepsilon%7D%5E%7Bcv%7D_N%24%20k-fold')%0A%20%20%20%20_ax.plot(N_range_2%2C%20%5Bb.radii%20for%20b%20in%20bootstrap_results%5D%2C%20color%3D'tomato'%2C%20marker%3D'%3C'%2C%20label%3D'%24%5C%5Cwidehat%7B%5C%5Cepsilon%7D%5E%7B%5C%5Cbeta%7D_N%24%20%241%20-%20%5C%5Cbeta%20%3D%200.9%24')%0A%20%20%20%20_ax.set_xscale('log')%0A%20%20%20%20_ax.set_yscale('log')%0A%20%20%20%20_ax.set_xlabel('N')%0A%20%20%20%20_ax.set_xlim(10%2C%201000)%0A%20%20%20%20_ax.set_ylim(0.005%2C%200.5)%0A%20%20%20%20_ax.set_ylabel('Average%20Wasserstein%20radii')%0A%20%20%20%20_ax.grid(which%3D'major'%2C%20alpha%3D0.4)%0A%20%20%20%20_ax.grid(which%3D'minor'%2C%20alpha%3D0.3)%0A%20%20%20%20_ax.legend()%0A%20%20%20%20plt.savefig('radius_v_samplesize.jpg'%2C%20dpi%3D150%2C%20bbox_inches%3D'tight')%0A%20%20%20%20plt.show()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22The%20results%20provided%20in%20this%20notebook%20were%20computed%20on%20a%20laptop%20with%20Intel%C2%AE%20Core%E2%84%A2%20i7-10875H%20processor%20and%2032%20GB%20RAM.%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%3Ca%20rel%3D%22license%22%20href%3D%22http%3A%2F%2Fcreativecommons.org%2Flicenses%2Fby%2F4.0%2F%22%3E%3Cimg%20alt%3D%22Creative%20Commons%20License%22%20style%3D%22border-width%3A0%22%20src%3D%22https%3A%2F%2Fi.creativecommons.org%2Fl%2Fby%2F4.0%2F80x15.png%22%20%2F%3E%3C%2Fa%3E%3Cbr%20%2F%3EThis%20work%20is%20licensed%20under%20a%20%3Ca%20rel%3D%22license%22%20href%3D%22http%3A%2F%2Fcreativecommons.org%2Flicenses%2Fby%2F4.0%2F%22%3ECreative%20Commons%20Attribution%204.0%20International%20License%3C%2Fa%3E.%20The%20**MOSEK**%20logo%20and%20name%20are%20trademarks%20of%20%3Ca%20href%3D%22http%3A%2F%2Fmosek.com%22%3EMosek%20ApS%3C%2Fa%3E.%20The%20code%20is%20provided%20as-is.%20Compatibility%20with%20future%20release%20of%20**MOSEK**%20or%20the%20%60Fusion%20API%60%20are%20not%20guaranteed.%20For%20more%20information%20contact%20our%20%5Bsupport%5D(mailto%3Asupport%40mosek.com).%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20return%20(mo%2C)%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
9b23ab8e5d9ffc250505b420e9da25fc80d8a938142cf28bdfbcf3d822ce70ff