Example #1
0
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;
}