<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"

#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "components/signin/core/browser/webdata/token_web_data.h"
#include "components/webdata/common/web_data_service_base.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#include "net/url_request/url_request_context_getter.h"

namespace {

const char kAccountIdPrefix[] = "AccountId-";
const size_t kAccountIdPrefixLength = 10;

std::string ApplyAccountIdPrefix(const std::string& account_id) {
  return kAccountIdPrefix + account_id;
}

bool IsLegacyRefreshTokenId(const std::string& service_id) {
  return service_id == GaiaConstants::kGaiaOAuth2LoginRefreshToken;
}

bool IsLegacyServiceId(const std::string& account_id) {
  return account_id.compare(0u, kAccountIdPrefixLength, kAccountIdPrefix) != 0;
}

std::string RemoveAccountIdPrefix(const std::string& prefixed_account_id) {
  return prefixed_account_id.substr(kAccountIdPrefixLength);
}

}  // namespace

// This class sends a request to GAIA to revoke the given refresh token from
// the server.  This is a best effort attempt only.  This class deletes itself
// when done sucessfully or otherwise.
class MutableProfileOAuth2TokenService::RevokeServerRefreshToken
    : public GaiaAuthConsumer {
 public:
  RevokeServerRefreshToken(MutableProfileOAuth2TokenService* token_service,
                           const std::string& account_id);
  ~RevokeServerRefreshToken() override;

 private:
  // GaiaAuthConsumer overrides:
  void OnOAuth2RevokeTokenCompleted() override;

  MutableProfileOAuth2TokenService* token_service_;
  GaiaAuthFetcher fetcher_;

  DISALLOW_COPY_AND_ASSIGN(RevokeServerRefreshToken);
};

MutableProfileOAuth2TokenService::
    RevokeServerRefreshToken::RevokeServerRefreshToken(
    MutableProfileOAuth2TokenService* token_service,
    const std::string& refresh_token)
    : token_service_(token_service),
      fetcher_(this, GaiaConstants::kChromeSource,
               token_service_->GetRequestContext()) {
  fetcher_.StartRevokeOAuth2Token(refresh_token);
}

MutableProfileOAuth2TokenService::
    RevokeServerRefreshToken::~RevokeServerRefreshToken() {}

void MutableProfileOAuth2TokenService::
    RevokeServerRefreshToken::OnOAuth2RevokeTokenCompleted() {
  // |this| pointer will be deleted when removed from the vector, so don't
  // access any members after call to erase().
  token_service_->server_revokes_.erase(
      std::find(token_service_->server_revokes_.begin(),
                token_service_->server_revokes_.end(),
                this));
}

MutableProfileOAuth2TokenService::AccountInfo::AccountInfo(
    SigninErrorController* signin_error_controller,
    const std::string& account_id,
    const std::string& refresh_token)
  : signin_error_controller_(signin_error_controller),
    account_id_(account_id),
    refresh_token_(refresh_token),
    last_auth_error_(GoogleServiceAuthError::NONE) {
  DCHECK(signin_error_controller_);
  DCHECK(!account_id_.empty());
  signin_error_controller_->AddProvider(this);
}

MutableProfileOAuth2TokenService::AccountInfo::~AccountInfo() {
  signin_error_controller_->RemoveProvider(this);
}

void MutableProfileOAuth2TokenService::AccountInfo::SetLastAuthError(
    const GoogleServiceAuthError& error) {
  if (error.state() != last_auth_error_.state()) {
    last_auth_error_ = error;
    signin_error_controller_->AuthStatusChanged();
  }
}

std::string
MutableProfileOAuth2TokenService::AccountInfo::GetAccountId() const {
  return account_id_;
}

std::string
MutableProfileOAuth2TokenService::AccountInfo::GetUsername() const {
  // TODO(rogerta): when |account_id| becomes the obfuscated gaia id, this
  // will need to be changed.
  return account_id_;
}

GoogleServiceAuthError
MutableProfileOAuth2TokenService::AccountInfo::GetAuthStatus() const {
  return last_auth_error_;
}

MutableProfileOAuth2TokenService::MutableProfileOAuth2TokenService()
    : web_data_service_request_(0)  {
}

MutableProfileOAuth2TokenService::~MutableProfileOAuth2TokenService() {
  DCHECK(server_revokes_.empty());
}

void MutableProfileOAuth2TokenService::Shutdown() {
  server_revokes_.clear();
  CancelWebTokenFetch();
  CancelAllRequests();
  refresh_tokens_.clear();

  ProfileOAuth2TokenService::Shutdown();
}

bool MutableProfileOAuth2TokenService::RefreshTokenIsAvailable(
    const std::string& account_id) const {
  return !GetRefreshToken(account_id).empty();
}

std::string MutableProfileOAuth2TokenService::GetRefreshToken(
    const std::string& account_id) const {
  AccountInfoMap::const_iterator iter = refresh_tokens_.find(account_id);
  if (iter != refresh_tokens_.end())
    return iter->second->refresh_token();
  return std::string();
}

OAuth2AccessTokenFetcher*
MutableProfileOAuth2TokenService::CreateAccessTokenFetcher(
    const std::string& account_id,
    net::URLRequestContextGetter* getter,
    OAuth2AccessTokenConsumer* consumer) {
  ValidateAccountId(account_id);
  std::string refresh_token = GetRefreshToken(account_id);
  DCHECK(!refresh_token.empty());
  return new OAuth2AccessTokenFetcherImpl(consumer, getter, refresh_token);
}

net::URLRequestContextGetter*
MutableProfileOAuth2TokenService::GetRequestContext() {
  return client()->GetURLRequestContext();
}

void MutableProfileOAuth2TokenService::LoadCredentials(
    const std::string& primary_account_id) {
  DCHECK(!primary_account_id.empty());
  ValidateAccountId(primary_account_id);
  DCHECK(loading_primary_account_id_.empty());
  DCHECK_EQ(0, web_data_service_request_);

  CancelAllRequests();
  refresh_tokens().clear();
  loading_primary_account_id_ = primary_account_id;
  scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
  if (token_web_data.get())
    web_data_service_request_ = token_web_data->GetAllTokens(this);
}

void MutableProfileOAuth2TokenService::OnWebDataServiceRequestDone(
    WebDataServiceBase::Handle handle,
    const WDTypedResult* result) {
  DCHECK_EQ(web_data_service_request_, handle);
  web_data_service_request_ = 0;

  if (result) {
    DCHECK(result->GetType() == TOKEN_RESULT);
    const WDResult<std::map<std::string, std::string> > * token_result =
        static_cast<const WDResult<std::map<std::string, std::string> > * > (
            result);
    LoadAllCredentialsIntoMemory(token_result->GetValue());
  }

  // Make sure that we have an entry for |loading_primary_account_id_| in the
  // map.  The entry could be missing if there is a corruption in the token DB
  // while this profile is connected to an account.
  DCHECK(!loading_primary_account_id_.empty());
  if (refresh_tokens().count(loading_primary_account_id_) == 0) {
    refresh_tokens()[loading_primary_account_id_].reset(
        new AccountInfo(signin_error_controller(),
                        loading_primary_account_id_,
                        std::string()));
  }

  // If we don't have a refresh token for a known account, signal an error.
  for (AccountInfoMap::const_iterator i = refresh_tokens_.begin();
       i != refresh_tokens_.end(); ++i) {
    if (!RefreshTokenIsAvailable(i->first)) {
      UpdateAuthError(
          i->first,
          GoogleServiceAuthError(
              GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
      break;
    }
  }

  loading_primary_account_id_.clear();
}

void MutableProfileOAuth2TokenService::LoadAllCredentialsIntoMemory(
    const std::map<std::string, std::string>& db_tokens) {
  std::string old_login_token;

  {
    ScopedBatchChange batch(this);

    for (std::map<std::string, std::string>::const_iterator iter =
             db_tokens.begin();
         iter != db_tokens.end();
         ++iter) {
      std::string prefixed_account_id = iter->first;
      std::string refresh_token = iter->second;

      if (IsLegacyRefreshTokenId(prefixed_account_id) && !refresh_token.empty())
        old_login_token = refresh_token;

      if (IsLegacyServiceId(prefixed_account_id)) {
        scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
        if (token_web_data.get())
          token_web_data->RemoveTokenForService(prefixed_account_id);
      } else {
        DCHECK(!refresh_token.empty());
        std::string account_id = RemoveAccountIdPrefix(prefixed_account_id);

        // If the account_id is an email address, then canonicalize it.  This
        // is to support legacy account_ids, and will not be needed after
        // switching to gaia-ids.
        if (account_id.find('@') != std::string::npos)
          account_id = gaia::CanonicalizeEmail(account_id);

        refresh_tokens()[account_id].reset(
            new AccountInfo(signin_error_controller(),
                            account_id,
                            refresh_token));
        FireRefreshTokenAvailable(account_id);
      }
    }

    if (!old_login_token.empty()) {
      DCHECK(!loading_primary_account_id_.empty());
      if (refresh_tokens().count(loading_primary_account_id_) == 0)
        UpdateCredentials(loading_primary_account_id_, old_login_token);
    }
  }

  FireRefreshTokensLoaded();
}

void MutableProfileOAuth2TokenService::UpdateAuthError(
    const std::string& account_id,
    const GoogleServiceAuthError& error) {
  ValidateAccountId(account_id);

  // Do not report connection errors as these are not actually auth errors.
  // We also want to avoid masking a "real" auth error just because we
  // subsequently get a transient network error.
  if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
      error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE)
    return;

  if (refresh_tokens_.count(account_id) == 0) {
    // This could happen if the preferences have been corrupted (see
    // http://crbug.com/321370). In a Debug build that would be a bug, but in a
    // Release build we want to deal with it gracefully.
    NOTREACHED();
    return;
  }
  refresh_tokens_[account_id]->SetLastAuthError(error);
}

std::vector<std::string> MutableProfileOAuth2TokenService::GetAccounts() {
  std::vector<std::string> account_ids;
  for (AccountInfoMap::const_iterator iter = refresh_tokens_.begin();
           iter != refresh_tokens_.end(); ++iter) {
    account_ids.push_back(iter->first);
  }
  return account_ids;
}

void MutableProfileOAuth2TokenService::UpdateCredentials(
    const std::string& account_id,
    const std::string& refresh_token) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(!account_id.empty());
  DCHECK(!refresh_token.empty());
  ValidateAccountId(account_id);

  signin_metrics::LogSigninAddAccount();

  bool refresh_token_present = refresh_tokens_.count(account_id) > 0;
  if (!refresh_token_present ||
      refresh_tokens_[account_id]->refresh_token() != refresh_token) {
    ScopedBatchChange batch(this);

    // If token present, and different from the new one, cancel its requests,
    // and clear the entries in cache related to that account.
    if (refresh_token_present) {
      std::string revoke_reason = refresh_token_present ? "token differs" :
                                                          "token is missing";
      LOG(WARNING) << "Revoking refresh token on server. "
                   << "Reason: token update, " << revoke_reason;
      RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
      CancelRequestsForAccount(account_id);
      ClearCacheForAccount(account_id);
      refresh_tokens_[account_id]->set_refresh_token(refresh_token);
    } else {
      refresh_tokens_[account_id].reset(
          new AccountInfo(signin_error_controller(),
                          account_id,
                          refresh_token));
    }

    // Save the token in memory and in persistent store.
    PersistCredentials(account_id, refresh_token);

    UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
    FireRefreshTokenAvailable(account_id);
  }
}

