// $Id: tempident.cpp,v 1.24 2018/01/03 21:33:04 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

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.

*/

/* Authors: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


#include <cassert>
#include <map>

#include "tempident.h"
#include "registry.h"
#include "treesum.h"
#include "constants.h"
#include "types.h"
#include "chainstate.h"
#include "collmanager.h"

#ifdef DMALLOC_FUNC_CHECK
#include "/usr/local/include/dmalloc.h"
#endif

using namespace std;

class Tree;

//------------------------------------------------------------------------------------

TemperatureIdentity::TemperatureIdentity(double temperature, StringVec1d arrstrings)
    : m_naccepted(0),
      m_badtrees(0),
      m_tinypoptrees(0),
      m_zerodltrees(0),
      m_stretchedtrees(0),
      m_temperature(temperature),
      m_swapsmade(0),
      m_swapstried(0),
      m_totalswapsmade(0),
      m_totalswapstried(0),
      m_averagetemp(0),
      m_totaltrees(0)
{
    // deduce the object's own coldness
    if (m_temperature == 1.0) m_iscold = true;
    else m_iscold = false;
    for (size_t arr=0; arr<arrstrings.size(); arr++)
    {
        m_acceptances.insert(make_pair(arrstrings[arr], make_pair(0, 0)));
    }
} // TemperatureIdentity ctor

//------------------------------------------------------------------------------------

void TemperatureIdentity::NoteSwap(TemperatureIdentity& hot, ChainState & hotstate, ChainState & coldstate)
{
    ++m_swapsmade;
    ++m_totalswapsmade;
    hotstate.TreeChanged();
    coldstate.TreeChanged();
} // NoteSwap

//------------------------------------------------------------------------------------

void TemperatureIdentity::StartChain()
{
    m_naccepted = 0;
    m_badtrees = 0;
    m_tinypoptrees = 0;
    m_stretchedtrees = 0;
    m_zerodltrees = 0;
    m_swapsmade = 0;
    m_swapstried = 0;
    m_totalswapsmade = 0;
    m_totalswapstried = 0;
    m_totaltrees = 0;
    m_chainout.SetStarttime();
    ClearAcceptances();
} // StartChain

//------------------------------------------------------------------------------------

ChainOut& TemperatureIdentity::EndChain()
{
    m_chainout.SetNumBadTrees(m_badtrees);
    m_chainout.SetNumTinyPopTrees(m_tinypoptrees);
    m_chainout.SetNumStretchedTrees(m_stretchedtrees);
    m_chainout.SetNumZeroDLTrees(m_zerodltrees);
    m_chainout.SetAccrate (static_cast<double>(m_naccepted) / m_totaltrees);
    if (m_iscold) m_chainout.SetAllAccrates(m_acceptances);
    return m_chainout;

} // EndChain

//------------------------------------------------------------------------------------
// Do bookkeeping based on a rearrangement just completed by the Chain.

void TemperatureIdentity::ScoreRearrangement(const string & arrangername, bool accepted)
{
    ++m_totaltrees;
    if (accepted)
    {
        ++m_naccepted;
    }

    // We keep track of per-arranger acceptance only for the cold chain
    if (m_iscold)
    {
        ratemap::iterator mapit = m_acceptances.find(arrangername);
        // is this a never-before-seen arranger?
        if (mapit == m_acceptances.end())
        {
            assert(false); //under the new scheme, we should never see this.
            mapit = m_acceptances.insert(make_pair(arrangername, make_pair(0, 0))).first;
        }

        // score an attempt at rearrangement
        ++mapit->second.second;
        // score a successful rearrangement
        if (accepted) ++mapit->second.first;
    }

} // ScoreRearrangement

//------------------------------------------------------------------------------------

void TemperatureIdentity::Sample(CollectionManager& collmanager, ChainState & chstate, long initialOrFinal, bool lastchain)
{
#ifndef STATIONARIES
    if (m_iscold)
    {
        collmanager.Collect(chstate, initialOrFinal, lastchain); // EWFIX.CHAINTYPE
    }
#else // STATIONARIES
    if (m_iscold)
    {
        registry.GetProtoTreeSummary().DumpStationariesData(*(chstate.GetTree()), chstate.GetParameters());
    }
#endif // STATIONARIES

} // Sample

//------------------------------------------------------------------------------------

void TemperatureIdentity::SetTemperature(double temperature)
{
    m_temperature = temperature;
    if (m_temperature == 1.0) m_iscold = true;
    else m_iscold = false;
} // SetTemperature

//------------------------------------------------------------------------------------

double TemperatureIdentity::GetSwapRate() const
{
    if (m_swapstried != 0)
        return static_cast<double>(m_swapsmade) / m_swapstried;
    else return FLAGDOUBLE;
} // GetSwapRate

//------------------------------------------------------------------------------------

double TemperatureIdentity::GetTotalSwapRate() const
{
    if (m_totalswapstried != 0)
        return static_cast<double>(m_totalswapsmade) / m_totalswapstried;
    else return FLAGDOUBLE;

} // GetTotalSwapRate

void TemperatureIdentity::ClearAcceptances()
{
    for (ratemap::iterator mapit = m_acceptances.begin();
         mapit != m_acceptances.end(); mapit++)
    {
        mapit->second.first = 0;
        mapit->second.second = 0;
    }
}

//____________________________________________________________________________________
