<commit_before>// Copyright 2019 DeepMind Technologies Ltd. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "open_spiel/algorithms/tabular_exploitability.h"

#include <cmath>
#include <limits>
#include <unordered_set>

#include "open_spiel/algorithms/expected_returns.h"
#include "open_spiel/algorithms/history_tree.h"
#include "open_spiel/spiel.h"
#include "open_spiel/spiel_utils.h"

namespace open_spiel {
namespace algorithms {

TabularBestResponse::TabularBestResponse(const Game& game,
                                         int best_responder_id,
                                         const Policy* policy)
    : best_responder_id_(best_responder_id),
      tabular_policy_container_(),
      policy_(policy),
      tree_(HistoryTree(game.NewInitialState(), best_responder_id_)),
      num_players_(game.NumPlayers()),
      infosets_(GetAllInfoSets(game.NewInitialState(), best_responder_id,
                               policy, &tree_)),
      root_(game.NewInitialState()) {
  if (game.GetType().dynamics != GameType::Dynamics::kSequential) {
    SpielFatalError("The game must be turn-based.");
  }
}

TabularBestResponse::TabularBestResponse(
    const Game& game, int best_responder_id,
    const std::unordered_map<std::string, ActionsAndProbs>& policy_table)
    : best_responder_id_(best_responder_id),
      tabular_policy_container_(policy_table),
      policy_(&tabular_policy_container_),
      tree_(HistoryTree(game.NewInitialState(), best_responder_id_)),
      num_players_(game.NumPlayers()),
      infosets_(GetAllInfoSets(game.NewInitialState(), best_responder_id,
                               policy_, &tree_)),
      root_(game.NewInitialState()) {
  if (game.GetType().dynamics != GameType::Dynamics::kSequential) {
    SpielFatalError("The game must be turn-based.");
  }
}

double TabularBestResponse::HandleTerminalCase(const HistoryNode& node) const {
  return node.GetValue();
}

double TabularBestResponse::HandleDecisionCase(HistoryNode* node) {
  if (node == nullptr) SpielFatalError("HandleDecisionCase: node is null.");
  if (node->GetState()->CurrentPlayer() == best_responder_id_) {
    // If we're playing as the best responder, we look at every child node,
    // and pick the one with the highest expected utility to play.
    Action action = BestResponseAction(node->GetInfoState());
    HistoryNode* child = node->GetChild(action).second;
    if (child == nullptr) SpielFatalError("HandleDecisionCase: node is null.");
    return Value(child->GetHistory());
  }
  // If the other player is playing, then we can recursively compute the
  // expected utility of that node by looking at their policy.
  // We take child probabilities from the policy as that is what we are
  // calculating a best response to.
  ActionsAndProbs state_policy = policy_->GetStatePolicy(node->GetInfoState());
  if (state_policy.empty())
    SpielFatalError(absl::StrCat("InfoState ", node->GetInfoState(),
                                 " not found in policy."));
  if (state_policy.size() > node->NumChildren()) {
    int num_zeros = 0;
    for (const auto& a_and_p : state_policy) {
      if (Near(a_and_p.second, 0.)) ++num_zeros;
    }
    // We check here that the policy is valid, i.e. that it doesn't contain too
    // many (invalid) actions. This can only happen when the policy is built
    // incorrectly. If this is failing, you are building the policy wrong.
    if (state_policy.size() > node->NumChildren() + num_zeros) {
      std::vector<std::string> action_probs_str_vector;
      action_probs_str_vector.reserve(state_policy.size());
      for (const auto& action_prob : state_policy) {
        // TODO(b/b/127423396): Use absl::StrFormat.
        action_probs_str_vector.push_back(absl::StrCat(
            "(", action_prob.first, ", ", action_prob.second, ")"));
      }
      std::string action_probs_str =
          absl::StrJoin(action_probs_str_vector, " ");<commit_msg>Fix Typo in TODO.<commit_after>// Copyright 2019 DeepMind Technologies Ltd. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "open_spiel/algorithms/tabular_exploitability.h"

#include <cmath>
#include <limits>
#include <unordered_set>

#include "open_spiel/algorithms/expected_returns.h"
#include "open_spiel/algorithms/history_tree.h"
#include "open_spiel/spiel.h"
#include "open_spiel/spiel_utils.h"

namespace open_spiel {
namespace algorithms {

TabularBestResponse::TabularBestResponse(const Game& game,
                                         int best_responder_id,
                                         const Policy* policy)
    : best_responder_id_(best_responder_id),
      tabular_policy_container_(),
      policy_(policy),
      tree_(HistoryTree(game.NewInitialState(), best_responder_id_)),
      num_players_(game.NumPlayers()),
      infosets_(GetAllInfoSets(game.NewInitialState(), best_responder_id,
                               policy, &tree_)),
      root_(game.NewInitialState()) {
  if (game.GetType().dynamics != GameType::Dynamics::kSequential) {
    SpielFatalError("The game must be turn-based.");
  }
}

TabularBestResponse::TabularBestResponse(
    const Game& game, int best_responder_id,
    const std::unordered_map<std::string, ActionsAndProbs>& policy_table)
    : best_responder_id_(best_responder_id),
      tabular_policy_container_(policy_table),
      policy_(&tabular_policy_container_),
      tree_(HistoryTree(game.NewInitialState(), best_responder_id_)),
      num_players_(game.NumPlayers()),
      infosets_(GetAllInfoSets(game.NewInitialState(), best_responder_id,
                               policy_, &tree_)),
      root_(game.NewInitialState()) {
  if (game.GetType().dynamics != GameType::Dynamics::kSequential) {
    SpielFatalError("The game must be turn-based.");
  }
}

double TabularBestResponse::HandleTerminalCase(const HistoryNode& node) const {
  return node.GetValue();
}

double TabularBestResponse::HandleDecisionCase(HistoryNode* node) {
  if (node == nullptr) SpielFatalError("HandleDecisionCase: node is null.");
  if (node->GetState()->CurrentPlayer() == best_responder_id_) {
    // If we're playing as the best responder, we look at every child node,
    // and pick the one with the highest expected utility to play.
    Action action = BestResponseAction(node->GetInfoState());
    HistoryNode* child = node->GetChild(action).second;
    if (child == nullptr) SpielFatalError("HandleDecisionCase: node is null.");
    return Value(child->GetHistory());
  }
  // If the other player is playing, then we can recursively compute the
  // expected utility of that node by looking at their policy.
  // We take child probabilities from the policy as that is what we are
  // calculating a best response to.
  ActionsAndProbs state_policy = policy_->GetStatePolicy(node->GetInfoState());
  if (state_policy.empty())
    SpielFatalError(absl::StrCat("InfoState ", node->GetInfoState(),
                                 " not found in policy."));
  if (state_policy.size() > node->NumChildren()) {
    int num_zeros = 0;
    for (const auto& a_and_p : state_policy) {
      if (Near(a_and_p.second, 0.)) ++num_zeros;
    }
    // We check here that the policy is valid, i.e. that it doesn't contain too
    // many (invalid) actions. This can only happen when the policy is built
    // incorrectly. If this is failing, you are building the policy wrong.
    if (state_policy.size() > node->NumChildren() + num_zeros) {
      std::vector<std::string> action_probs_str_vector;
      action_probs_str_vector.reserve(state_policy.size());
      for (const auto& action_prob : state_policy) {
        // TODO(b/127423396): Use absl::StrFormat.
        action_probs_str_vector.push_back(absl::StrCat(
            "(", action_prob.first, ", ", action_prob.second, ")"));
      }
      std::string action_probs_str =
          absl::StrJoin(action_probs_str_vector, " ");
{'fraction_non_alphanumeric': 0.1111111111111111, 'fraction_numerical': 0.004247708473060586, 'mean_word_length': 3.5416243654822335, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5443323', 'n_tokens_mistral': 2627, 'n_tokens_neox': 2572, 'n_words': 695}