// $Id: forcesummary.h,v 1.35 2018/01/03 21:32:58 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 */


/********************************************************************
 ForceSummary is the governing object for polymorphism along force lines.
 It creates the basic tree and manages other force-specific objects.

 It is not polymorphic along force lines, but it contains forcevec, a
 vector of pointers to Force objects, which are polymorphic and
 can be used as a run-down of which forces are in effect in the program.
 This information is used in maximization and in output reporting.

 ForceSummary owns the things that its forcevec points to, and will
 delete them in its destructor.  No one else deletes these objects!
 When a ForceSummary is copied, a new set of Force objects is
 created for it to point to.

 ForceSummary is also the factory for TimeManager objects (see force.h).

 Written by Jim Sloan, heavily revised by Mary Kuhner

Jon Yamato:
 added SummarizeData(datapack)
Peter Beerli:
 added parameterlist class variable and
 several Getters and Setters for it (8/30/01)
Mary Kuhner:
 took them out again, created the ParamVector class to remove
 the need for them (October 2001)
********************************************************************/

#ifndef FORCESUMMARY_H
#define FORCESUMMARY_H

#include <cassert>  // May be needed for inline definitions.
#include <map>
#include <stdlib.h>
#include <string>
#include <vector>

#include "constants.h"
#include "defaults.h"
#include "forceparam.h"
#include "types.h"
#include "vectorx.h"

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

class Random;
class Force;
class Tree;
class TreeSummary;
class ChainPack;
class DataPack;
class Parameter;
class ParamVector;
class ChainOut;
class Summary;
class UIVars;
class StickForce;
class Event;    // for CreateEventVec(), we're the callthrough factory
class TimeManager;

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

class ForceSummary
{
  private:

    ForceVec m_forcevec;  // contains one instance of each active force

    ForceParameters m_startParameters; // Starting force parameter values.

    DoubleVec1d m_llikemles;          // likelihoods at the MLEs per region.
    double      m_overallLlikemle;

    // A vector of indices for the groups which are constrained to be identical
    ULongVec2d m_identicalGroups;

    // A vector of indices for the groups which are constrained to
    // be multiplicative
    ULongVec2d m_multiplicativeGroups;

    // The multiplier of each group in the same order as
    // m_multiplicativeGroups.
    DoubleVec1d m_multgroupmultiplier;

    // mechanism for accessing the Parameters as a linearized vector using
    // a check-in/check-out scheme
    friend class ParamVector;
    std::vector<Parameter>   GetAllParameters();
    void                     SetAllParameters(const std::vector<Parameter>& src);

    // There should only be one ForceSummary object
    ForceSummary(const ForceSummary& src);              // undefined
    ForceSummary& operator=(const ForceSummary& src);   // undefined


    ULongVec1d GetParamsIdenticalGroupedWith(unsigned long pindex) const;
    ULongVec1d
    GetParamsMultiplicativelyGroupedWith(unsigned long pindex) const;
    double     GetGroupMultiplier(unsigned long pindex) const;

  public:

    ForceSummary(ForceVec fvec, ForceParameters fparams, DataPack& dpac);
    ~ForceSummary();

    // is this force active?
    bool          CheckForce(force_type tag)   const;

    // Posterior output setup
    void          SetupPosteriors(const ChainPack& chpack,
                                  const DataPack& dpack) const;

    // Factory Functions
    Tree*          CreateProtoTree() const;
    TreeSummary*   CreateProtoTreeSummary() const;
    vector<Event*> CreateEventVec() const;  // used by ResimArranger::ctor

    // Many Set Functions removed because now that we have separation between front and back end,
    // we don't have to turn any forces on or off after the forcesummary is created.
    // ewalkup 8/17/2004
    void SetRegionMLEs(const ChainOut& chout, long region);
    void SetOverallMLE(const ChainOut& chout);

    bool  IsMissingForce(force_type tag) const;
    bool  AnyForcesOtherThanGrowCoal() const;
    bool  UsingStick() const;
    bool  HasGrowth() const { return CheckForce(force_GROW) || CheckForce(force_EXPGROWSTICK); };
    bool  HasSelection() const { return CheckForce(force_LOGISTICSELECTION) || CheckForce(force_LOGSELECTSTICK); };
    bool  HasLogisticSelection() const { return CheckForce(force_LOGISTICSELECTION); };
    // Get Functions
    long        GetNForces()       const { return m_forcevec.size(); };
    long        GetNLocalPartitionForces() const;
    ForceVec::const_iterator GetForceByTag(force_type tag) const;
    const StickForce& GetStickForce() const;
    LongVec1d GetLocalPartitionIndexes() const;
    LongVec1d GetNonLocalPartitionIndexes() const;
    force_type GetNonLocalPartitionForceTag() const;

    long        GetMaxEvents(force_type tag) const;
    MethodTypeVec1d GetMethods(force_type tag) const;
    const std::vector<Epoch>* GetEpochs() const;

    StringVec1d ToXML(unsigned long nspaces) const;

    const ForceParameters& GetStartParameters() const { return m_startParameters; };

    bool ConstrainParameterValues(ForceParameters& fp) const;

    double GetLlikeMle(long region) const   {
        assert(static_cast<unsigned>(region) < m_llikemles.size());
        return m_llikemles[region]; };

    double GetOverallLlikeMle()     const    { double mle =
            ((m_llikemles.size() == 1)
             ? m_llikemles[0] : m_overallLlikemle);
        return mle; };

    // It is a ghastly error to call the next function unless the underlying model actually is 2D
    // (and square).  It will throw an exception if you try.

    MethodTypeVec2d  Get2DMethods(force_type tag) const;

    const ForceVec&    GetAllForces()  const  { return m_forcevec; };
    vector<long>       GetForceSizes() const;
    vector<force_type> GetForceTags()  const;
    ULongVec2d       GetIdenticalGroupedParams() const { return m_identicalGroups; };
    ULongVec2d       GetMultiplicativeGroupedParams() const { return m_multiplicativeGroups; };
    void   SetParamWithConstraints(long pindex, double newval, DoubleVec1d& pvec, bool islog) const;

    const ForceVec   GetPartitionForces() const;
    const ForceVec   GetLocalPartitionForces() const;

    long             GetNParameters(force_type tag) const;

    long             GetAllNParameters() const;
    DoubleVec1d      GetModifiers(long posinparamvec) const;
    DoubleVec1d      GetModifiersByForce(force_type tag) const;
    proftype         GetOverallProfileType() const;

    double GetLowParameter(long posinparamvec) const;
    double GetHighParameter(long posinparamvec) const;
    double GetHighMult(long posinparamvec) const;
    double GetLowMult(long posinparamvec) const;

    // If you need to check out a set of Parameters as a linearized vector, declare a variable of type
    // ParamVector.  That constructor uses the singleton ForceSummary object from the registry and can
    // give you a read-only or read-write version of the parameters.  See parameter.h

    // GetPartIndex() is a call through function to handle dynamic
    // casting
    long             GetPartIndex(force_type forcename) const;

    // Used by the code that constructs proto-ranges
    LongVec1d        GetSelectedSites() const;

    TimeManager*     CreateTimeManager() const;

    // Validation
    bool IsValidForceSummary() const;
    // This is used in summary file reading, to make sure we are
    // reading a file created with the same forces as we now have.
    void ValidateForceParamOrBarf(const ForceParameters& fp);
};

#endif // FORCESUMMARY_H

//____________________________________________________________________________________
