import%20marimo%0A%0A__generated_with%20%3D%20%220.23.11%22%0Aapp%20%3D%20marimo.App(%0A%20%20%20%20width%3D%22medium%22%2C%0A%20%20%20%20app_title%3D%22Overview%20-%20Hawk%2FDove%20with%20Multiple%20Risk-Attitudes%22%2C%0A%20%20%20%20html_head_file%3D%22..%2Fdocs_head.html%22%2C%0A)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20from%20simulatingrisk.doc_utils%20import%20docs_header%0A%0A%20%20%20%20docs_header()%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%0A%20%20%20%20%23%20Hawk%2FDove%20with%20Multiple%20Risk-Attitudes%20in%20a%20Population%0A%0A%20%20%20%20Overview%20of%20simulation%20batch%20run%20data.%20Includes%20information%20about%20parameters%20and%20number%20of%20runs%2C%20with%20brief%20analysis%20of%20run%20length%20and%20convergence%20correlation%20with%20initial%20parameters.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20polars%20as%20pl%0A%20%20%20%20import%20altair%20as%20alt%0A%20%20%20%20import%20seaborn%20as%20sns%0A%0A%20%20%20%20from%20simulatingrisk.hawkdovemulti.batch_run%20import%20params%0A%0A%20%20%20%20data_dir%20%3D%20Path(%22data%2Fno_adjustment%2F%22)%0A%20%20%20%20return%20alt%2C%20data_dir%2C%20mo%2C%20params%2C%20pl%2C%20sns%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20mo%2C%20params%2C%20pl%2C%20run_groups_df%2C%20runs_per_group%2C%20total_agent_rows)%3A%0A%0A%20%20%20%20param_opts%20%3D%20%5B%5D%0A%0A%20%20%20%20for%20key%2C%20value%20in%20params%5B%22no_adjustment%22%5D.items()%3A%0A%20%20%20%20%20%20%20%20if%20isinstance(value%2C%20(list%2C%20tuple))%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20value_str%20%3D%20%22%2C%20%22.join(%5Bstr(v)%20for%20v%20in%20value%5D)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20value_str%20%3D%20str(value)%0A%20%20%20%20%20%20%20%20param_opts.append(f%22-%20**%7Bkey%7D**%3A%20%7Bvalue_str%7D%22)%0A%0A%20%20%20%20param_info%20%3D%20%22%5Cn%22.join(param_opts)%0A%0A%20%20%20%20%23%20aggregate%20by%20status%20for%20plotting%20and%20reporting%0A%20%20%20%20status_df%20%3D%20df.group_by(%22status%22).agg(count%3Dpl.len()%2C%20percent%3Dpl.len()%20%2F%20df.height)%0A%20%20%20%20%23%20export%20total%20and%20percent%20of%20runs%20that%20converged%20for%20inclusion%20in%20text%0A%20%20%20%20converged_stats%20%3D%20status_df.filter(pl.col.status.eq(%22converged%22)).to_dicts()%5B0%5D%0A%0A%20%20%20%20%23%20TODO%3A%20would%20be%20great%20to%20report%20how%20many%20runs%20per%20parameter%20combination%20(hopefully%20100)%0A%20%20%20%20overview_txt%20%3D%20f%22%22%22%0A%20%20%20%20Analyzing%20data%20from%20**%7Bdf.height%3A%2C%7D**%20total%20simulation%20runs.%20%20Data%20was%20collected%20for%20model%20and%20agents%20at%20the%20last%20round%20only.%0A%0A%20%20%20%20**%7Bconverged_stats%5B%22count%22%5D%3A%2C%7D%20(%7Bconverged_stats%5B%22percent%22%5D%20*%20100%3A.1f%7D%25)**%20%20simulations%20converged.%0A%0A%20%20%20%20Simulations%20were%20run%20on%20the%20following%20combination%20of%20initial%20parameters%3A%0A%20%20%20%20%7Bparam_info%7D%0A%0A%20%20%20%20This%20resulted%20in%20**%7Brun_groups_df.height%3A%2C%7D**%20combinations%3B%20each%20set%20of%20parameters%20was%20run%20**%7Bruns_per_group%3A%2C%7D%20times**.%0A%0A%20%20%20%20Agent%20data%20for%20those%20simualations%20results%20in%20**%7Btotal_agent_rows%3A%2C%7D**%20rows.%0A%20%20%20%20%22%22%22%0A%20%20%20%20mo.md(overview_txt)%0A%20%20%20%20return%20(status_df%2C)%0A%0A%0A%40app.cell%0Adef%20_(data_dir%2C%20pl)%3A%0A%20%20%20%20%23%20load%20all%20model%20files%20in%20the%20no_adjustment%20data%20directory%0A%20%20%20%20df%20%3D%20pl.scan_csv(%0A%20%20%20%20%20%20%20%20%5Bstr(file)%20for%20file%20in%20data_dir.glob(%22*_model.csv%22)%20if%20file.stat().st_size%20!%3D%200%5D%0A%20%20%20%20).collect()%0A%20%20%20%20return%20(df%2C)%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20mo%2C%20pl%2C%20status_df)%3A%0A%20%20%20%20%23%20generate%20a%20nice%20string%20version%20of%20the%20%25%20for%20display%0A%20%20%20%20_status_pct_df%20%3D%20status_df.with_columns(%0A%20%20%20%20%20%20%20%20percent_str%3Dpl.col.percent.map_elements(%0A%20%20%20%20%20%20%20%20%20%20%20%20lambda%20x%3A%20f%22%7Bx%20*%20100%3A%2C.2f%7D%25%22%2C%20return_dtype%3Dpl.String%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%0A%20%20%20%20_count_bar%20%3D%20(%0A%20%20%20%20%20%20%20%20alt.Chart(_status_pct_df)%0A%20%20%20%20%20%20%20%20.mark_bar()%0A%20%20%20%20%20%20%20%20.encode(y%3D%22status%22%2C%20x%3D%22count%22%2C%20color%3D%22status%22)%0A%20%20%20%20)%0A%0A%20%20%20%20text_color%20%3D%20%22white%22%20if%20mo.app_meta().theme%20%3D%3D%20%22light%22%20else%20%22black%22%0A%20%20%20%20_percent_text%20%3D%20_count_bar.mark_text(xOffset%3D20).encode(%0A%20%20%20%20%20%20%20%20y%3Dalt.Y(%22status%22%2C%20title%3D%22%22)%2C%0A%20%20%20%20%20%20%20%20x%3Dalt.X(%22count%22%2C%20title%3D%22Number%20of%20Simulations%22)%2C%0A%20%20%20%20%20%20%20%20text%3D%22percent_str%22%2C%0A%20%20%20%20%20%20%20%20color%3Dalt.value(text_color)%2C%0A%20%20%20%20)%0A%0A%20%20%20%20mo.ui.altair_chart((_count_bar%20%2B%20_percent_text).properties(width%3D550))%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%0A%20%20%20%20To%20check%20if%20convergence%20is%20correlated%20with%20any%20of%20the%20initial%20parameters%2C%20we%20generate%20and%20graph%20a%20correlation%20matrix.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20pl)%3A%0A%20%20%20%20%23%20we%20want%20to%20know%20if%20there%20is%20any%20correlation%20between%20convergence%20%2F%20run%20length%20and%20the%20starting%20parameters%0A%0A%20%20%20%20corr_matrix_df%20%3D%20(%0A%20%20%20%20%20%20%20%20%23%20add%20a%20boolean%20column%20for%20status%20converged%0A%20%20%20%20%20%20%20%20df.with_columns(converged%3Dpl.col.status.eq(%22converged%22))%0A%20%20%20%20%20%20%20%20.rename(%7B%22Step%22%3A%20%22run%20length%22%7D)%0A%20%20%20%20%20%20%20%20.select(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22run%20length%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22grid_size%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22play_neighborhood%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22observed_neighborhood%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22hawk_odds%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22random_play_odds%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22converged%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22include_endpoints%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.corr()%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20uncomment%20to%20display%0A%20%20%20%20%23%20corr_matrix_df%0A%20%20%20%20return%20(corr_matrix_df%2C)%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20corr_matrix_df%2C%20pl)%3A%0A%20%20%20%20%23%20add%20labels%20and%20unpivot%20for%20graphing%20as%20a%20heatmap%0A%0A%20%20%20%20%23%20add%20columns%20as%20label%2C%20then%20unpivot%20to%20long%20form%20for%20charting%0A%20%20%20%20corr_matrix_long_df%20%3D%20(%0A%20%20%20%20%20%20%20%20corr_matrix_df.with_columns(pl.Series(%22var_x%22%2C%20corr_matrix_df.columns))%0A%20%20%20%20%20%20%20%20.unpivot(%0A%20%20%20%20%20%20%20%20%20%20%20%20on%3Dcorr_matrix_df.columns%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20index%3D%22var_x%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20variable_name%3D%22var_y%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20value_name%3D%22correlation%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.filter(pl.col.var_y.is_in(%5B%22run%20length%22%2C%20%22converged%22%5D))%0A%20%20%20%20%20%20%20%20.filter(~pl.col.var_x.is_in(%5B%22run%20length%22%2C%20%22converged%22%5D))%0A%20%20%20%20%20%20%20%20.with_columns(%0A%20%20%20%20%20%20%20%20%20%20%20%20correlation_str%3Dpl.col.correlation.map_elements(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20lambda%20x%3A%20f%22%7Bx%3A%2C.2f%7D%22%2C%20return_dtype%3Dpl.String%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%0A%20%20%20%20_heatmap_corr_chart%20%3D%20(%0A%20%20%20%20%20%20%20%20alt.Chart(corr_matrix_long_df)%0A%20%20%20%20%20%20%20%20.mark_rect()%0A%20%20%20%20%20%20%20%20.encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22var_x%3AO%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20axis%3Dalt.Axis(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20orient%3D%22top%22%2C%20%20%23%20move%20axis%20to%20top%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20labelAngle%3D-45%2C%20%20%23%20angle%20the%20labels%20(negative%20%3D%20counterclockwise)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22var_y%3AO%22%2C%20title%3D%22%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20use%20spectral%20theme%20since%20we%20have%20both%20negative%20and%20positive%20correlations%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color(%22correlation%22).scale(scheme%3D%22spectral%22)%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.properties(width%3D450%2C%20height%3D300)%0A%20%20%20%20)%0A%0A%20%20%20%20_text_corr_chart%20%3D%20_heatmap_corr_chart.mark_text().encode(%0A%20%20%20%20%20%20%20%20x%3D%22var_x%3AO%22%2C%0A%20%20%20%20%20%20%20%20y%3D%22var_y%3AO%22%2C%0A%20%20%20%20%20%20%20%20text%3D%22correlation_str%22%2C%0A%20%20%20%20%20%20%20%20%23%20for%20contrast%2C%20vary%20the%20color%20based%20on%20the%20intensity%20of%20the%20correlation%2C%20negative%20or%20positive%0A%20%20%20%20%20%20%20%20color%3Dalt.condition(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22abs(datum.correlation)%20%3E%200.3%22%2C%20alt.value(%22white%22)%2C%20alt.value(%22black%22)%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20)%0A%0A%20%20%20%20_heatmap_corr_chart%20%2B%20_text_corr_chart%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%0A%20%20%20%20There%20is%20a%20noticeable%20correlation%20between%20grid%20size%20and%20convergence%20%2F%20simulation%20run%20length.%20%20Convergence%20is%20slightly%20correlated%20with%20grid%20size%3B%20run%20length%20is%20negatively%20correlated%20with%20grid%20size.%20%20This%20is%20because%20the%20samll%205x5%20simulation%20has%20a%20much%20lower%20convergence%20rate%2C%20with%20a%20corresponding%20number%20of%20simulations%20that%20ran%20until%20the%20batch-run%20configured%20maximum%20of%20300%20steps.%0A%0A%20%20%20%20A%20bar%20chart%20of%20simulation%20run%20length%20(based%20on%20last%20step)%20faceted%20by%20grid%20size%20shows%20that%20the%20majority%20of%20runs%20end%20fairly%20quickly.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(alt%2C%20df%2C%20mo%2C%20pl)%3A%0A%20%20%20%20%23%20generate%20aggregate%20counts%20by%20step%20for%20graphing%20(charting%20the%20full%20data%20without%20aggregation%20is%20too%20large%20for%20altair)%0A%20%20%20%20grid_runlength_df%20%3D%20df.group_by(%22Step%22%2C%20%22status%22%2C%20%22grid_size%22).agg(count%3Dpl.len())%0A%0A%20%20%20%20mo.ui.altair_chart(%0A%20%20%20%20%20%20%20%20alt.Chart(grid_runlength_df)%0A%20%20%20%20%20%20%20%20.mark_bar()%0A%20%20%20%20%20%20%20%20.encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22Step%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%22count%22%2C%20title%3D%22Number%20of%20Simulations%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20tooltip%3D%22count%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20color%3D%22status%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20.properties(width%3D205%2C%20height%3D180%2C%20title%3D%22Simulation%20run%20length%22)%0A%20%20%20%20%20%20%20%20.facet(%22grid_size%22%2C%20title%3D%22Simulation%20run%20length%20by%20grid%20size%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(r%22%22%22%0A%20%20%20%20A%20%22boxenplot%22%20is%20a%20helpful%20way%20to%20see%20the%20distribution%20of%20simulation%20run%20lengths%20over%20grid%20sizes.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20sns)%3A%0A%20%20%20%20sns.boxenplot(data%3Ddf%2C%20y%3D%22Step%22%2C%20x%3D%22grid_size%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%0A%20%20%20%20The%20other%20parameter%20with%20a%20noticeable%20impact%20on%20convergence%20is%20the%20random%20play%20odds%20-%20an%20increase%20in%20random%20play%20odds%20results%20in%20a%20decrease%20in%20convergence%20and%20an%20increase%20in%20run%20length.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20sns)%3A%0A%20%20%20%20sns.boxenplot(data%3Ddf%2C%20y%3D%22Step%22%2C%20x%3D%22random_play_odds%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%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%20Data%20file%20review%0A%0A%20%20%20%20List%20and%20checks%20on%20the%20files%2C%20parameters%2C%20and%20number%20of%20runs%20included%20in%20the%20data%20used%20for%20analysis.%0A%0A%0A%20%20%20%20%23%23%23%20Model%20data%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(data_dir%2C%20mo%2C%20pl)%3A%0A%20%20%20%20%23%20create%20a%20dataframe%20with%20overview%20information%20the%20files%20we're%20drawing%20from%2C%0A%20%20%20%20%23%20to%20confirm%20that%20the%20files%20have%20the%20data%20and%20parameters%20we%20expect%0A%0A%20%20%20%20def%20get_data_file_info(file_iter)%3A%0A%20%20%20%20%20%20%20%20file_info%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20data_file%20in%20file_iter%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20file_size%20%3D%20data_file.stat().st_size%0A%20%20%20%20%20%20%20%20%20%20%20%20rows%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20max_step%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20cols%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20n_cols%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20file_size%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20file_df%20%3D%20pl.read_csv(data_file)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rows%20%3D%20file_df.height%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%22Step%22%20in%20file_df.columns%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20max_step%20%3D%20file_df%5B%22Step%22%5D.max()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(f%22data%20but%20no%20step%20in%20%7Bdata_file.name%7D%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cols%20%3D%20file_df.columns%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20n_cols%20%3D%20len(cols)%0A%20%20%20%20%20%20%20%20%20%20%20%20file_info.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22file_name%22%3A%20data_file.name%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22file_size%22%3A%20file_size%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22rows%22%3A%20rows%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22max_step%22%3A%20max_step%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%22columns%22%3A%20cols%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22n_cols%22%3A%20n_cols%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20file_info_df%20%3D%20pl.from_dicts(file_info)%0A%20%20%20%20%20%20%20%20return%20file_info_df%0A%0A%20%20%20%20model_file_info_df%20%3D%20get_data_file_info(data_dir.glob(%22*_model.csv%22))%0A%20%20%20%20%23%20check%20that%20there%20is%20a%20corresponding%20agent%20data%20file%0A%20%20%20%20model_file_info_df%20%3D%20model_file_info_df.with_columns(%0A%20%20%20%20%20%20%20%20agent_file_name%3Dpl.col.file_name.str.replace(%22_model%22%2C%20%22_agent%22)%0A%20%20%20%20).with_columns(%0A%20%20%20%20%20%20%20%20agent_file_exists%3Dpl.col.agent_file_name.map_elements(%0A%20%20%20%20%20%20%20%20%20%20%20%20lambda%20x%3A%20(data_dir%20%2F%20x).exists()%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%0A%20%20%20%20mo.ui.table(model_file_info_df%2C%20page_size%3D15%2C%20selection%3DNone)%0A%20%20%20%20return%20get_data_file_info%2C%20model_file_info_df%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Check%20that%20the%20data%20doesn't%20include%20any%20incomplete%20or%20unexpected%20data.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(model_file_info_df%2C%20pl)%3A%0A%20%20%20%20%23%20we%20expect%20the%20same%20number%20of%20parameters%20in%20each%20file%20(may%20be%20redundant%3B%20can't%20load%20into%20common%20dataframe%20if%20they%20don't%20match)%0A%20%20%20%20assert%20(model_file_info_df%5B%22n_cols%22%5D.n_unique())%20%3D%3D%201%2C%20(%0A%20%20%20%20%20%20%20%20%22All%20files%20should%20have%20the%20same%20number%20of%20parameters%22%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20less%20than%203240%20means%20incomplete%20run%20(not%20all%20parameter%20combos)%0A%20%20%20%20assert%20model_file_info_df.filter(pl.col.rows.lt(3240)).height%20%3D%3D%200%2C%20(%0A%20%20%20%20%20%20%20%20%22Data%20should%20not%20include%20files%20with%20less%20than%203240%20rows%20(incomplete%20run)%22%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20max%20step%20300%20was%20used%20for%20the%20full%20set%20fo%20100%20batches%0A%20%20%20%20assert%20model_file_info_df.filter(pl.col.max_step.ne(300)).height%20%3D%3D%200%2C%20(%0A%20%20%20%20%20%20%20%20%22Data%20should%20only%20include%20files%20with%20max%20step%20of%20300%22%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20all%20model%20files%20should%20have%20agent%20%20data%0A%20%20%20%20assert%20model_file_info_df.filter(pl.col.agent_file_exists.eq(False)).height%20%3D%3D%200%2C%20(%0A%20%20%20%20%20%20%20%20%22All%20model%20data%20files%20should%20have%20corresponding%20agent%20data%20file%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(r%22%22%22%0A%20%20%20%20Aggregate%20collected%20data%20by%20the%20initial%20parameters%20and%20check%20combination%20of%20parameters%20and%20number%20of%20runs%20per%20parameter%20set.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df%2C%20params%2C%20pl)%3A%0A%20%20%20%20%23%20runs%20per%20parameter%20combination%0A%20%20%20%20run_groups_df%20%3D%20df.group_by(params%5B%22no_adjustment%22%5D.keys()).agg(runs%3Dpl.len())%0A%0A%20%20%20%20%23%20we%20expect%20the%20same%20number%20of%20runs%20for%20each%20parameter%20set%0A%20%20%20%20assert%20(run_groups_df%5B%22runs%22%5D.n_unique())%20%3D%3D%201%0A%0A%20%20%20%20runs_per_group%20%3D%20run_groups_df%5B%22runs%22%5D.max()%0A%0A%20%20%20%20run_groups_df%0A%20%20%20%20return%20run_groups_df%2C%20runs_per_group%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Agent%20data%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(data_dir%2C%20get_data_file_info%2C%20mo%2C%20pl)%3A%0A%0A%20%20%20%20agent_file_info_df%20%3D%20get_data_file_info(data_dir.glob(%22*_agent.csv%22))%0A%20%20%20%20%23%20check%20that%20there%20is%20a%20corresponding%20model%20file%0A%20%20%20%20agent_file_info_df%20%3D%20agent_file_info_df.with_columns(%0A%20%20%20%20%20%20%20%20model_file_name%3Dpl.col.file_name.str.replace(%22_agent%22%2C%20%22_model%22)%0A%20%20%20%20).with_columns(%0A%20%20%20%20%20%20%20%20model_file_exists%3Dpl.col.model_file_name.map_elements(%0A%20%20%20%20%20%20%20%20%20%20%20%20lambda%20x%3A%20(data_dir%20%2F%20x).exists()%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%0A%20%20%20%20mo.ui.table(agent_file_info_df%2C%20page_size%3D15%2C%20selection%3DNone)%0A%20%20%20%20return%20(agent_file_info_df%2C)%0A%0A%0A%40app.cell%0Adef%20_(agent_file_info_df)%3A%0A%20%20%20%20total_agent_rows%20%3D%20agent_file_info_df%5B%22rows%22%5D.sum()%0A%20%20%20%20total_agent_rows%0A%20%20%20%20return%20(total_agent_rows%2C)%0A%0A%0A%40app.cell%0Adef%20_(agent_file_info_df%2C%20pl)%3A%0A%20%20%20%20%23%20we%20expect%20the%20same%20number%20of%20parameters%20in%20each%20file%0A%20%20%20%20assert%20(agent_file_info_df%5B%22n_cols%22%5D.n_unique())%20%3D%3D%201%2C%20(%0A%20%20%20%20%20%20%20%20%22All%20files%20should%20have%20the%20same%20number%20of%20parameters%22%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20max%20step%20300%20was%20used%20for%20the%20full%20set%20fo%20100%20batches%0A%20%20%20%20assert%20agent_file_info_df.filter(pl.col.max_step.ne(300)).height%20%3D%3D%200%2C%20(%0A%20%20%20%20%20%20%20%20%22Data%20should%20only%20include%20files%20with%20max%20step%20of%20300%22%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20all%20agent%20files%20should%20have%20model%20data%0A%20%20%20%20assert%20agent_file_info_df.filter(pl.col.model_file_exists.eq(False)).height%20%3D%3D%200%2C%20(%0A%20%20%20%20%20%20%20%20%22All%20agent%20data%20files%20should%20have%20corresponding%20model%20data%20file%22%0A%20%20%20%20)%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
11c6875624dd1744b10ac4ba8c7c6219