// $Id: forceparam.h,v 1.29 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 */


/********************************************************************
 ForceParameters is a collection class used for internal communication
 throughout Lamarc.

 ForceParameters is a package of information about the values of
 all force parameters (for all forces--it is not polymorphic).
 Any routine which wishes to pass or return a bundle of force
 parameters should use this class.  It is normally passed by
 value.

 Internally, the parameters are kept in separate vectors, but can
 present them as one big vector using the registry's ForceSummary
 object.

 Written by Jim Sloan, revised by Mary Kuhner, further revised by Lucian Smith

 Jon Yamato:
    added SetToMeanOf(vector<forceparameters>)
********************************************************************/
/* There are three 'modes' a ForceParameters object can come in.  In the
   'fully aware' version, it holds values for all the parameters, and it
   knows what those parameters should be for a particular genomic region.
   In this case, m_space is known_region.  All the parameter vectors
   will be filled with values in this case, and it can safely return either
   regional or global values.

   There are two 'partially aware' versions of the object, one where all it
   knows is the global parameter values, and one where all it knows are one
   region's parameter values, but doesn't know what region that is.  In the
   former case, m_space is global_region, and in the latter, m_space is
   unknown_region.  The starting values, for example, are global_region,
   since they must be used for every region, and the likelihood maximizer
   works with unknown_region objects, since it's just working, and nobody
   tells it what region it's working on.

   If you have either partially aware versions and want a fully aware version,
   you construct a new ForceParameters object and tell it what region you
   want:

   ForceParameters aware_fp(global_fp, reg#);
   ForceParameters aware_fp(unknown_fp, reg#);

   This constructor copies the appropriate vectors, then looks up the scaling
   factor it needs to fill in the other vectors.
   -Lucian
*/

#ifndef FORCEPARAM_H
#define FORCEPARAM_H

#include <vector>
#include "vectorx.h"
#include "constants.h"
#include "defaults.h"

class ForceSummary;
class Epoch;

enum param_space {global_region, known_region, unknown_region};

class ForceParameters
{
  private:
    ForceParameters(); //undefined

    // the parameter vectors.  recrates is a vector of one element, for
    // consistency of interface.
    DoubleVec1d m_globalThetas;
    DoubleVec1d m_regionalThetas;
    DoubleVec1d m_migrates;
    DoubleVec1d m_diseases;
    DoubleVec1d m_recrates;
    DoubleVec1d m_growths;
    // one-element vector, for consistency
    DoubleVec1d m_logisticSelectionCoefficient;
    DoubleVec1d m_epochtimes;

    long m_region; //Either the appropriate region or FLAGLONG for global.
    param_space m_space;

    vector<force_type> m_forceTags;
    vector<long>       m_forceSizes;

    // non-owning pointer to Epoch information, null if none exists
    const std::vector<Epoch>* m_epochptr;

    void CopyGlobalMembers(const ForceParameters& src);
    void CopyRegionalMembers(const ForceParameters& src);

    DoubleVec1d GetLogParameters(bool isGlobal) const;
    DoubleVec1d GetParameters(bool isGlobal)    const;

    void SetParameters(const DoubleVec1d& v, bool isGlobal);

    void FillGlobalParamsFromRegionalParams();
    void FillRegionalParamsFromGlobalParams();

  public:
    // ForceParameters(const ForceParameters& src); //we accept the default
    // ForceParameters& operator=(const ForceParameters& src);
    ForceParameters(long region);
    ForceParameters(param_space space);
    ForceParameters(param_space space,
                    ForceTypeVec1d types, LongVec1d sizes);
    ForceParameters(const ForceParameters& src, long region);
    // If we ever end up creating one of these things in global space but
    // don't know it, we would need a converter from unknown_region to global:
    // ForceParameters(const ForceParameters& src, param_space space);

    // Setters
    void  SetGlobalThetas  (const DoubleVec1d& v);
    void  SetRegionalThetas(const DoubleVec1d& v);
    void  SetMigRates(const DoubleVec1d& v);
    void  SetDiseaseRates(const DoubleVec1d& v);
    void  SetRecRates(const DoubleVec1d& v);
    void  SetGrowthRates(const DoubleVec1d& v);
    void  SetLogisticSelectionCoefficient(const DoubleVec1d& v);
    void  SetEpochTimes(const DoubleVec1d& v);
    void  SetGlobalParameters(const DoubleVec1d& v);
    void  SetRegionalParameters(const DoubleVec1d& v);
    void  SetGlobalParametersByTag(force_type tag, const DoubleVec1d& v);
    void  SetRegionalParametersByTag(force_type tag, const DoubleVec1d& v);

    // Getters
    // erynes 2004/01/22: made these return by constant reference
    // to improve speed.  This might become inappropriate as the
    // code base evolves.
    param_space        GetParamSpace()    const { return m_space; };
    const DoubleVec1d& GetGlobalThetas()  const;
    const DoubleVec1d& GetRegionalThetas()const;
    const DoubleVec1d& GetMigRates()      const { return m_migrates; };
    const DoubleVec1d& GetDiseaseRates()  const { return m_diseases; };
    const DoubleVec1d& GetRecRates()      const { return m_recrates; };
    const DoubleVec1d& GetGrowthRates()   const { return m_growths;  };
    const DoubleVec1d& GetLogisticSelectionCoefficient() const
    { return m_logisticSelectionCoefficient;  };
    const DoubleVec1d& GetEpochTimes()    const { return m_epochtimes; };
    const DoubleVec1d& GetGlobalParametersByTag  (force_type tag)    const;
    const DoubleVec1d& GetRegionalParametersByTag(force_type tag)    const;
    double GetRegionalLogParameter(long pnum) const;
    const std::vector<Epoch>* GetEpochs() const { return m_epochptr; };

    // only pull the valid (in the paramvec sense) disease rates
    DoubleVec1d GetOnlyDiseaseRates() const;

    // GetLogParameters() is used by the BayesArranger
    DoubleVec1d GetGlobalLogParameters()           const;
    DoubleVec1d GetRegionalLogParameters()         const;
    DoubleVec1d GetGlobalParameters()              const;
    DoubleVec1d GetRegionalParameters()            const;
    DoubleVec2d GetGlobal2dRates(force_type tag)   const;
    DoubleVec2d GetRegional2dRates(force_type tag) const;

    DoubleVec1d GetRegionalScalars() const;

    void WriteForceParameters(std::ofstream& out, long numtabs) const;
};

#endif // FORCEPARAM_H

//____________________________________________________________________________________