void MutableProfileOAuth2TokenService::RevokeCredentials(
    const std::string& account_id) {
  ValidateAccountId(account_id);
  DCHECK(thread_checker_.CalledOnValidThread());

  if (refresh_tokens_.count(account_id) > 0) {
    ScopedBatchChange batch(this);
    RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
    CancelRequestsForAccount(account_id);
    ClearCacheForAccount(account_id);
    refresh_tokens_.erase(account_id);
    ClearPersistedCredentials(account_id);
    FireRefreshTokenRevoked(account_id);
  }
}

void MutableProfileOAuth2TokenService::PersistCredentials(
    const std::string& account_id,
    const std::string& refresh_token) {
  scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
  if (token_web_data.get()) {
    token_web_data->SetTokenForService(ApplyAccountIdPrefix(account_id),
                                       refresh_token);
  }
}

void MutableProfileOAuth2TokenService::ClearPersistedCredentials(
    const std::string& account_id) {
  scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
  if (token_web_data.get())
    token_web_data->RemoveTokenForService(ApplyAccountIdPrefix(account_id));
}

void MutableProfileOAuth2TokenService::RevokeAllCredentials() {
  if (!client()->CanRevokeCredentials())
    return;
  DCHECK(thread_checker_.CalledOnValidThread());

  ScopedBatchChange batch(this);

  CancelWebTokenFetch();
  CancelAllRequests();
  ClearCache();
  AccountInfoMap tokens = refresh_tokens_;
  for (AccountInfoMap::iterator i = tokens.begin(); i != tokens.end(); ++i)
    RevokeCredentials(i->first);

  DCHECK_EQ(0u, refresh_tokens_.size());
}

void MutableProfileOAuth2TokenService::RevokeCredentialsOnServer(
    const std::string& refresh_token) {
  // Keep track or all server revoke requests.  This way they can be deleted
  // before the token service is shutdown and won't outlive the profile.
  server_revokes_.push_back(
      new RevokeServerRefreshToken(this, refresh_token));
}

void MutableProfileOAuth2TokenService::CancelWebTokenFetch() {
  if (web_data_service_request_ != 0) {
    scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
    DCHECK(token_web_data.get());
    token_web_data->CancelRequest(web_data_service_request_);
    web_data_service_request_  = 0;
  }
}
<commit_msg>Instrument the MutablePO2TS.<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"

#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "components/signin/core/browser/webdata/token_web_data.h"
#include "components/webdata/common/web_data_service_base.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
#include "net/url_request/url_request_context_getter.h"

namespace {

const char kAccountIdPrefix[] = "AccountId-";
const size_t kAccountIdPrefixLength = 10;

std::string ApplyAccountIdPrefix(const std::string& account_id) {
  return kAccountIdPrefix + account_id;
}

bool IsLegacyRefreshTokenId(const std::string& service_id) {
  return service_id == GaiaConstants::kGaiaOAuth2LoginRefreshToken;
}

bool IsLegacyServiceId(const std::string& account_id) {
  return account_id.compare(0u, kAccountIdPrefixLength, kAccountIdPrefix) != 0;
}

std::string RemoveAccountIdPrefix(const std::string& prefixed_account_id) {
  return prefixed_account_id.substr(kAccountIdPrefixLength);
}

}  // namespace

// This class sends a request to GAIA to revoke the given refresh token from
// the server.  This is a best effort attempt only.  This class deletes itself
// when done sucessfully or otherwise.
class MutableProfileOAuth2TokenService::RevokeServerRefreshToken
    : public GaiaAuthConsumer {
 public:
  RevokeServerRefreshToken(MutableProfileOAuth2TokenService* token_service,
                           const std::string& account_id);
  ~RevokeServerRefreshToken() override;

 private:
  // GaiaAuthConsumer overrides:
  void OnOAuth2RevokeTokenCompleted() override;

  MutableProfileOAuth2TokenService* token_service_;
  GaiaAuthFetcher fetcher_;

  DISALLOW_COPY_AND_ASSIGN(RevokeServerRefreshToken);
};

MutableProfileOAuth2TokenService::
    RevokeServerRefreshToken::RevokeServerRefreshToken(
    MutableProfileOAuth2TokenService* token_service,
    const std::string& refresh_token)
    : token_service_(token_service),
      fetcher_(this, GaiaConstants::kChromeSource,
               token_service_->GetRequestContext()) {
  fetcher_.StartRevokeOAuth2Token(refresh_token);
}

MutableProfileOAuth2TokenService::
    RevokeServerRefreshToken::~RevokeServerRefreshToken() {}

void MutableProfileOAuth2TokenService::
    RevokeServerRefreshToken::OnOAuth2RevokeTokenCompleted() {
  // |this| pointer will be deleted when removed from the vector, so don't
  // access any members after call to erase().
  token_service_->server_revokes_.erase(
      std::find(token_service_->server_revokes_.begin(),
                token_service_->server_revokes_.end(),
                this));
}

MutableProfileOAuth2TokenService::AccountInfo::AccountInfo(
    SigninErrorController* signin_error_controller,
    const std::string& account_id,
    const std::string& refresh_token)
  : signin_error_controller_(signin_error_controller),
    account_id_(account_id),
    refresh_token_(refresh_token),
    last_auth_error_(GoogleServiceAuthError::NONE) {
  DCHECK(signin_error_controller_);
  DCHECK(!account_id_.empty());
  signin_error_controller_->AddProvider(this);
}

MutableProfileOAuth2TokenService::AccountInfo::~AccountInfo() {
  signin_error_controller_->RemoveProvider(this);
}

void MutableProfileOAuth2TokenService::AccountInfo::SetLastAuthError(
    const GoogleServiceAuthError& error) {
  if (error.state() != last_auth_error_.state()) {
    last_auth_error_ = error;
    signin_error_controller_->AuthStatusChanged();
  }
}

std::string
MutableProfileOAuth2TokenService::AccountInfo::GetAccountId() const {
  return account_id_;
}

std::string
MutableProfileOAuth2TokenService::AccountInfo::GetUsername() const {
  // TODO(rogerta): when |account_id| becomes the obfuscated gaia id, this
  // will need to be changed.
  return account_id_;
}

GoogleServiceAuthError
MutableProfileOAuth2TokenService::AccountInfo::GetAuthStatus() const {
  return last_auth_error_;
}

MutableProfileOAuth2TokenService::MutableProfileOAuth2TokenService()
    : web_data_service_request_(0)  {
  VLOG(1) << "MutablePO2TS::MutablePO2TS";
}

MutableProfileOAuth2TokenService::~MutableProfileOAuth2TokenService() {
  VLOG(1) << "MutablePO2TS::~MutablePO2TS";
  DCHECK(server_revokes_.empty());
}

void MutableProfileOAuth2TokenService::Shutdown() {
  VLOG(1) << "MutablePO2TS::Shutdown";
  server_revokes_.clear();
  CancelWebTokenFetch();
  CancelAllRequests();
  refresh_tokens_.clear();

  ProfileOAuth2TokenService::Shutdown();
}

bool MutableProfileOAuth2TokenService::RefreshTokenIsAvailable(
    const std::string& account_id) const {
  return !GetRefreshToken(account_id).empty();
}

std::string MutableProfileOAuth2TokenService::GetRefreshToken(
    const std::string& account_id) const {
  AccountInfoMap::const_iterator iter = refresh_tokens_.find(account_id);
  if (iter != refresh_tokens_.end())
    return iter->second->refresh_token();
  return std::string();
}

OAuth2AccessTokenFetcher*
MutableProfileOAuth2TokenService::CreateAccessTokenFetcher(
    const std::string& account_id,
    net::URLRequestContextGetter* getter,
    OAuth2AccessTokenConsumer* consumer) {
  ValidateAccountId(account_id);
  std::string refresh_token = GetRefreshToken(account_id);
  DCHECK(!refresh_token.empty());
  return new OAuth2AccessTokenFetcherImpl(consumer, getter, refresh_token);
}

