function net = mixmlp(nin, ehidden, nout, ghidden, nexp , func, tag, varargin)
%mixmlp	Create a non-linear gated experts model.
%
%       NET = MIXMLP(NIN, EHIDDEN, NOUT, GHIDDEN,  NEXP , FUNC, TAG) takes the number of inputs 
%       outputs, experts, and hidden units (for the expert networks and the
%       gating network) for a gated experts model, together with 
%       a string FUNC which specifies the output unit activation function
%       for the expert networks. TAG specifies the type of gated expert used:
%         'standard' = standard gated experts
%         'variance' = with an adaptive variance parameter for each expert
%         'kernel'   = with Gaussian kernels for the gating network (for regression problems)
%         'ker&var'  = 'kernel' with an adaptive variance parameter for each expert (for regression problems)
%
%       NET = MIXMLP(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. 
%
%       MIXMLP 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'
%                  'sigmoid'
%                  'softmax'
%                 for the expert networks. 
%         tag   = string for type of gated expert
%         exp   = data structure for the NEXP expert networks. Each of the
%                 expert networks is defined as a MLP with NIN inputs, NOUT 
%                 outputs, EHIDDEN hidden units, and activation function FUNC.
%         gate  = data structure for the gating network. The gating network
%                 is either a MLP with NIN inputs, GHIDDEN hidden units,
%                 NEXP outputs, and a softmax activation function or a
%                 Gaussian mixture model (GMM) with NEXP centres, dimension
%                 NIN and a covariance structure.
%
%         See also
%         mixmlpfwd, mlp, gmm, mixmlpem, mixmlppak, mixmlpunpak
%
%         Copyright: Perry Moerland


net.type = 'mixmlp';
net.nin = nin;
net.ehidden = ehidden;
net.nout = nout;
net.ghidden = ghidden;
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)*ehidden + (ehidden+1)*nout)*nexp;
  otherwise
    % gating network is a MLP
    net.nwts = ((nin + 1)*ehidden + (ehidden+1)*nout)*nexp + ((nin + 1)*ghidden  + (ghidden + 1)*nexp);
end;

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 MLPs
  net.exp(i) = mlp(nin,ehidden,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 MLP
   net.gate = mlp(nin,ghidden,nexp,'softmax');
end;

net.tag = tag;