%
%   Copyright 2007-2020 by the individuals mentioned in the source code history
%
%   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.

\name{mxFitFunctionMultigroup}
\alias{MxFitFunctionMultigroup-class}
\alias{mxFitFunctionMultigroup}

\title{Create a fit function used to fit multiple-group models}

\description{
\code{mxFitFunctionMultigroup} creates a fit function consisting of the sum of the fit statistics
from a list of submodels provided. Thus, it aggregates fit statistics from multiple submodels.

This total provides the optimization target for fitting a multi-group model.

In addition to being more compact and readable, using \code{mxFitFunctionMultigroup} has
additional side effects which are valuable for multi-group modeling.

First, it aggregates analytic derivative calculations.

Second, it allows \code{\link{mxRefModels}} to compute saturated models for raw data, as this function can learn which are the constituent submodels.

Third, and finally, it allows \code{\link{mxCheckIdentification}} to evaluate the local identification of the multigroup model.
}

\usage{
mxFitFunctionMultigroup(groups, ..., verbose = 0L)
}

\arguments{
\item{groups}{vector of submodel names (strings)}

\item{...}{Not used. Forces subsequent arguments to be specified by name.}

\item{verbose}{the level of debugging output}
}

\details{
Conceptually, \code{mxFitFunctionMultigroup} is equivalent to summing the subModel objectives in an \link{mxAlgebra},
and using an \link{mxFitFunctionAlgebra} to optimize the model based on this summed likelihood.

e.g. this 1-line call to mxFitFunctionMultigroup:

    \code{mxFitFunctionMultigroup(c("model1", "model2"))}

is equivalent to the following pair of statements:

    \code{mxAlgebra(name = "myAlgebra", model1.objective + model2.objective)}

    \code{mxFitFunctionAlgebra("myAlgebra")}

\emph{Note}: If needed, you can refer to the algebra generated by \code{mxFitFunctionMultigroup} as:

    \code{modelName.fitfunction}

Where "modelName" is the name of the container or supermodel.

}


\seealso{
Other fit functions:
\code{\link{mxFitFunctionML}},
\code{\link{mxFitFunctionWLS}}, \code{\link{mxFitFunctionAlgebra}},
\code{\link{mxFitFunctionGREML}}, \code{\link{mxFitFunctionR}},
\code{\link{mxFitFunctionRow}}

More information about the OpenMx package may be found \link[=OpenMx]{here}.
}


\examples{
#------------------------------------------------
# Brief non-running example
require("OpenMx")
mxFitFunctionMultigroup(c("model1", "model2")) # names of sub-models to be jointly optimised



# ===========================================
# = Longer, fully featured, running example =
# ===========================================

# Create and fit a model using mxMatrix, mxExpectationRAM, mxFitFunctionML,
# and mxFitFunctionMultigroup.
# The model is multiple group regression.
# Only the residual variances are allowed to differ across groups.


library(OpenMx)

# Simulate some data

# Group 1
N1 = 100
x = rnorm(N1, mean= 0, sd= 1)
y = 0.5*x + rnorm(N1, mean= 0, sd= 1)
ds1 <- data.frame(x, y)
dsNames <- names(ds1)

# Group 2: y has greater variance; x & y slightly lower correlation...
N2= 150
x= rnorm(N2, mean= 0, sd= 1)
y= 0.5*x + rnorm(N2, mean= 0, sd= sqrt(1.5))
ds2 <- data.frame(x, y)


# Define the matrices (A matrix implementation of 2 RAM models)

I <- mxMatrix(name="I", type="Iden", nrow=2, ncol=2)
M <- mxMatrix(name = "M", type = "Full", nrow = 1, ncol = 2, values=0,
              free=TRUE, labels=c("Mean_x", "Mean_y"))
# A matrix containing a path "b" of x on y
A <- mxMatrix(name = "A", type = "Full", nrow = 2, ncol = 2, values=c(0,1,0,0),
              free=c(FALSE,TRUE,FALSE,FALSE), labels=c(NA, "b", NA, NA))

S1 <- mxMatrix(name = "S", type = "Diag", nrow = 2, ncol = 2, values=1,
              free=TRUE, labels=c("Var_x", "Resid_y_group1"))
S2 <- mxMatrix(name = "S", type = "Diag", nrow = 2, ncol = 2, values=1,
              free=TRUE, labels=c("Var_x", "Resid_y_group2"))

# Define the expectation
expect <- mxExpectationRAM('A', 'S', 'I', 'M', dimnames= dsNames)


# Choose a fit function
fitFunction <- mxFitFunctionML(rowDiagnostics=TRUE)
# Also return row likelihoods (the fit function value is still 1x1)

# Multiple-group fit function sums the model likelihoods
# from its component models
mgFitFun <- mxFitFunctionMultigroup(c('g1model', 'g2model'))


# Define model 1 and model 2
m1 = mxModel(model="g1model",
	M, S1, A, I, expect, fitFunction,
    mxData(cov(ds1), type="cov", numObs=N1, means=colMeans(ds1))
)
m2 = mxModel(model="g2model",
	M, S2, A, I, expect, fitFunction,
    mxData(cov(ds2), type="cov", numObs=N2, means=colMeans(ds2))
)

mg <- mxModel(model='multipleGroup', m1, m2, mgFitFun)
# note!: Paths with the same name in both submodels are
# constrained to the same value across models. i.e.,
# b has only 1 value, as does Var_x. But Resid_y can take distinct
# values in the two groups.

# Fit the model and print a summary
mg <- mxRun(mg)
summary(mg)

# Examine fit function results
# Fit in -2lnL units)
mxEval(fitfunction, mg)

# Fit function results for each submodel:
mxEval(g1model.fitfunction, mg)
mxEval(g2model.fitfunction, mg)

mg2 = omxSetParameters(mg,
  labels = c("Resid_y_group1", "Resid_y_group2"),
  newlabels = "Resid_y", name = "equated")
mg2 = omxAssignFirstParameters(mg2)
mg2 = mxRun(mg2)

mxCompare(mg, mg2)
# ouch... that was a significant loss in fit: the residuals definately are larger in group2!

}