net::URLRequestContextGetter*
MutableProfileOAuth2TokenService::GetRequestContext() {
  return client()->GetURLRequestContext();
}

void MutableProfileOAuth2TokenService::LoadCredentials(
    const std::string& primary_account_id) {
  DCHECK(!primary_account_id.empty());
  ValidateAccountId(primary_account_id);
  DCHECK(loading_primary_account_id_.empty());
  DCHECK_EQ(0, web_data_service_request_);

  CancelAllRequests();
  refresh_tokens().clear();
  loading_primary_account_id_ = primary_account_id;
  scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
  if (token_web_data.get())
    web_data_service_request_ = token_web_data->GetAllTokens(this);
}

void MutableProfileOAuth2TokenService::OnWebDataServiceRequestDone(
    WebDataServiceBase::Handle handle,
    const WDTypedResult* result) {
  VLOG(1) << "MutablePO2TS::OnWebDataServiceRequestDone. Result type: "
          << (result == nullptr ? -1 : (int)result->GetType());
  DCHECK_EQ(web_data_service_request_, handle);
  web_data_service_request_ = 0;

  if (result) {
    DCHECK(result->GetType() == TOKEN_RESULT);
    const WDResult<std::map<std::string, std::string> > * token_result =
        static_cast<const WDResult<std::map<std::string, std::string> > * > (
            result);
    LoadAllCredentialsIntoMemory(token_result->GetValue());
  }

  // Make sure that we have an entry for |loading_primary_account_id_| in the
  // map.  The entry could be missing if there is a corruption in the token DB
  // while this profile is connected to an account.
  DCHECK(!loading_primary_account_id_.empty());
  if (refresh_tokens().count(loading_primary_account_id_) == 0) {
    refresh_tokens()[loading_primary_account_id_].reset(
        new AccountInfo(signin_error_controller(),
                        loading_primary_account_id_,
                        std::string()));
  }

  // If we don't have a refresh token for a known account, signal an error.
  for (AccountInfoMap::const_iterator i = refresh_tokens_.begin();
       i != refresh_tokens_.end(); ++i) {
    if (!RefreshTokenIsAvailable(i->first)) {
      UpdateAuthError(
          i->first,
          GoogleServiceAuthError(
              GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
      break;
    }
  }

  loading_primary_account_id_.clear();
}

void MutableProfileOAuth2TokenService::LoadAllCredentialsIntoMemory(
    const std::map<std::string, std::string>& db_tokens) {
  std::string old_login_token;

  {
    ScopedBatchChange batch(this);

    VLOG(1) << "MutablePO2TS::LoadAllCredentialsIntoMemory; "
            << db_tokens.size() << " Credential(s).";
    for (std::map<std::string, std::string>::const_iterator iter =
             db_tokens.begin();
         iter != db_tokens.end();
         ++iter) {
      std::string prefixed_account_id = iter->first;
      std::string refresh_token = iter->second;

      if (IsLegacyRefreshTokenId(prefixed_account_id) && !refresh_token.empty())
        old_login_token = refresh_token;

      if (IsLegacyServiceId(prefixed_account_id)) {
        scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
        if (token_web_data.get())
          token_web_data->RemoveTokenForService(prefixed_account_id);
      } else {
        DCHECK(!refresh_token.empty());
        std::string account_id = RemoveAccountIdPrefix(prefixed_account_id);

        // If the account_id is an email address, then canonicalize it.  This
        // is to support legacy account_ids, and will not be needed after
        // switching to gaia-ids.
        if (account_id.find('@') != std::string::npos)
          account_id = gaia::CanonicalizeEmail(account_id);

        refresh_tokens()[account_id].reset(
            new AccountInfo(signin_error_controller(),
                            account_id,
                            refresh_token));
        FireRefreshTokenAvailable(account_id);
      }
    }

    if (!old_login_token.empty()) {
      DCHECK(!loading_primary_account_id_.empty());
      if (refresh_tokens().count(loading_primary_account_id_) == 0)
        UpdateCredentials(loading_primary_account_id_, old_login_token);
    }
  }

  FireRefreshTokensLoaded();
}

void MutableProfileOAuth2TokenService::UpdateAuthError(
    const std::string& account_id,
    const GoogleServiceAuthError& error) {
  VLOG(1) << "MutablePO2TS::UpdateAuthError. Error: " << error.state();
  ValidateAccountId(account_id);

  // Do not report connection errors as these are not actually auth errors.
  // We also want to avoid masking a "real" auth error just because we
  // subsequently get a transient network error.
  if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
      error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE)
    return;

  if (refresh_tokens_.count(account_id) == 0) {
    // This could happen if the preferences have been corrupted (see
    // http://crbug.com/321370). In a Debug build that would be a bug, but in a
    // Release build we want to deal with it gracefully.
    NOTREACHED();
    return;
  }
  refresh_tokens_[account_id]->SetLastAuthError(error);
}

std::vector<std::string> MutableProfileOAuth2TokenService::GetAccounts() {
  std::vector<std::string> account_ids;
  for (AccountInfoMap::const_iterator iter = refresh_tokens_.begin();
           iter != refresh_tokens_.end(); ++iter) {
    account_ids.push_back(iter->first);
  }
  return account_ids;
}

void MutableProfileOAuth2TokenService::UpdateCredentials(
    const std::string& account_id,
    const std::string& refresh_token) {
  DCHECK(thread_checker_.CalledOnValidThread());
  DCHECK(!account_id.empty());
  DCHECK(!refresh_token.empty());
  ValidateAccountId(account_id);

  signin_metrics::LogSigninAddAccount();

  bool refresh_token_present = refresh_tokens_.count(account_id) > 0;
  if (!refresh_token_present ||
      refresh_tokens_[account_id]->refresh_token() != refresh_token) {
    ScopedBatchChange batch(this);

    // If token present, and different from the new one, cancel its requests,
    // and clear the entries in cache related to that account.
    if (refresh_token_present) {
      VLOG(1) << "MutablePO2TS::UpdateCredentials; Refresh Token was present. "
              << "account_id=" << account_id;
      std::string revoke_reason = refresh_token_present ? "token differs" :
                                                          "token is missing";
      LOG(WARNING) << "Revoking refresh token on server. "
                   << "Reason: token update, " << revoke_reason;
      RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
      CancelRequestsForAccount(account_id);
      ClearCacheForAccount(account_id);
      refresh_tokens_[account_id]->set_refresh_token(refresh_token);
    } else {
      VLOG(1) << "MutablePO2TS::UpdateCredentials; Refresh Token was absent. "
              << "account_id=" << account_id;
      refresh_tokens_[account_id].reset(
          new AccountInfo(signin_error_controller(),
                          account_id,
                          refresh_token));
    }

    // Save the token in memory and in persistent store.
    PersistCredentials(account_id, refresh_token);

    UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
    FireRefreshTokenAvailable(account_id);
  }
}

void MutableProfileOAuth2TokenService::RevokeCredentials(
    const std::string& account_id) {
  ValidateAccountId(account_id);
  DCHECK(thread_checker_.CalledOnValidThread());

  if (refresh_tokens_.count(account_id) > 0) {
    VLOG(1) << "MutablePO2TS::RevokeCredentials for account_id=" << account_id;
    ScopedBatchChange batch(this);
    RevokeCredentialsOnServer(refresh_tokens_[account_id]->refresh_token());
    CancelRequestsForAccount(account_id);
    ClearCacheForAccount(account_id);
    refresh_tokens_.erase(account_id);
    ClearPersistedCredentials(account_id);
    FireRefreshTokenRevoked(account_id);
  }
}

void MutableProfileOAuth2TokenService::PersistCredentials(
    const std::string& account_id,
    const std::string& refresh_token) {
  scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
  if (token_web_data.get()) {
    VLOG(1) << "MutablePO2TS::PersistCredentials for account_id=" << account_id;
    token_web_data->SetTokenForService(ApplyAccountIdPrefix(account_id),
                                       refresh_token);
  }
}

void MutableProfileOAuth2TokenService::ClearPersistedCredentials(
    const std::string& account_id) {
  scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
  if (token_web_data.get()) {
    VLOG(1) << "MutablePO2TS::ClearPersistedCredentials for account_id="
            << account_id;
    token_web_data->RemoveTokenForService(ApplyAccountIdPrefix(account_id));
  }
}

void MutableProfileOAuth2TokenService::RevokeAllCredentials() {
  if (!client()->CanRevokeCredentials())
    return;
  DCHECK(thread_checker_.CalledOnValidThread());

  ScopedBatchChange batch(this);

  VLOG(1) << "MutablePO2TS::RevokeAllCredentials";
  CancelWebTokenFetch();
  CancelAllRequests();
  ClearCache();
  AccountInfoMap tokens = refresh_tokens_;
  for (AccountInfoMap::iterator i = tokens.begin(); i != tokens.end(); ++i)
    RevokeCredentials(i->first);

  DCHECK_EQ(0u, refresh_tokens_.size());
}

void MutableProfileOAuth2TokenService::RevokeCredentialsOnServer(
    const std::string& refresh_token) {
  // Keep track or all server revoke requests.  This way they can be deleted
  // before the token service is shutdown and won't outlive the profile.
  server_revokes_.push_back(
      new RevokeServerRefreshToken(this, refresh_token));
}

void MutableProfileOAuth2TokenService::CancelWebTokenFetch() {
  if (web_data_service_request_ != 0) {
    scoped_refptr<TokenWebData> token_web_data = client()->GetDatabase();
    DCHECK(token_web_data.get());
    token_web_data->CancelRequest(web_data_service_request_);
    web_data_service_request_  = 0;
  }
}
<|endoftext|>


<commit_before>#include "smooth_control.h"

void SmoothControl::getTrajectory(igvc_msgs::velocity_pair& vel, const nav_msgs::PathConstPtr& path,
                                  nav_msgs::Path& trajectory, const RobotState& start_pos, RobotState& target)
{
  RobotState state = start_pos;
  RobotState simulation_target;
  unsigned int path_index = 0;

  ros::Time time = path->header.stamp;

  // Store starting position in trajectory
  geometry_msgs::PoseStamped start;
  start.pose.position.x = start_pos.x;
  start.pose.position.y = start_pos.y;
  start.pose.orientation = start_pos.quat();
  start.header.stamp = time;
  trajectory.poses.emplace_back(start);

  // Calculate timesteps
  static ros::Duration dt = ros::Duration(1 / simulation_frequency_);

  // Visualization
  nav_msgs::Path closest_point_path;
  nav_msgs::Path targets_path;

  closest_point_path.header = path->header;
  targets_path.header = path->header;
  for (int i = 0; i < simulation_horizon_ * simulation_frequency_ && path_index < path->poses.size() - 1; i++)
  {
    // Get target
    path_index = getClosestPosition(path, state);

    simulation_target = getTargetPosition(path, path_index, state);

    // Calculate control using Control Law
    Action action = getAction(state, simulation_target);
    action.dt = dt.toSec();

    if (i == 0)
    {
      target = simulation_target;
      getWheelVelocities(vel, action);
    }

    propogateState(action, state);
    time += dt;

    // For Visualization
    geometry_msgs::PoseStamped pose;
    pose.header = path->header;
    pose.pose.position.x = path->poses[path_index].pose.position.x;
    pose.pose.position.y = path->poses[path_index].pose.position.y;
    pose.pose.orientation = path->poses[path_index].pose.orientation;
    closest_point_path.poses.emplace_back(pose);

    pose.pose.position.x = simulation_target.x;
    pose.pose.position.y = simulation_target.y;
    pose.pose.orientation = simulation_target.quat();
    targets_path.poses.emplace_back(pose);

    pose.pose.position.x = state.x;
    pose.pose.position.y = state.y;
    pose.pose.orientation = state.quat();
    pose.header.stamp = start.header.stamp;
    trajectory.poses.emplace_back(pose);
  }
  target_pub_.publish(targets_path);
  closest_point_pub_.publish(closest_point_path);
}

void SmoothControl::propogateState(const Action& action, RobotState& state)
{
  double v = action.v;
  double w = action.w;
  double dt = action.dt;

  // pose after applying action to current pose
  Eigen::Vector3d resultant_pose;

  if (std::abs(w) > 1e-10)
  {
    // calculate instantaneous center of curvature (ICC = [ICCx, ICCy])
    double R = v / w;
    double ICCx = state.x - (R * sin(state.yaw));
    double ICCy = state.y + (R * cos(state.yaw));

    using namespace Eigen;
    Matrix3d T;
    double wdt = w * dt;
    T << cos(wdt), -sin(wdt), 0, sin(wdt), cos(wdt), 0, 0, 0, 1;
    Vector3d a(state.x - ICCx, state.y - ICCy, state.yaw);
    Vector3d b = T * a;
    Vector3d c = b + Vector3d(ICCx, ICCy, wdt);
    igvc::fit_to_polar(c[2]);

    resultant_pose << c[0], c[1], c[2];
  }
  else
  {
    resultant_pose << state.x + (cos(state.yaw * v * dt)), state.y + (sin(state.yaw) * v * dt), state.yaw;
  }

  state.setState(resultant_pose);
}

Action SmoothControl::getAction(const RobotState& state, const RobotState& target)
{
  double line_of_sight = atan2(target.y - state.y, target.x - state.x);

  double delta = state.yaw - line_of_sight;
  double theta = target.yaw - line_of_sight;

  // adjust both angles to lie between -PI and PI
  igvc::fit_to_polar(delta);
  igvc::fit_to_polar(theta);

  // calculate the radius of curvature, K
  double d = state.distTo(target);  // euclidian distance to target
  double K = k2_ * (delta - atan(-k1_ * theta));
  K += (1 + (k1_ / (1 + pow(k1_ * theta, 2)))) * sin(delta);
  K /= -d;

  // calculate angular velocity using radius of curvature and target velocity
  double w = K * target_velocity_;
  return Action{ target_velocity_, w, 0 };
}

RobotState SmoothControl::getTargetPosition(const nav_msgs::PathConstPtr& path, unsigned int path_index,
                                            const RobotState& state) const
{
  // target position
  double tar_x;
  double tar_y;
  double tar_yaw = 1.57;

  geometry_msgs::Point end = path->poses[path->poses.size() - 1].pose.position;

  double distance = 0;

  for (; path_index < path->poses.size() - 1; path_index++)
  {
    geometry_msgs::Point point1, point2;
    point1 = path->poses[path_index].pose.position;
    point2 = path->poses[path_index + 1].pose.position;
    double increment = igvc::get_distance(point1.x, point1.y, point2.x, point2.y);

    if (distance + increment > lookahead_dist_)
    {
      Eigen::Vector3d first(point1.x, point1.y, 0);
      Eigen::Vector3d second(point2.x, point2.y, 0);
      Eigen::Vector3d slope = (second - first) / increment;

      slope *= (lookahead_dist_ - distance);

      tar_x = first[0] + slope[0];
      tar_y = first[1] + slope[1];
      tar_yaw = tf::getYaw(path->poses[path_index].pose.orientation);
      if (tar_yaw == 0)
      {
        ROS_ERROR("WHYYYYY");
      }
      return RobotState{ tar_x, tar_y, tar_yaw };
    }
    distance += increment;
  }
  tar_x = end.x;
  tar_y = end.y;

  return RobotState{ tar_x, tar_y, tf::getYaw(path->poses[path->poses.size() - 2].pose.orientation) };
}

unsigned int SmoothControl::getClosestPosition(const nav_msgs::PathConstPtr& path, const RobotState& state) const
{
  double closest = state.distTo(path->poses[0].pose.position.x, path->poses[0].pose.position.y);

  for (unsigned int path_index = 0; path_index < path->poses.size(); path_index++)
  {
    double cur_dist = state.distTo(path->poses[path_index].pose.position.x, path->poses[path_index].pose.position.y);
    if (cur_dist <= closest)
    {
      closest = cur_dist;
    }
    else  // Derivative < 0, found maximum
    {
      return path_index;
    }
  }
}

void SmoothControl::getWheelVelocities(igvc_msgs::velocity_pair& vel_msg, const Action& action) const
{
  vel_msg.left_velocity = action.v - action.w * axle_length_ / 2;
  vel_msg.right_velocity = action.v + action.w * axle_length_ / 2;
}

SmoothControl::SmoothControl(double k1, double k2, double axle_length, double simulation_frequency,
                             double target_velocity, double lookahead_dist, double simulation_horizon)
  : k1_{ k1 }
  , k2_{ k2 }
  , axle_length_{ axle_length }
  , simulation_frequency_{ simulation_frequency }
  , target_velocity_{ target_velocity }
  , lookahead_dist_{ lookahead_dist }
  , simulation_horizon_{ simulation_horizon }
{
  ros::NodeHandle pNh{ "~" };
  target_pub_ = pNh.advertise<nav_msgs::Path>("smooth_control/target", 1);
  closest_point_pub_ = pNh.advertise<nav_msgs::Path>("smooth_control/why2", 1);
}
<commit_msg>Removed debugging statement<commit_after>#include "smooth_control.h"

void SmoothControl::getTrajectory(igvc_msgs::velocity_pair& vel, const nav_msgs::PathConstPtr& path,
                                  nav_msgs::Path& trajectory, const RobotState& start_pos, RobotState& target)
{
  RobotState state = start_pos;
  RobotState simulation_target;
  unsigned int path_index = 0;

  ros::Time time = path->header.stamp;

  // Store starting position in trajectory
  geometry_msgs::PoseStamped start;
  start.pose.position.x = start_pos.x;
  start.pose.position.y = start_pos.y;
  start.pose.orientation = start_pos.quat();
  start.header.stamp = time;
  trajectory.poses.emplace_back(start);

  // Calculate timesteps
  static ros::Duration dt = ros::Duration(1 / simulation_frequency_);

  // Visualization
  nav_msgs::Path closest_point_path;
  nav_msgs::Path targets_path;

  closest_point_path.header = path->header;
  targets_path.header = path->header;
  for (int i = 0; i < simulation_horizon_ * simulation_frequency_ && path_index < path->poses.size() - 1; i++)
  {
    // Get target
    path_index = getClosestPosition(path, state);

    simulation_target = getTargetPosition(path, path_index, state);

    // Calculate control using Control Law
    Action action = getAction(state, simulation_target);
    action.dt = dt.toSec();

    if (i == 0)
    {
      target = simulation_target;
      getWheelVelocities(vel, action);
    }

    propogateState(action, state);
    time += dt;

    // For Visualization
    geometry_msgs::PoseStamped pose;
    pose.header = path->header;
    pose.pose.position.x = path->poses[path_index].pose.position.x;
    pose.pose.position.y = path->poses[path_index].pose.position.y;
    pose.pose.orientation = path->poses[path_index].pose.orientation;
    closest_point_path.poses.emplace_back(pose);

    pose.pose.position.x = simulation_target.x;
    pose.pose.position.y = simulation_target.y;
    pose.pose.orientation = simulation_target.quat();
    targets_path.poses.emplace_back(pose);

    pose.pose.position.x = state.x;
    pose.pose.position.y = state.y;
    pose.pose.orientation = state.quat();
    pose.header.stamp = start.header.stamp;
    trajectory.poses.emplace_back(pose);
  }
  target_pub_.publish(targets_path);
  closest_point_pub_.publish(closest_point_path);
}

void SmoothControl::propogateState(const Action& action, RobotState& state)
{
  double v = action.v;
  double w = action.w;
  double dt = action.dt;

  // pose after applying action to current pose
  Eigen::Vector3d resultant_pose;

  if (std::abs(w) > 1e-10)
  {
    // calculate instantaneous center of curvature (ICC = [ICCx, ICCy])
    double R = v / w;
    double ICCx = state.x - (R * sin(state.yaw));
    double ICCy = state.y + (R * cos(state.yaw));

    using namespace Eigen;
    Matrix3d T;
    double wdt = w * dt;
    T << cos(wdt), -sin(wdt), 0, sin(wdt), cos(wdt), 0, 0, 0, 1;
    Vector3d a(state.x - ICCx, state.y - ICCy, state.yaw);
    Vector3d b = T * a;
    Vector3d c = b + Vector3d(ICCx, ICCy, wdt);
    igvc::fit_to_polar(c[2]);

    resultant_pose << c[0], c[1], c[2];
  }
  else
  {
    resultant_pose << state.x + (cos(state.yaw * v * dt)), state.y + (sin(state.yaw) * v * dt), state.yaw;
  }

  state.setState(resultant_pose);
}

Action SmoothControl::getAction(const RobotState& state, const RobotState& target)
{
  double line_of_sight = atan2(target.y - state.y, target.x - state.x);

  double delta = state.yaw - line_of_sight;
  double theta = target.yaw - line_of_sight;

  // adjust both angles to lie between -PI and PI
  igvc::fit_to_polar(delta);
  igvc::fit_to_polar(theta);

  // calculate the radius of curvature, K
  double d = state.distTo(target);  // euclidian distance to target
  double K = k2_ * (delta - atan(-k1_ * theta));
  K += (1 + (k1_ / (1 + pow(k1_ * theta, 2)))) * sin(delta);
  K /= -d;

  // calculate angular velocity using radius of curvature and target velocity
  double w = K * target_velocity_;
  return Action{ target_velocity_, w, 0 };
}

RobotState SmoothControl::getTargetPosition(const nav_msgs::PathConstPtr& path, unsigned int path_index,
                                            const RobotState& state) const
{
  // target position
  double tar_x;
  double tar_y;
  double tar_yaw = 1.57;

  geometry_msgs::Point end = path->poses[path->poses.size() - 1].pose.position;

  double distance = 0;

  for (; path_index < path->poses.size() - 1; path_index++)
  {
    geometry_msgs::Point point1, point2;
    point1 = path->poses[path_index].pose.position;
    point2 = path->poses[path_index + 1].pose.position;
    double increment = igvc::get_distance(point1.x, point1.y, point2.x, point2.y);

    if (distance + increment > lookahead_dist_)
    {
      Eigen::Vector3d first(point1.x, point1.y, 0);
      Eigen::Vector3d second(point2.x, point2.y, 0);
      Eigen::Vector3d slope = (second - first) / increment;

      slope *= (lookahead_dist_ - distance);

      tar_x = first[0] + slope[0];
      tar_y = first[1] + slope[1];
      tar_yaw = tf::getYaw(path->poses[path_index].pose.orientation);
      return RobotState{ tar_x, tar_y, tar_yaw };
    }
    distance += increment;
  }
  tar_x = end.x;
  tar_y = end.y;

  return RobotState{ tar_x, tar_y, tf::getYaw(path->poses[path->poses.size() - 2].pose.orientation) };
}

unsigned int SmoothControl::getClosestPosition(const nav_msgs::PathConstPtr& path, const RobotState& state) const
{
  double closest = state.distTo(path->poses[0].pose.position.x, path->poses[0].pose.position.y);

  for (unsigned int path_index = 0; path_index < path->poses.size(); path_index++)
  {
    double cur_dist = state.distTo(path->poses[path_index].pose.position.x, path->poses[path_index].pose.position.y);
    if (cur_dist <= closest)
    {
      closest = cur_dist;
    }
    else  // Derivative < 0, found maximum
    {
      return path_index;
    }
  }
}

void SmoothControl::getWheelVelocities(igvc_msgs::velocity_pair& vel_msg, const Action& action) const
{
  vel_msg.left_velocity = action.v - action.w * axle_length_ / 2;
  vel_msg.right_velocity = action.v + action.w * axle_length_ / 2;
}

SmoothControl::SmoothControl(double k1, double k2, double axle_length, double simulation_frequency,
                             double target_velocity, double lookahead_dist, double simulation_horizon)
  : k1_{ k1 }
  , k2_{ k2 }
  , axle_length_{ axle_length }
  , simulation_frequency_{ simulation_frequency }
  , target_velocity_{ target_velocity }
  , lookahead_dist_{ lookahead_dist }
  , simulation_horizon_{ simulation_horizon }
{
  ros::NodeHandle pNh{ "~" };
  target_pub_ = pNh.advertise<nav_msgs::Path>("smooth_control/target", 1);
  closest_point_pub_ = pNh.advertise<nav_msgs::Path>("smooth_control/closest_point", 1);
}
<|endoftext|>


<commit_before>//============================================================================
// Name        : ObjectDetectionService.cpp
// Author      : ITM13
// Version     : 1.0
// Copyright   : Copyright (c) 2014 Swank Rat, MIT License (MIT)
// Description :
//============================================================================

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>

#include "ObjectDetectionService.h"

using namespace cv;
using namespace std;

RNG rng(12345);

ObjectDetectionService::ObjectDetectionService()
{

}

ObjectDetectionService::~ObjectDetectionService()
{

}

void ObjectDetectionService::DetectObject(Mat src, int iLowH, int iLowS, int iLowV, int iHighH, int iHighS, int iHighV){

	Mat imgOriginal(src);
	Mat imgHSV;

	cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV); //Convert the captured frame from BGR to HSV

	Mat imgThresholded;

	inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded); //Threshold the image

	//morphological opening (removes small objects from the foreground)
	erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
	dilate(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));

	//morphological closing (removes small holes from the foreground)
	dilate(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
	erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));

	imshow("input", imgThresholded);
	waitKey();

	/// Convert image to gray and blur it
	cvtColor(src, src_gray, COLOR_BGR2GRAY);
	blur(src_gray, src_gray, Size(3, 3));

	ThreshCallback(0, 0, src, src_gray, thresh);
}

