void scaling_t::analyze_stats() { if ( ! calculate_scale_factors ) return; if ( sim -> players_by_name.empty() ) return; // No Players std::vector<stat_e> stats_to_scale; for ( stat_e i = STAT_NONE; i < STAT_MAX; i++ ) if ( is_scaling_stat( sim, i ) && ( stats.get_stat( i ) != 0 ) ) stats_to_scale.push_back( i ); mutex.lock(); num_scaling_stats = remaining_scaling_stats = as<int>( stats_to_scale.size() ); mutex.unlock(); if ( ! num_scaling_stats ) return; // No Stats to scale mutex.lock(); baseline_sim = sim; // Take the current sim as baseline mutex.unlock(); for ( size_t k = 0; k < stats_to_scale.size(); ++k ) { if ( sim -> is_canceled() ) break; current_scaling_stat = stats_to_scale[ k ]; // Stat we're scaling over const stat_e& stat = current_scaling_stat; double scale_delta = stats.get_stat( stat ); assert ( scale_delta ); bool center = center_scale_delta && ! stat_may_cap( stat ); mutex.lock(); ref_sim = baseline_sim; delta_sim = new sim_t( sim ); mutex.unlock(); if ( sim -> report_progress ) { std::stringstream stat_name; stat_name.width( 12 ); stat_name << std::left << std::string( util::stat_type_abbrev( stat ) ) + ":"; delta_sim -> sim_phase_str = "Generating " + stat_name.str(); //util::fprintf( stdout, "\nGenerating scale factors for %s...\n", util::stat_type_string( stat ) ); //fflush( stdout ); } delta_sim -> scaling -> scale_stat = stat; delta_sim -> scaling -> scale_value = +scale_delta / ( center ? 2 : 1 ); delta_sim -> execute(); if ( center ) { mutex.lock(); ref_sim = new sim_t( sim ); mutex.unlock(); if ( sim -> report_progress ) { std::stringstream stat_name; stat_name.width( 8 ); stat_name << std::left << std::string( util::stat_type_abbrev( stat ) ) + ":"; ref_sim -> sim_phase_str = "Generating ref " + stat_name.str(); } ref_sim -> scaling -> scale_stat = stat; ref_sim -> scaling -> scale_value = center ? -( scale_delta / 2 ) : 0; ref_sim -> execute(); } for ( size_t j = 0; j < sim -> players_by_name.size(); j++ ) { player_t* p = sim -> players_by_name[ j ]; if ( ! p -> scales_with[ stat ] ) continue; player_t* ref_p = ref_sim -> find_player( p -> name() ); player_t* delta_p = delta_sim -> find_player( p -> name() ); assert( ref_p && "Reference Player not found" ); assert( delta_p && "Delta player not found" ); double divisor = scale_delta; if ( delta_p -> invert_scaling ) divisor = -divisor; if ( divisor < 0.0 ) divisor += ref_p -> over_cap[ stat ]; for ( scale_metric_e sm = SCALE_METRIC_NONE; sm < SCALE_METRIC_MAX; sm++ ) { double delta_score = delta_p -> scaling_for_metric( sm ).value; double ref_score = ref_p -> scaling_for_metric( sm ).value; double delta_error = delta_p -> scaling_for_metric( sm ).stddev * delta_sim -> confidence_estimator; double ref_error = ref_p -> scaling_for_metric( sm ).stddev * ref_sim -> confidence_estimator; // TODO: this is the only place in the entire code base where scaling_delta_dps shows up, // apart from declaration in simulationcraft.hpp line 4535. Possible to remove? p -> scaling_delta_dps[ sm ].set_stat( stat, delta_score ); double score = ( delta_score - ref_score ) / divisor; double error = delta_error * delta_error + ref_error * ref_error; if ( error > 0 ) error = sqrt( error ); error = fabs( error / divisor ); if ( fabs( divisor ) < 1.0 ) // For things like Weapon Speed, show the gain per 0.1 speed gain rather than every 1.0. { score /= 10.0; error /= 10.0; delta_error /= 10.0; } analyze_ability_stats( stat, divisor, p, ref_p, delta_p ); if ( center ) p -> scaling_compare_error[ sm ].set_stat( stat, error ); else p -> scaling_compare_error[ sm ].set_stat( stat, delta_error / divisor ); p -> scaling[ sm ].set_stat( stat, score ); p -> scaling_error[ sm ].set_stat( stat, error ); } } if ( debug_scale_factors ) { std::cout << "\nref_sim report for '" << util::stat_type_string( stat ) << "'..." << std::endl; report::print_text( ref_sim, true ); std::cout << "\ndelta_sim report for '" << util::stat_type_string( stat ) << "'..." << std::endl; report::print_text( delta_sim, true ); } mutex.lock(); if ( ref_sim != baseline_sim && ref_sim != sim ) { delete ref_sim; ref_sim = nullptr; } delete delta_sim; delta_sim = nullptr; remaining_scaling_stats--; mutex.unlock(); } if ( baseline_sim != sim ) delete baseline_sim; baseline_sim = nullptr; }
void scaling_t::analyze_stats() { if ( ! calculate_scale_factors ) return; if ( sim -> players_by_name.empty() ) return; // No Players std::vector<stat_e> stats_to_scale; for ( stat_e i = STAT_NONE; i < STAT_MAX; i++ ) if ( is_scaling_stat( sim, i ) && ( stats.get_stat( i ) != 0 ) ) stats_to_scale.push_back( i ); num_scaling_stats = remaining_scaling_stats = as<int>( stats_to_scale.size() ); if ( ! num_scaling_stats ) return; // No Stats to scale baseline_sim = sim; // Take the current sim as baseline for ( size_t k = 0; k < stats_to_scale.size(); ++k ) { if ( sim -> is_canceled() ) break; current_scaling_stat = stats_to_scale[ k ]; // Stat we're scaling over const stat_e& stat = current_scaling_stat; double scale_delta = stats.get_stat( stat ); assert ( scale_delta ); bool center = center_scale_delta && ! stat_may_cap( stat ); ref_sim = baseline_sim; delta_sim = new sim_t( sim ); delta_sim -> scaling -> scale_stat = stat; delta_sim -> scaling -> scale_value = +scale_delta / ( center ? 2 : 1 ); if ( sim -> report_progress ) { std::stringstream stat_name; stat_name.width( 12 ); stat_name << std::left << std::string( util::stat_type_abbrev( stat ) ) + ":"; delta_sim -> sim_phase_str = "Generating " + stat_name.str(); //util::fprintf( stdout, "\nGenerating scale factors for %s...\n", util::stat_type_string( stat ) ); //fflush( stdout ); } delta_sim -> execute(); if ( center ) { ref_sim = new sim_t( sim ); if ( sim -> report_progress ) { std::stringstream stat_name; stat_name.width( 8 ); stat_name << std::left << std::string( util::stat_type_abbrev( stat ) ) + ":"; ref_sim -> sim_phase_str = "Generating ref " + stat_name.str(); } ref_sim -> scaling -> scale_stat = stat; ref_sim -> scaling -> scale_value = center ? -( scale_delta / 2 ) : 0; ref_sim -> execute(); } for ( size_t j = 0; j < sim -> players_by_name.size(); j++ ) { player_t* p = sim -> players_by_name[ j ]; if ( ! p -> scales_with[ stat ] ) continue; player_t* ref_p = ref_sim -> find_player( p -> name() ); player_t* delta_p = delta_sim -> find_player( p -> name() ); assert( ref_p && "Reference Player not found" ); assert( delta_p && "Delta player not found" ); double divisor = scale_delta; if ( delta_p -> invert_scaling ) divisor = -divisor; if ( divisor < 0.0 ) divisor += ref_p -> over_cap[ stat ]; double delta_score = delta_p -> scales_over().value; double ref_score = ref_p -> scales_over().value; double delta_error = delta_p -> scales_over().stddev * delta_sim -> confidence_estimator; double ref_error = ref_p -> scales_over().stddev * ref_sim -> confidence_estimator; p -> scaling_delta_dps.set_stat( stat, delta_score ); //if we do a dtps analysis for stamina, scale it by the tank's hp so that we get relative dtps if ( stat == STAT_STAMINA && scale_over == "dtps" ) { delta_score /= delta_p -> resources.max[ RESOURCE_HEALTH ]; ref_score /= ref_p -> resources.max[ RESOURCE_HEALTH ]; delta_error /= delta_p -> resources.max[ RESOURCE_HEALTH ]; ref_error /= ref_p -> resources.max[ RESOURCE_HEALTH ]; } double score = ( delta_score - ref_score ) / divisor; double error = delta_error * delta_error + ref_error * ref_error; //if we do a dtps analysis for stamina, unscale relative dtps so that we can compare to the other factors if ( stat == STAT_STAMINA && scale_over == "dtps" ) { score *= ref_p -> resources.max[ RESOURCE_HEALTH ]; error *= ref_p -> resources.max[ RESOURCE_HEALTH ] * ref_p -> resources.max[ RESOURCE_HEALTH ]; } if ( error > 0 ) error = sqrt( error ); error = fabs( error / divisor ); if ( fabs( divisor ) < 1.0 ) // For things like Weapon Speed, show the gain per 0.1 speed gain rather than every 1.0. { score /= 10.0; error /= 10.0; delta_error /= 10.0; } analyze_ability_stats( stat, divisor, p, ref_p, delta_p ); if ( center ) p -> scaling_compare_error.set_stat( stat, error ); else p -> scaling_compare_error.set_stat( stat, delta_error / divisor ); p -> scaling.set_stat( stat, score ); p -> scaling_error.set_stat( stat, error ); } if ( debug_scale_factors ) { io::cfile report_f( sim -> output_file_str, "a" ); if ( report_f ) { ref_sim -> out_std.printf( "\nref_sim report for %s...\n", util::stat_type_string( stat ) ); report::print_text( report_f, ref_sim, true ); delta_sim -> out_std.printf( "\ndelta_sim report for %s...\n", util::stat_type_string( stat ) ); report::print_text( report_f, delta_sim, true ); } } if ( ref_sim != baseline_sim && ref_sim != sim ) { delete ref_sim; ref_sim = 0; } delete delta_sim; delta_sim = 0; remaining_scaling_stats--; } if ( baseline_sim != sim ) delete baseline_sim; baseline_sim = 0; }
void scaling_t::analyze_stats() { if ( ! calculate_scale_factors ) return; int num_players = ( int ) sim -> players_by_name.size(); if ( num_players == 0 ) return; remaining_scaling_stats = 0; for ( int i=0; i < STAT_MAX; i++ ) if ( is_scaling_stat( sim, i ) && ( stats.get_stat( i ) != 0 ) ) remaining_scaling_stats++; num_scaling_stats = remaining_scaling_stats; if ( num_scaling_stats == 0 ) return; baseline_sim = sim; if ( smooth_scale_factors ) { if( sim -> report_progress ) { util_t::fprintf( stdout, "\nGenerating smooth baseline...\n" ); fflush( stdout ); } baseline_sim = new sim_t( sim ); baseline_sim -> scaling -> scale_stat = STAT_MAX-1; baseline_sim -> execute(); } for ( int i=0; i < STAT_MAX; i++ ) { if ( sim -> canceled ) break; if ( ! is_scaling_stat( sim, i ) ) continue; double scale_delta = stats.get_stat( i ); if ( scale_delta == 0.0 ) continue; current_scaling_stat = i; if( sim -> report_progress ) { util_t::fprintf( stdout, "\nGenerating scale factors for %s...\n", util_t::stat_type_string( i ) ); fflush( stdout ); } bool center = center_scale_delta && ! stat_may_cap( i ); ref_sim = center ? new sim_t( sim ) : baseline_sim; delta_sim = new sim_t( sim ); delta_sim -> scaling -> scale_stat = i; delta_sim -> scaling -> scale_value = +scale_delta / ( center ? 2 : 1 ); delta_sim -> execute(); if ( center ) { ref_sim -> scaling -> scale_stat = i; ref_sim -> scaling -> scale_value = center ? -( scale_delta / 2 ) : 0; ref_sim -> execute(); } for ( int j=0; j < num_players; j++ ) { player_t* p = sim -> players_by_name[ j ]; if ( p -> scales_with[ i ] <= 0 ) continue; player_t* ref_p = ref_sim -> find_player( p -> name() ); player_t* delta_p = delta_sim -> find_player( p -> name() ); double divisor = scale_delta; if ( divisor < 0.0 ) divisor += ref_p -> over_cap[ i ]; double f = ( delta_p -> dps - ref_p -> dps ) / divisor; if ( fabs( divisor ) < 1.0 ) // For things like Weapon Speed, show the gain per 0.1 speed gain rather than every 1.0. f /= 10.0; if ( f >= scale_factor_noise ) p -> scaling.set_stat( i, f ); } if ( debug_scale_factors ) { report_t::print_text( sim -> output_file, ref_sim, true ); report_t::print_text( sim -> output_file, delta_sim, true ); } if ( ref_sim != baseline_sim && ref_sim != sim ) delete ref_sim; delete delta_sim; delta_sim = ref_sim = 0; remaining_scaling_stats--; } if ( baseline_sim != sim ) delete baseline_sim; baseline_sim = 0; }