def main(): fcns = { 'preprocess': example_preprocess, 'run': example_run, 'postprocess': example_postprocess } ndraws = 1024 seed = 123456 # Recommended for repeatability # Initialize the simulation sim = mc.Sim(name='Dice Roll', singlethreaded=True, savecasedata=False, ndraws=ndraws, fcns=fcns, seed=seed) # Generate the input variables sim.addInVar(name='die1', dist=randint, distkwargs={ 'low': 1, 'high': 6 + 1 }) sim.addInVar(name='die2', dist=randint, distkwargs={ 'low': 1, 'high': 12 + 1 }) # Run the Simulation sim.runSim() # Calculate the mean and 5-95th percentile statistics for the dice sum sim.outvars['Sum'].addVarStat('mean') sim.outvars['Sum'].addVarStat('percentile', {'p': [0.95, 0.05]}) # Plots a histogram of the dice sum fig, axs = plt.subplots(3, 1) mc.plot(sim.outvars['Sum'], plotkwargs={'bins': 16}, ax=axs[0]) # Creates a scatter plot of the dum vs the roll number, showing randomness mc.plot(sim.outvars['Sum'], sim.outvars['Roll Number'], ax=axs[1]) axs[1].get_shared_x_axes().join(axs[0], axs[1]) # Calculate the sensitivity of the dice sum to each of the input variables sim.calcSensitivities('Sum') sim.outvars['Sum'].plotSensitivities(ax=axs[2]) plt.show(block=True)
def pandemic_example_monte_carlo_sim(): sim = mc.Sim(name='pandemic', ndraws=ndraws, fcns=fcns, firstcaseismedian=True, seed=seed, singlethreaded=False, verbose=True, debug=False) sim.addInVar(name='Probability of Infection', dist=uniform, distkwargs={ 'loc': 0.28, 'scale': 0.04 }) sim.runSim() sim.outvars['Proportion Infected'].addVarStat(stat='orderstatTI', statkwargs={ 'p': p, 'c': c, 'bound': bound }) sim.outvars['Superspreader Degree'].addVarStat(stat='orderstatTI', statkwargs={ 'p': 0.5, 'c': 0.5, 'bound': 'all' }) mc.plot(sim.outvars['Timestep'], sim.outvars['Superspreader Degree']) mc.plot(sim.outvars['Max Superspreader Degree'], highlight_cases=0) mc.plot(sim.outvars['Herd Immunity Threshold'], highlight_cases=0) ''' import matplotlib.pyplot as plt fig, ax = mc.plot(sim.outvars['Timestep'], sim.outvars['Proportion Infected'], highlight_cases=0) fig.set_size_inches(8.8, 6.0) plt.savefig('cum_infections_vs_time.png', dpi=100) fig, axs = mc.multi_plot([sim.invars['Probability of Infection'], sim.outvars['Herd Immunity Threshold']], cov_plot=False, highlight_cases=0) fig.set_size_inches(8.8, 6.0) plt.savefig('p_infection_vs_herd_immunity.png', dpi=100) #''' return sim
def test_calc_sensitivities(): fcns = { 'preprocess': vars_preprocess, 'run': vars_run, 'postprocess': vars_postprocess } ndraws = 128 sim = mc.Sim(name='dvars', ndraws=ndraws, fcns=fcns, firstcaseismedian=False, seed=3462356, singlethreaded=True, daskkwargs=dict(), samplemethod='random', savecasedata=False, savesimdata=False, verbose=False, debug=True) varnames = ['x1', 'x2', 'x3', 'x4', 'x5', 'x6'] for varname in varnames: sim.addInVar(name=varname, dist=uniform, distkwargs={ 'loc': 0, 'scale': 1 }) sim.runSim() sim.calcSensitivities('f') # sim.outvars['f'].plotSensitivities() calculated_ratios = list(sim.outvars['f'].sensitivity_ratios.values()) expected_ratios = [ 0.471030, 0.361213, 0.062541, 0.074203, 0.030412, 0.000598 ] assert np.allclose(calculated_ratios, expected_ratios, atol=1e-6)
def election_example_monte_carlo_sim(): sim = mc.Sim(name='election', ndraws=ndraws, fcns=fcns, firstcaseismedian=False, seed=seed, singlethreaded=True, samplemethod='random', savecasedata=False, verbose=True, debug=False) rootdir = pathlib.Path(__file__).parent.absolute() df = pd.read_csv(rootdir / 'state_presidential_odds.csv') states = df['State'].tolist() df['Dem_Sig'] = df['Dem_80_tol'] / mc.pct2sig(0.8, bound='2-sided') df['Rep_Sig'] = df['Rep_80_tol'] / mc.pct2sig(0.8, bound='2-sided') df['Other_Sig'] = df['Other_80_tol'] / mc.pct2sig(0.8, bound='2-sided') sim.addInVar(name='National Dem Swing', dist=uniform, distkwargs={ 'loc': -0.03, 'scale': 0.06 }) for state in states: i = df.loc[df['State'] == state].index[0] sim.addInVar(name=f'{state} Dem Unscaled Pct', dist=norm, distkwargs={ 'loc': df['Dem_Mean'][i], 'scale': df['Dem_Sig'][i] }) sim.addInVar(name=f'{state} Rep Unscaled Pct', dist=norm, distkwargs={ 'loc': df['Rep_Mean'][i], 'scale': df['Rep_Sig'][i] }) sim.addInVar(name=f'{state} Other Unscaled Pct', dist=norm, distkwargs={ 'loc': df['Other_Mean'][i], 'scale': df['Other_Sig'][i] }) sim.addConstVal(name='states', val=states) sim.addConstVal(name='df', val=df) sim.runSim() sim.outvars['Dem EVs'].addVarStat(stat='orderstatP', statkwargs={ 'p': 0.5, 'bound': 'nearest' }) sim.outvars['Dem EVs'].addVarStat(stat='orderstatTI', statkwargs={ 'p': 0.75, 'c': 0.90, 'bound': '2-sided' }) fig, ax = mc.plot(sim.outvars['Dem EVs'], plotkwargs={'bins': 50}) ax.set_autoscale_on(False) ax.plot([270, 270], [0, 1], '--k') fig.set_size_inches(8.0, 4.5) plt.savefig('ev_histogram.png', dpi=100) pct_dem_win = sum(x == 'Dem' for x in sim.outvars['Winner'].vals) / sim.ncases pct_rep_win = sum(x == 'Rep' for x in sim.outvars['Winner'].vals) / sim.ncases pct_contested = sum(x == 'Contested' for x in sim.outvars['Winner'].vals) / sim.ncases print(f'Win probabilities: {100*pct_dem_win:0.1f}% Dem, ' + f'{100*pct_rep_win:0.1f}% Rep, ' + f'{100*pct_contested:0.1f}% Contested') mc.plot(sim.outvars['Winner']) pct_recount = sum(x != 0 for x in sim.outvars['Num Recounts'].vals) / sim.ncases print( f'In {100*pct_recount:0.1f}% of runs there was a state close enough ' + 'to trigger a recount (<0.5%)') dem_win_state_pct = dict() for state in states: dem_win_state_pct[state] \ = sum(x == 'Dem' for x in sim.outvars[f'{state} Winner'].vals)/sim.ncases # Only generate state map if plotly installed. Want to avoid this as a dependency gen_map = False import importlib if importlib.util.find_spec('plotly') and gen_map: import plotly.graph_objects as go from plotly.offline import plot plt.figure() fig = go.Figure(data=go.Choropleth( locations=df['State_Code'], # Spatial coordinates z=np.fromiter(dem_win_state_pct.values(), dtype=float) * 100, locationmode='USA-states', colorscale='RdBu', colorbar_title="Dem % Win")) fig.update_layout(geo_scope='usa') plot(fig) return sim
def template_monte_carlo_sim(): # We first initialize the sim with a name of our choosing sim = mc.Sim(name='Coin Flip', ndraws=ndraws, fcns=fcns, firstcaseismedian=firstcaseismedian, seed=seed, singlethreaded=singlethreaded, savecasedata=savecasedata, savesimdata=savesimdata, verbose=True, debug=False) # We now add input variables, with their associated distributions # Out first variable will be the person flipping a coin - Sam and Alex will # do so with even odds. # For even odds between 0 and 1 we want to call scipy.stats.randint(0,2) # The dist argument is therefor randint, and we look up its arguments in the # documentation: # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.randint.html # The kwargs are {'low':0, 'high':2}, which we package in a keyword dictionary. # Since our inputs here are strings rather than numbers, we need to map the # numbers from our random draws to those imputs with a nummap dictionary nummap = {0: 'Sam', 1: 'Alex'} sim.addInVar(name='flipper', dist=randint, distkwargs={ 'low': 0, 'high': 2 }, nummap=nummap) # If we want to generate custom odds, we can create our own distribution, see: # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.rv_discrete.html # Let's assume that we have a weighted coin where heads comes up 70% of the time. # Our 'template_run' run function reads 0 as heads and 1 as tails. flip_dist = rv_discrete(name='flip_dist', values=([0, 1], [0.7, 0.3])) # If the distribution is custom then it doesn't take arguments, so pass in # an empty dictionary sim.addInVar(name='flip', dist=flip_dist, distkwargs=dict()) # Once all input variables are initialized, we run the sim. # For each case, the preprocessing function will pull in the random variables # and any other data the run fuction needs, the run function executes, and # its output is passed to the postprocessing function for extracting the # desired output values from each case. # The cases are collected, and the individual output values are collected into # an output variable stored by the sim object. sim.runSim() # Once the sim is run, we have access to its member variables. print(f'{sim.name} Runtime: {sim.runtime}') # From here we can perform further postprocessing on our results. The outvar # names were assigned in our postprocessing function. We expect the heads # bias to be near the 70% we assigned up in flip_dist. bias = sim.outvars['Flip Result'].vals.count('heads') / sim.ncases * 100 print(f'Average heads bias: {bias}%') # We can also quickly make some plots of our invars and outvars. The mc.plot # function will automatically try to figure out which type of plot is most # appropriate based on the number and dimension of the variables. # This will make a histogram of the results: mc.plot(sim.outvars['Flip Result']) # And this scatter plot will show that the flips were random over time: mc.plot(sim.outvars['Flip Number'], sim.outvars['Flip Result']) # We can also look at the correlation between all scalar input and output # vars to see which are most affecting the others. This shows that the input # and output flip information is identical, and that the flipper and flip # number had no effect on the coin landing heads or tails. mc.plot_cov_corr(*sim.corr()) # Alternatively, you can return the sim object and work with it elsewhere. return sim
def integration_example_monte_carlo_sim(): sim = mc.Sim(name='integration', ndraws=ndraws, fcns=fcns, firstcaseismedian=firstcaseismedian, samplemethod=samplemethod, seed=seed, singlethreaded=True, savecasedata=savecasedata, savesimdata=False, verbose=True, debug=True) sim.addInVar(name='x', dist=uniform, distkwargs={ 'loc': xrange[0], 'scale': (xrange[1] - xrange[0]) }) # -1 <= x <= 1 sim.addInVar(name='y', dist=uniform, distkwargs={ 'loc': yrange[0], 'scale': (yrange[1] - yrange[0]) }) # -1 <= y <= 1 sim.runSim() # Note that (True,False) vals are automatically valmapped to the nums (1,0) underCurvePct = sum(sim.outvars['pi_est'].nums) / ndraws err = mc.integration_error(sim.outvars['pi_est'].nums, dimension=dimension, volume=totalArea, conf=conf, samplemethod=samplemethod, runningerror=False) stdev = np.std(sim.outvars['pi_est'].nums, ddof=1) resultsstr = f'π ≈ {underCurvePct*totalArea:0.5f}, n = {ndraws}, ' + \ f'{round(conf*100, 2)}% error = ±{err:0.5f}, stdev={stdev:0.3f}' print(resultsstr) ''' import matplotlib.pyplot as plt indices_under_curve = [i for i, x in enumerate(sim.outvars['pi_est'].vals) if x] fig, ax = mc.plot(sim.invars['x'], sim.invars['y'], highlight_cases=indices_under_curve) ax.axis('equal') plt.title(resultsstr) fig.set_size_inches(8.8, 6.0) plt.savefig('circle_integration.png', dpi=100) fig, ax = mc.plot_integration_convergence(sim.outvars['pi_est'], dimension=dimension, volume=totalArea, refval=np.pi, conf=0.95, title='Approx. value of π', samplemethod=samplemethod) ax.set_ylim((3.10, 3.18)) fig.set_size_inches(8.8, 6.0) plt.savefig('pi_convergence.png', dpi=100) fig, ax = mc.plot_integration_error(sim.outvars['pi_est'], dimension=dimension, volume=totalArea, refval=np.pi, conf=0.95, title='Approx. error of π', samplemethod=samplemethod) fig.set_size_inches(8.8, 6.0) plt.savefig('pi_error.png', dpi=100) plt.show() #''' return sim
def baseball_example_monte_carlo_sim(): ## Define sim sim = mc.Sim(name='baseball', ndraws=ndraws, fcns=fcns, firstcaseismedian=True, seed=seed, singlethreaded=True, verbose=True, debug=True, savecasedata=False, savesimdata=False) ## Define input variables sim.addInVar(name='Y Init [m]', dist=uniform, distkwargs={ 'loc': -19.94 * in2m / 2, 'scale': 19.94 * in2m }) sim.addInVar(name='Z Init [m]', dist=uniform, distkwargs={ 'loc': 18.29 * in2m, 'scale': 25.79 * in2m }) sim.addInVar(name='Speed Init [m/s]', dist=norm, distkwargs={ 'loc': 90 * mph2mps, 'scale': 5 * mph2mps }) sim.addInVar(name='Launch Angle [deg]', dist=norm, distkwargs={ 'loc': 10, 'scale': 20 }) sim.addInVar(name='Side Angle [deg]', dist=norm, distkwargs={ 'loc': 0, 'scale': 30 }) sim.addInVar(name='Topspin [rpm]', dist=norm, distkwargs={ 'loc': 80, 'scale': 500 }) sim.addInVar(name='Mass [kg]', dist=uniform, distkwargs={ 'loc': 0.142, 'scale': 0.007 }) sim.addInVar(name='Diameter [m]', dist=uniform, distkwargs={ 'loc': 0.073, 'scale': 0.003 }) sim.addInVar(name='Wind Speed [m/s]', dist=uniform, distkwargs={ 'loc': 0, 'scale': 10 }) sim.addInVar(name='Wind Azi [deg]', dist=uniform, distkwargs={ 'loc': 0, 'scale': 360 }) sim.addInVar(name='CD', dist=norm, distkwargs={ 'loc': 0.300, 'scale': 0.015 }) ## Run sim sim.runSim() ## Generate stats and plots homerun_indices = np.where(sim.outvars['Home Run'].vals)[0] # foul_indices = np.where(sim.outvars['Foul Ball'].vals)[0] # sim.outvars['Landing Dist [m]'].addVarStat(stat='gaussianP', # statkwargs={'p': 0.90, 'c': 0.50}) # sim.outvars['Landing Dist [m]'].addVarStat(stat='gaussianP', # statkwargs={'p': 0.10, 'c': 0.50}) # print(sim.outvars['Landing Dist [m]'].stats()) # mc.plot(sim.outvars['Time [s]'], sim.outvars['Distance [m]'], highlight_cases=homerun_indices) # mc.plot(sim.outvars['Time [s]'], sim.outvars['Speed [m/s]'], # highlight_cases=homerun_indices) fig, ax = mc.plot(sim.outvars['X [m]'], sim.outvars['Y [m]'], sim.outvars['Z [m]'], title='Baseball Trajectory', highlight_cases=homerun_indices, plotkwargs={'zorder': 10}) plot_baseball_field(ax) ax.scatter(sim.outvars['Landing X [m]'].nums, sim.outvars['Landing Y [m]'].nums, 0, s=2, c='k', alpha=0.9, marker='o') # fig.set_size_inches(7.0, 7.0) # plt.savefig('baseball_trajectory.png', dpi=100) sim.plot(highlight_cases=homerun_indices) fig, axs = mc.multi_plot( [sim.invars['Launch Angle [deg]'], sim.outvars['Landing Dist [m]']], title='Launch Angle vs Landing Distance', cov_plot=False, highlight_cases=homerun_indices) # fig.set_size_inches(8.8, 6.6) # plt.savefig('launch_angle_vs_landing.png', dpi=100) plt.show(block=False) ## Calculate and plot sensitivity indices sim.calcSensitivities('Home Run') fig, ax = sim.outvars['Home Run'].plotSensitivities() # fig.set_size_inches(10, 4) # plt.savefig('landing_dist_sensitivities.png', dpi=100) plt.show() return sim
def retirement_example_monte_carlo_sim(): sim = mc.Sim(name='retirement', ndraws=ndraws, fcns=fcns, firstcaseismedian=True, samplemethod='sobol_random', seed=seed, singlethreaded=False, savecasedata=False, verbose=True, debug=True) sp500_mean = 0.114 sp500_stdev = 0.197 inflation = 0.02 nyears = 30 for i in range(nyears): sim.addInVar(name=f'Year {i} Returns', dist=norm, distkwargs={ 'loc': (sp500_mean - inflation), 'scale': sp500_stdev }) sim.addInVar(name='Beginning Balance', dist=uniform, distkwargs={ 'loc': 1000000, 'scale': 100000 }) sim.addConstVal(name='nyears', val=nyears) sim.runSim() wentbrokecases = [ i for i, e in enumerate(sim.outvars['Broke'].vals) if e == 'Yes' ] mc.plot(sim.invars['Year 0 Returns'], sim.outvars['Final Balance'], highlight_cases=0, cov_plot=False) mc.plot(sim.outvars['Broke']) mc.plot(sim.invars['Beginning Balance'], highlight_cases=0) fig, ax = mc.plot(sim.outvars['Date'], sim.outvars['Ending Balance'], highlight_cases=wentbrokecases, title='Yearly Balances') ax.set_yscale('symlog') ax.set_ylim(bottom=1e4) fig.set_size_inches(7.6, 5.4) plt.savefig('yearly_balances.png', dpi=100) sim.genCovarianceMatrix() fig = plt.figure() yearly_return_broke_corr = [] for i in range(nyears): corr = sim.covs[sim.covvarlist.index('Broke')][sim.covvarlist.index( f'Year {i} Returns')] yearly_return_broke_corr.append(corr) plt.plot(range(nyears), yearly_return_broke_corr, 'k') plt.plot(range(nyears), np.zeros(nyears), 'k--') plt.title('Correlation Between Yearly Return and Going Broke') plt.ylabel('Correlation Coeff') plt.xlabel('Year') fig.set_size_inches(7.6, 5.4) plt.savefig('return_broke_corr.png', dpi=100) plt.show() return sim