/**
* @function thresh_callback
*/
void ObjectDetectionService::ThreshCallback(int, void*, Mat src, Mat src_gray, int thresh)
{
	Mat canny_output;
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	/// Detect edges using canny
	Canny(src_gray, canny_output, thresh, thresh * 2, 3);
	/// Find contours
	findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	/// Draw contours
	Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3);
	for (size_t i = 0; i < contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawing, contours, (int)i, color, 2, 8, hierarchy, 0, Point());
	}

	/// Show in a window
	namedWindow("Contours", WINDOW_AUTOSIZE);
	imshow("Contours", drawing);
	waitKey();
}<commit_msg>conture of threshed img<commit_after>//============================================================================
// Name        : ObjectDetectionService.cpp
// Author      : ITM13
// Version     : 1.0
// Copyright   : Copyright (c) 2014 Swank Rat, MIT License (MIT)
// Description :
//============================================================================

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>

#include "ObjectDetectionService.h"

using namespace cv;
using namespace std;

RNG rng(12345);

ObjectDetectionService::ObjectDetectionService()
{

}

ObjectDetectionService::~ObjectDetectionService()
{

}

void ObjectDetectionService::DetectObject(Mat src, int iLowH, int iLowS, int iLowV, int iHighH, int iHighS, int iHighV){

	Mat imgOriginal(src);
	Mat imgHSV;

	cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV); //Convert the captured frame from BGR to HSV

	Mat imgThresholded;

	inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), imgThresholded); //Threshold the image

	//morphological opening (removes small objects from the foreground)
	erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
	dilate(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));

	//morphological closing (removes small holes from the foreground)
	dilate(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
	erode(imgThresholded, imgThresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));

	imshow("input", imgThresholded);
	waitKey();

	///// Convert image to gray and blur it
	//cvtColor(imgThresholded, src_gray, COLOR_BGR2GRAY);
	//blur(src_gray, src_gray, Size(3, 3));

	ThreshCallback(0, 0, src, imgThresholded, thresh);
}

