function net = mix(nin, nout, nexp , func, tag, varargin)
%mix	Create a mixture of experts model.
%
%	NET = MIX(NIN, NOUT, NEXP , FUNC, TAG) takes the number of inputs 
%       outputs, and experts for a mixtures-of-experts model, together with 
%       a string FUNC which specifies the output unit activation function
%       for the expert networks. TAG specifies the type of ME used:
%         'standard' = standard mixture-of-experts
%         'variance' = with an adaptive variance parameter for each expert (for regression problems)
%         'kernel'   = with Gaussian kernels for the gating network
%         'ker&var'  = 'kernel' with an adaptive variance parameter for each expert (for regression problems)
%
%       NET = MIX(NIN, NOUT, NEXP , FUNC, TAG, STRING) with STRING to
%       specify the covariance structure:
%         'spherical' = single variance parameter for each component
%         'diag'      = diagonal matrix for each component
%         'full'      = full matrix for each component
%       of the component Gaussians when the gate is a mixture of Gaussians. 
%
%       MIX returns a data structure NET. The fields in NET are:
%         type  = 'mix'
%         nin   = number of inputs
%         nout  = number of outputs
%         nexp  = number of experts
%         nwts  = total number of weights and biases (in the NEXP expert
%                 networks plus the gating network)
%         actfn = string describing the output unit activation function:
%	           'linear'   (for regression problems)
%	           'sigmoid'  (for 2-class classification)
%	           'softmax'  (for multiclass classification)
%                 for the expert networks. 
%         tag   = string for type of ME
%         exp   = data structure for the NEXP expert networks. Each of the
%                 expert networks is defined as a generalized linear model
%                 (GLM) with NIN inputs, NOUT outputs, and activation
%                 function FUNC.
%         gate  = data structure for the gating network. The gating network
%                 is either a GLM with NIN inputs, NEXP outputs, and a
%                 softmax activation function or a Gaussian mixture model
%                 (GMM) with NEXP centres, dimension NIN and a covariance 
%                 structure.
%
%         See also
%         mixfwd, glm, gmm, mixem, mixtrain, mixpak, mixunpak
%
%         Copyright: Perry Moerland

net.type = 'mix';
net.nin  = nin;
net.nout = nout;
net.nexp = nexp;

switch tag
  case {'kernel','ker&var','mfa','mfa&var','mpca','mpca&var'} 
   % gating network is a Gaussian kernel
   net.nwts = ((nin + 1)*nout)*nexp;
  otherwise
   % gating network is a GLM
   net.nwts = ((nin + 1)*nout)*nexp + (nin  + 1)*nexp;
end
net.tag = tag;

actfns = {'linear', 'logistic', 'softmax'};

if sum(strcmp(func, actfns)) == 0
  error('Undefined activation function. Exiting.');
else
  net.actfn = func;
end;

for i=1:nexp
  % expert networks are GLMs
  net.exp(i) = glm(nin,nout,net.actfn);
end;

switch tag
  case {'kernel','ker&var'}
   % gating network is a Gaussian kernel
   % the optional input specifies the type of covariance matrix
   net.gate = gmm(nin,nexp,varargin{1});
 case {'mfa','mfa&var'}
   % gating network is mixture of factor analysers
   % the optional input specifies the dimension of the latent space
   net.gate = mfa(nin,nexp,varargin{1});
 case {'mpca','mpca&var'}
   % gating network is a mixture of PCAs
   % the optional input specifies the dimension of the latent space
   net.gate = mpca(nin,nexp,varargin{1});
  otherwise
   % gating network is a GLM
   net.gate = glm(nin,nexp,'softmax');
end;