/**
* @function thresh_callback
*/
void ObjectDetectionService::ThreshCallback(int, void*, Mat src, Mat src_gray, int thresh)
{
	Mat canny_output;
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	/// Detect edges using canny
	Canny(src_gray, canny_output, thresh, thresh * 2, 3);
	/// Find contours
	findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	/// Draw contours
	Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3);
	for (size_t i = 0; i < contours.size(); i++)
	{
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawing, contours, (int)i, color, 2, 8, hierarchy, 0, Point());
	}

	/// Show in a window
	namedWindow("Contours", WINDOW_AUTOSIZE);
	imshow("Contours", drawing);
	waitKey();
}<|endoftext|>


<commit_before>#pragma once

#include "blackhole/formatter.hpp"

#include <boost/optional/optional.hpp>
#include <boost/variant/variant.hpp>
#include <boost/algorithm/string.hpp>

namespace blackhole {
namespace detail {
namespace formatter {
namespace string {
namespace parser {

class error_t : public std::runtime_error {
    const std::size_t pos;
    const std::string inspect;

public:
    error_t(std::size_t pos, const std::string& pattern, const std::string& reason) :
        std::runtime_error("parser error: " + reason),
        pos(pos),
        inspect("parser error: " +  reason + "\n" +
            pattern + "\n" +
            std::string(pos, '~') + "^"
        )
    {}

    ~error_t() noexcept {}

    auto position() const noexcept -> std::size_t {
        return pos;
    }

    auto detail() const noexcept -> const std::string& {
        return inspect;
    }
};

class broken_t : public error_t {
public:
    broken_t(std::size_t pos, const std::string& pattern) :
        error_t(pos, pattern, "broken parser")
    {}
};

class exhausted_t : public error_t {
public:
    exhausted_t(std::size_t pos, const std::string& pattern) :
        error_t(pos, pattern, "exhausted state")
    {}
};

class illformed_t : public error_t {
public:
    illformed_t(std::size_t pos, const std::string& pattern) :
        error_t(pos, pattern, "illformed pattern")
    {}
};

class invalid_placeholder_t : public error_t {
public:
    invalid_placeholder_t(std::size_t pos, const std::string& pattern) :
        error_t(pos, pattern, "invalid placeholder name (only [a-zA-Z0-9_] allowed)")
    {}
};

}  // namespace parser

struct literal_t {
    std::string value;
};

struct placeholder_t {
    std::string name;
    std::string spec;
};

typedef boost::variant<
    literal_t,
    placeholder_t
> token_t;

class parser_t {
    enum state_t {
        /// Undetermined state.
        whatever,
        literal,
        placeholder,
        broken
    };

    const std::string pattern;

    std::string::const_iterator pos;
    state_t state;

public:
    explicit parser_t(std::string pattern) :
        pattern(std::move(pattern)),
        pos(this->pattern.begin()),
        state(whatever)
    {}

    auto begin() const -> std::string::const_iterator {
        return pattern.begin();
    }

    auto end() const noexcept -> std::string::const_iterator {
        return pattern.end();
    }

    auto next() -> boost::optional<token_t> {
        if (state == broken) {
            throw_<parser::broken_t>();
        }

        if (pos == end()) {
            return boost::none;
        }

       switch (state) {
        case whatever:
            return parse_whatever();
        case literal:
            return parse_literal();
        case placeholder:
            return parse_placeholder();
        case broken:
            throw_<parser::broken_t>();
        default:
            BOOST_ASSERT(false);
        }

        throw_<parser::broken_t>();
    }

private:
    auto parse_whatever() -> boost::optional<token_t> {
        if (starts_with(pos, end(), "{{")) {
            state = literal;
        } else if (starts_with(pos, end(), "{")) {
            pos += 1;
            state = placeholder;
        } else {
            state = literal;
        }

        return next();
    }

    auto parse_literal() -> token_t {
        literal_t literal;

        while (pos != end()) {
            if (starts_with(pos, end(), "{{") || starts_with(pos, end(), "}}")) {
                pos += 1;
            } else if (starts_with(pos, end(), "{")) {
                pos += 1;
                state = placeholder;
                return literal;
            } else if (starts_with(pos, end(), "}")) {
                throw_<parser::illformed_t>();
            }

            literal.value.push_back(*pos);
            ++pos;
        }

        return literal;
    }

    auto parse_placeholder() -> token_t {
        placeholder_t result;

        while (pos != end()) {
            const auto ch = *pos;

            if (std::isalpha(ch) || std::isdigit(ch) || ch == '_') {
                result.name.push_back(ch);
            } else {
                if (ch == ':') {
                    result.spec.push_back(ch);
                    ++pos;
                    return parse_spec(std::move(result));
                } else if (starts_with(pos, end(), "}")) {
                    pos += 1;
                    state = whatever;
                    return result;
                } else {
                    throw_<parser::invalid_placeholder_t>();
                }
            }

            pos++;
        }

        throw_<parser::illformed_t>();
    }

    auto parse_spec(placeholder_t placeholder) -> token_t {
        while (pos != end()) {
            const auto ch = *pos;

            // TODO: Here it's the right place to validate spec format, but now I don't have much
            // time to implement it.
            if (starts_with(pos, end(), "}")) {
                pos += 1;
                state = whatever;
                return placeholder;
            }

            placeholder.spec.push_back(ch);
            ++pos;
        }

        return placeholder;
    }

    template<class Exception, class... Args>
    __attribute__((noreturn)) auto throw_(Args&&... args) -> void {
        state = broken;
        throw Exception(std::distance(begin(), pos), std::string(begin(), end()),
            std::forward<Args>(args)...);
    }

    template<typename Iterator, class Range>
    static auto starts_with(Iterator first, Iterator last, const Range& range) -> bool {
        return boost::starts_with(boost::make_iterator_range(first, last), range);
    }
};

}  // namespace string
}  // namespace formatter
}  // namespace detail
}  // namespace blackhole
<commit_msg>style(format): make tiny style fix<commit_after>#pragma once

#include "blackhole/formatter.hpp"

#include <boost/optional/optional.hpp>
#include <boost/variant/variant.hpp>
#include <boost/algorithm/string.hpp>

namespace blackhole {
namespace detail {
namespace formatter {
namespace string {
namespace parser {

class error_t : public std::runtime_error {
    const std::size_t pos;
    const std::string inspect;

public:
    error_t(std::size_t pos, const std::string& pattern, const std::string& reason) :
        std::runtime_error("parser error: " + reason),
        pos(pos),
        inspect("parser error: " +  reason + "\n" +
            pattern + "\n" +
            std::string(pos, '~') + "^"
        )
    {}

    ~error_t() noexcept {}

    auto position() const noexcept -> std::size_t {
        return pos;
    }

    auto detail() const noexcept -> const std::string& {
        return inspect;
    }
};

class broken_t : public error_t {
public:
    broken_t(std::size_t pos, const std::string& pattern) :
        error_t(pos, pattern, "broken parser")
    {}
};

class exhausted_t : public error_t {
public:
    exhausted_t(std::size_t pos, const std::string& pattern) :
        error_t(pos, pattern, "exhausted state")
    {}
};

class illformed_t : public error_t {
public:
    illformed_t(std::size_t pos, const std::string& pattern) :
        error_t(pos, pattern, "illformed pattern")
    {}
};

class invalid_placeholder_t : public error_t {
public:
    invalid_placeholder_t(std::size_t pos, const std::string& pattern) :
        error_t(pos, pattern, "invalid placeholder name (only [a-zA-Z0-9_] allowed)")
    {}
};

}  // namespace parser

struct literal_t {
    std::string value;
};

struct placeholder_t {
    std::string name;
    std::string spec;
};

typedef boost::variant<
    literal_t,
    placeholder_t
> token_t;

class parser_t {
    enum state_t {
        /// Undetermined state.
        whatever,
        literal,
        placeholder,
        broken
    };

    const std::string pattern;

    std::string::const_iterator pos;
    state_t state;

public:
    explicit parser_t(std::string pattern) :
        pattern(std::move(pattern)),
        pos(this->pattern.begin()),
        state(whatever)
    {}

    auto begin() const -> std::string::const_iterator {
        return pattern.begin();
    }

    auto end() const noexcept -> std::string::const_iterator {
        return pattern.end();
    }

    auto next() -> boost::optional<token_t> {
        if (state == broken) {
            throw_<parser::broken_t>();
        }

        if (pos == end()) {
            return boost::none;
        }

       switch (state) {
        case whatever:
            return parse_whatever();
        case literal:
            return parse_literal();
        case placeholder:
            return parse_placeholder();
        case broken:
            throw_<parser::broken_t>();
        default:
            BOOST_ASSERT(false);
        }

        throw_<parser::broken_t>();
    }

private:
    auto parse_whatever() -> boost::optional<token_t> {
        if (starts_with(pos, end(), "{{")) {
            state = literal;
        } else if (starts_with(pos, end(), "{")) {
            pos += 1;
            state = placeholder;
        } else {
            state = literal;
        }

        return next();
    }

    auto parse_literal() -> token_t {
        literal_t literal;

        while (pos != end()) {
            if (starts_with(pos, end(), "{{") || starts_with(pos, end(), "}}")) {
                pos += 1;
            } else if (starts_with(pos, end(), "{")) {
                pos += 1;
                state = placeholder;
                return literal;
            } else if (starts_with(pos, end(), "}")) {
                throw_<parser::illformed_t>();
            }

            literal.value.push_back(*pos);
            ++pos;
        }

        return literal;
    }

    auto parse_placeholder() -> token_t {
        placeholder_t result;

        while (pos != end()) {
            const auto ch = *pos;

            if (std::isalpha(ch) || std::isdigit(ch) || ch == '_') {
                result.name.push_back(ch);
            } else {
                if (ch == ':') {
                    result.spec.push_back(ch);
                    ++pos;
                    return parse_spec(std::move(result));
                } else if (starts_with(pos, end(), "}")) {
                    pos += 1;
                    state = whatever;
                    return result;
                } else {
                    throw_<parser::invalid_placeholder_t>();
                }
            }

            pos++;
        }

        throw_<parser::illformed_t>();
    }

    auto parse_spec(placeholder_t placeholder) -> token_t {
        while (pos != end()) {
            const auto ch = *pos;

            // TODO: Here it's the right place to validate spec format, but now I don't have much
            // time to implement it.
            if (starts_with(pos, end(), "}")) {
                pos += 1;
                state = whatever;
                return placeholder;
            }

            placeholder.spec.push_back(ch);
            ++pos;
        }

        return placeholder;
    }

    template<class Exception, class... Args>
    __attribute__((noreturn)) auto throw_(Args&&... args) -> void {
        state = broken;
        throw Exception(std::distance(begin(), pos), pattern, std::forward<Args>(args)...);
    }

    template<typename Iterator, class Range>
    static auto starts_with(Iterator first, Iterator last, const Range& range) -> bool {
        return boost::starts_with(boost::make_iterator_range(first, last), range);
    }
};

}  // namespace string
}  // namespace formatter
}  // namespace detail
}  // namespace blackhole
<|endoftext|>


<commit_before>#pragma once

/**
 * Specialized fixpoint iterators for kill-gen problems.
 **/

//#include <crab/cfg/basic_block_traits.hpp>
#include <crab/analysis/graphs/sccg.hpp>
#include <crab/analysis/graphs/topo_order.hpp>
#include <crab/cfg/cfg_bgl.hpp>
#include <crab/domains/killgen_domain.hpp>
#include <crab/support/debug.hpp>
#include <crab/support/stats.hpp>

namespace crab {
namespace iterators {

// API for a kill-gen analysis operations
template <class CFG, class Dom> class killgen_operations_api {

public:
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using killgen_domain_t = Dom;

protected:
  CFG m_cfg;

public:
  killgen_operations_api(CFG cfg) : m_cfg(cfg) {}

  virtual ~killgen_operations_api() {}

  // whether forward or backward analysis
  virtual bool is_forward() = 0;

  // initial state
  virtual Dom entry() = 0;

  // (optional) initialization for the fixpoint
  virtual void init_fixpoint() = 0;

  // confluence operator
  virtual Dom merge(Dom, Dom) = 0;

  // analyze a basic block
  virtual Dom analyze(const basic_block_label_t &, Dom) = 0;

  // analysis name
  virtual std::string name() = 0;
};

// A simple fixpoint for a killgen analysis
template <class CFG, class AnalysisOps> class killgen_fixpoint_iterator {

public:
  using basic_block_t = typename CFG::basic_block_t;
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using killgen_domain_t = typename AnalysisOps::killgen_domain_t;
  using inv_map_t = std::unordered_map<basic_block_label_t, killgen_domain_t>;
  using iterator = typename inv_map_t::iterator;
  using const_iterator = typename inv_map_t::const_iterator;

protected:
  CFG m_cfg;
  inv_map_t m_in_map;
  inv_map_t m_out_map;

private:
  AnalysisOps m_analysis;

  /**
   * run_bwd_fixpo(G) is in theory equivalent to
   * run_fwd_fixpo(reverse(G)).
   *  However, weak_rev_topo_sort(G) != weak_topo_sort(reverse(G))
   *  For instance, for a G=(V,E) where
   *   V= {v1,v2, v3, v4, v5},
   *   E= {(v1,v2), (v1,v3), (v2,v4), (v4,v1), (v3,v5)}
   *  (1) weak_rev_topo_sort(cfg)=[v5,v3,v4,v2,v1]
   *  (2) weak_topo_sort(reverse(cfg))=[v5,v3,v2,v4,v1] or even
   *      worse [v5,v3,v1,v4,v2] if vertices in the same scc are
   *      traversed in preorder.
   *  For a backward analysis, (1) will converge faster.
   *  For all of this, we decide not to reverse graphs and have
   *  two dual versions for the forward and backward analyses.
   **/

  void run_fwd_fixpo(std::vector<typename CFG::node_t> &order,
                     unsigned &iterations) {

    order = crab::analyzer::graph_algo::weak_topo_sort(m_cfg);
    assert((int)order.size() == std::distance(m_cfg.begin(), m_cfg.end()));
    bool change = true;
    iterations = 0;
    while (change) {
      change = false;
      ++iterations;
      for (unsigned i=0, e=order.size(); i<e; ++i) {
	auto const &n = order[i];
        auto in = (i==0 ? m_analysis.entry() : killgen_domain_t::bottom());
        for (auto const &p : m_cfg.prev_nodes(n))
          in = m_analysis.merge(in, m_out_map[p]);
        auto old_out = m_out_map[n];
        auto out = m_analysis.analyze(n, in);
        if (!(out <= old_out)) {
          m_out_map[n] = m_analysis.merge(out, old_out);
          change = true;
        } else
          m_in_map[n] = in;
      }
    }
  }

  void run_bwd_fixpo(std::vector<typename CFG::node_t> &order,
                     unsigned &iterations) {

    order = crab::analyzer::graph_algo::weak_rev_topo_sort(m_cfg);
    assert((int)order.size() == std::distance(m_cfg.begin(), m_cfg.end()));
    bool change = true;
    iterations = 0;
    while (change) {
      change = false;
      ++iterations;
      for (unsigned i=0, e=order.size(); i<e; ++i) {
	auto const &n = order[i];
        auto out = (i==0 ? m_analysis.entry() : killgen_domain_t::bottom());
        for (auto const &p : m_cfg.next_nodes(n))
          out = m_analysis.merge(out, m_in_map[p]);
        auto old_in = m_in_map[n];
        auto in = m_analysis.analyze(n, out);
        if (!(in <= old_in)) {
          m_in_map[n] = m_analysis.merge(in, old_in);
          change = true;
        } else
          m_out_map[n] = out;
      }
    }
  }

public:
  killgen_fixpoint_iterator(CFG cfg) : m_cfg(cfg), m_analysis(m_cfg) {}

  void release_memory() {
    m_in_map.clear();
    m_out_map.clear();
  }

  void run() {
    crab::ScopedCrabStats __st__(m_analysis.name());

    m_analysis.init_fixpoint();

    std::vector<typename CFG::node_t> order;
    unsigned iterations = 0;

    if (m_analysis.is_forward()) {
      run_fwd_fixpo(order, iterations);
    } else {
      run_bwd_fixpo(order, iterations);
    }

    CRAB_LOG(
        m_analysis.name(), crab::outs() << "fixpoint ordering={";
        bool first = true; for (auto &v
                                : order) {
          if (!first)
            crab::outs() << ",";
          first = false;
          crab::outs() << basic_block_traits<basic_block_t>::to_string(v);
        } crab::outs() << "}\n";);

    CRAB_LOG(m_analysis.name(), crab::outs() << m_analysis.name() << ": "
                                             << "fixpoint reached in "
                                             << iterations << " iterations.\n");

    CRAB_LOG(
        m_analysis.name(), crab::outs() << m_analysis.name() << " sets:\n";
        for (auto it = m_cfg.label_begin(), et = m_cfg.label_end(); it != et;
             ++it) {
          crab::outs() << basic_block_traits<basic_block_t>::to_string(*it)
                       << " "
                       << "IN=" << m_in_map[*it] << " "
                       << "OUT=" << m_out_map[*it] << "\n";
        } crab::outs()
        << "\n";);
  }

  iterator in_begin() { return m_in_map.begin(); }
  iterator in_end() { return m_in_map.end(); }
  const_iterator in_begin() const { return m_in_map.begin(); }
  const_iterator in_end() const { return m_in_map.end(); }

  iterator out_begin() { return m_out_map.begin(); }
  iterator out_end() { return m_out_map.end(); }
  const_iterator out_begin() const { return m_out_map.begin(); }
  const_iterator out_end() const { return m_out_map.end(); }
};

} // end namespace iterators
} // end namespace crab
<commit_msg>refactor(killgen-fixpo): methods to get solutions for a given block<commit_after>#pragma once

/**
 * Specialized fixpoint iterators for kill-gen problems.
 **/

//#include <crab/cfg/basic_block_traits.hpp>
#include <crab/analysis/graphs/sccg.hpp>
#include <crab/analysis/graphs/topo_order.hpp>
#include <crab/cfg/cfg_bgl.hpp>
#include <crab/domains/killgen_domain.hpp>
#include <crab/support/debug.hpp>
#include <crab/support/stats.hpp>

namespace crab {
namespace iterators {

// API for a kill-gen analysis operations
template <class CFG, class Dom> class killgen_operations_api {

public:
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using killgen_domain_t = Dom;

protected:
  CFG m_cfg;

public:
  killgen_operations_api(CFG cfg) : m_cfg(cfg) {}

  virtual ~killgen_operations_api() {}

  // whether forward or backward analysis
  virtual bool is_forward() = 0;

  // initial state
  virtual Dom entry() = 0;

  // (optional) initialization for the fixpoint
  virtual void init_fixpoint() = 0;

  // confluence operator
  virtual Dom merge(Dom, Dom) = 0;

  // analyze a basic block
  virtual Dom analyze(const basic_block_label_t &, Dom) = 0;

  // analysis name
  virtual std::string name() = 0;
};

// A simple fixpoint for a killgen analysis
template <class CFG, class AnalysisOps> class killgen_fixpoint_iterator {

public:
  using basic_block_t = typename CFG::basic_block_t;
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using killgen_domain_t = typename AnalysisOps::killgen_domain_t;
  using inv_map_t = std::unordered_map<basic_block_label_t, killgen_domain_t>;
  using iterator = typename inv_map_t::iterator;
  using const_iterator = typename inv_map_t::const_iterator;

protected:
  CFG m_cfg;
  inv_map_t m_in_map;
  inv_map_t m_out_map;

private:
  AnalysisOps m_analysis;

  /**
   * run_bwd_fixpo(G) is in theory equivalent to
   * run_fwd_fixpo(reverse(G)).
   *  However, weak_rev_topo_sort(G) != weak_topo_sort(reverse(G))
   *  For instance, for a G=(V,E) where
   *   V= {v1,v2, v3, v4, v5},
   *   E= {(v1,v2), (v1,v3), (v2,v4), (v4,v1), (v3,v5)}
   *  (1) weak_rev_topo_sort(cfg)=[v5,v3,v4,v2,v1]
   *  (2) weak_topo_sort(reverse(cfg))=[v5,v3,v2,v4,v1] or even
   *      worse [v5,v3,v1,v4,v2] if vertices in the same scc are
   *      traversed in preorder.
   *  For a backward analysis, (1) will converge faster.
   *  For all of this, we decide not to reverse graphs and have
   *  two dual versions for the forward and backward analyses.
   **/

  void run_fwd_fixpo(std::vector<typename CFG::node_t> &order,
                     unsigned &iterations) {

    order = crab::analyzer::graph_algo::weak_topo_sort(m_cfg);
    assert((int)order.size() == std::distance(m_cfg.begin(), m_cfg.end()));
    bool change = true;
    iterations = 0;
    while (change) {
      change = false;
      ++iterations;
      for (unsigned i=0, e=order.size(); i<e; ++i) {
	auto const &n = order[i];
        auto in = (i==0 ? m_analysis.entry() : killgen_domain_t::bottom());
        for (auto const &p : m_cfg.prev_nodes(n))
          in = m_analysis.merge(in, m_out_map[p]);
        auto old_out = m_out_map[n];
        auto out = m_analysis.analyze(n, in);
        if (!(out <= old_out)) {
          m_out_map[n] = m_analysis.merge(out, old_out);
          change = true;
        } else
          m_in_map[n] = in;
      }
    }
  }

  void run_bwd_fixpo(std::vector<typename CFG::node_t> &order,
                     unsigned &iterations) {

    order = crab::analyzer::graph_algo::weak_rev_topo_sort(m_cfg);
    assert((int)order.size() == std::distance(m_cfg.begin(), m_cfg.end()));
    bool change = true;
    iterations = 0;
    while (change) {
      change = false;
      ++iterations;
      for (unsigned i=0, e=order.size(); i<e; ++i) {
	auto const &n = order[i];
        auto out = (i==0 ? m_analysis.entry() : killgen_domain_t::bottom());
        for (auto const &p : m_cfg.next_nodes(n))
          out = m_analysis.merge(out, m_in_map[p]);
        auto old_in = m_in_map[n];
        auto in = m_analysis.analyze(n, out);
        if (!(in <= old_in)) {
          m_in_map[n] = m_analysis.merge(in, old_in);
          change = true;
        } else
          m_out_map[n] = out;
      }
    }
  }

public:
  killgen_fixpoint_iterator(CFG cfg) : m_cfg(cfg), m_analysis(m_cfg) {}

  void release_memory() {
    m_in_map.clear();
    m_out_map.clear();
  }

  void run() {
    crab::ScopedCrabStats __st__(m_analysis.name());

    m_analysis.init_fixpoint();

    std::vector<typename CFG::node_t> order;
    unsigned iterations = 0;

    if (m_analysis.is_forward()) {
      run_fwd_fixpo(order, iterations);
    } else {
      run_bwd_fixpo(order, iterations);
    }

    CRAB_LOG(
        m_analysis.name(), crab::outs() << "fixpoint ordering={";
        bool first = true; for (auto &v
                                : order) {
          if (!first)
            crab::outs() << ",";
          first = false;
          crab::outs() << basic_block_traits<basic_block_t>::to_string(v);
        } crab::outs() << "}\n";);

    CRAB_LOG(m_analysis.name(), crab::outs() << m_analysis.name() << ": "
                                             << "fixpoint reached in "
                                             << iterations << " iterations.\n");

    CRAB_LOG(
        m_analysis.name(), crab::outs() << m_analysis.name() << " sets:\n";
        for (auto it = m_cfg.label_begin(), et = m_cfg.label_end(); it != et;
             ++it) {
          crab::outs() << basic_block_traits<basic_block_t>::to_string(*it)
                       << " "
                       << "IN=" << m_in_map[*it] << " "
                       << "OUT=" << m_out_map[*it] << "\n";
        } crab::outs()
        << "\n";);
  }

  iterator in_begin() { return m_in_map.begin(); }
  iterator in_end() { return m_in_map.end(); }
  const_iterator in_begin() const { return m_in_map.begin(); }
  const_iterator in_end() const { return m_in_map.end(); }

  iterator out_begin() { return m_out_map.begin(); }
  iterator out_end() { return m_out_map.end(); }
  const_iterator out_begin() const { return m_out_map.begin(); }
  const_iterator out_end() const { return m_out_map.end(); }

  // return null if not found
  const killgen_domain_t* get_in(const basic_block_label_t &bb) const {
    auto it = m_in_map.find(bb);
    if (it!= m_in_map.end()) {
      return &(it->second);
    } else {
      return nullptr;
    }
  }

  // return null if not found
  const killgen_domain_t* get_out(const basic_block_label_t &bb) const {
    auto it = m_out_map.find(bb);
    if (it!= m_out_map.end()) {
      return &(it->second);
    } else {
      return nullptr;
    }
  }

};

} // end namespace iterators
} // end namespace crab
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file observation_density.hpp
 * \date June 2015
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__MODEL__OBSERVATION__OBSERVATION_DENSITY_HPP
#define FL__MODEL__OBSERVATION__OBSERVATION_DENSITY_HPP

#include <fl/util/types.hpp>
#include <fl/util/traits.hpp>

namespace fl
{

template <
    typename Obsrv,
    typename State,
    int BatchSize = Eigen::Dynamic
>
class ObservationDensity
{
public:
    typedef Eigen::Array<State, BatchSize, 1 > StateArray;
    typedef Eigen::Array<FloatingPoint, BatchSize, 1 > ValueArray;

public:
    /// \todo should add the unnormalized log probability interface

    virtual FloatingPoint log_probability(const Obsrv& obsrv,
                                          const State& state) const = 0;

    /**
     * \return Dimension of the state variable $\f$x\f$
     */
    virtual int state_dimension() const = 0;

    /**
     * \return Dimension of the measurement \f$h(x, w)\f$
     */
    virtual int obsrv_dimension() const = 0;

    virtual FloatingPoint probability(const Obsrv& obsrv,
                                      const State& state) const
    {
        return std::exp(log_probability(obsrv, state));
    }

    virtual ValueArray log_probabilities(const Obsrv& obsrv,
                                         const StateArray& states)
    {
        auto probs = ValueArray(states.size());

        for (int i = 0; i < states.size(); ++i)
        {
            probs[i] = log_probability(obsrv, states[i]);
        }

        return probs;
    }

    virtual ValueArray probabilities(const Obsrv& obsrv,
                                     const StateArray& states)
    {
        return log_probabilities(obsrv, states).exp();
    }
};

}

#endif
<commit_msg>added switching observation density interface<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file observation_density.hpp
 * \date June 2015
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__MODEL__OBSERVATION__OBSERVATION_DENSITY_HPP
#define FL__MODEL__OBSERVATION__OBSERVATION_DENSITY_HPP

#include <fl/util/types.hpp>
#include <fl/util/traits.hpp>

namespace fl
{

template <
    typename Obsrv,
    typename State,
    int BatchSize = Eigen::Dynamic
>
class ObservationDensity
{
public:
    typedef Eigen::Array<State, BatchSize, 1 > StateArray;
    typedef Eigen::Array<FloatingPoint, BatchSize, 1 > ValueArray;

public:
    /// \todo should add the unnormalized log probability interface

    virtual FloatingPoint log_probability(const Obsrv& obsrv,
                                          const State& state) const = 0;

    /**
     * \return Dimension of the state variable $\f$x\f$
     */
    virtual int state_dimension() const = 0;

    /**
     * \return Dimension of the measurement \f$h(x, w)\f$
     */
    virtual int obsrv_dimension() const = 0;

    virtual FloatingPoint probability(const Obsrv& obsrv,
                                      const State& state) const
    {
        return std::exp(log_probability(obsrv, state));
    }

    virtual ValueArray log_probabilities(const Obsrv& obsrv,
                                         const StateArray& states)
    {
        auto probs = ValueArray(states.size());

        for (int i = 0; i < states.size(); ++i)
        {
            probs[i] = log_probability(obsrv, states[i]);
        }

        return probs;
    }

    virtual ValueArray probabilities(const Obsrv& obsrv,
                                     const StateArray& states)
    {
        return log_probabilities(obsrv, states).exp();
    }
};

template <
    typename Obsrv,
    typename State,
    int BatchSize = Eigen::Dynamic
>
class SwitchingObservationDensity
{
public:
    typedef Eigen::Array<State, BatchSize, 1 >          StateArray;
    typedef Eigen::Array<FloatingPoint, BatchSize, 1 >  ValueArray;
    typedef Eigen::Array<int, BatchSize, 1 >            IndexArray;

public:
    /// \todo should add the unnormalized log probability interface

    virtual FloatingPoint log_probability(const Obsrv& obsrv,
                                          const State& state,
                                          const int&   index) const = 0;

    /**
     * \return Dimension of the state variable $\f$x\f$
     */
    virtual int state_dimension() const = 0;

    /**
     * \return Dimension of the measurement \f$h(x, w)\f$
     */
    virtual int obsrv_dimension() const = 0;

    virtual FloatingPoint probability(const Obsrv& obsrv,
                                      const State& state,
                                      const int&   index) const
    {
        return std::exp(log_probability(obsrv, state, index));
    }

    virtual ValueArray log_probabilities(const Obsrv& obsrv,
                                         const StateArray& states,
                                         const IndexArray& indices)
    {
        auto probs = ValueArray(states.size());

        for (int i = 0; i < states.size(); ++i)
        {
            probs[i] = log_probability(obsrv, states[i], indices[i]);
        }

        return probs;
    }

    virtual ValueArray probabilities(const Obsrv& obsrv,
                                     const StateArray& states,
                                     const IndexArray& indices)
    {
        return log_probabilities(obsrv, states, indices).exp();
    }
};

}

#endif
<|endoftext|>