function [y,y_exp,y_ehidden,y_gate,y_ghidden] = mixmlpfwd(net,x)
%mixmlpfwd Forward propagation through a gated experts model.
%
%       Y = MIXMLPFWD(NET, X) takes a gated experts model data structure
%       NET together with a matrix X of input vectors, and forward propagates
%       the inputs through the network to generate a matrix Y of output
%       vectors. Each row of X corresponds to one input vector and each row
%       of Y corresponds to one output vector.
%
%       [Y,Y_EXP,Y_EHIDDEN,Y_GATE,Y_GHIDDEN] = MIXMLPFWD(NET, X) also
%       generates 3-dimensional matrices Y_EXP and Y_EHIDDEN where 
%       each submatrix Y_EXP(:,:,i) corresponds to the matrix of output 
%       vectors of expert i and each submatrix Y_EHIDDEN(:,:,i) to the 
%       matrix of hidden unit activations of expert i. Y_GATE contains 
%       the matrix of output vectors of the gating network and Y_GHIDDEN
%       the matrix of hidden unit activations of the gating network.
%
%       See also
%       mixmlp, mlpfwd
%
%       Copyright: Perry Moerland
	


% Check arguments for consistency
errstring = consist(net, 'mixmlp', x);
if ~isempty(errstring);
  error(errstring);
end

ndata = size(x, 1);
nexp  = net.nexp;
nout  = net.nout;
ehidden = net.ehidden;

% forward propagation for the expert networks
y_exp = zeros(ndata,nout,nexp);
y_ehidden = zeros(ndata,ehidden,nexp);
for i=1:nexp
  [y_exp(:,:,i),y_ehidden(:,:,i)] = mlpfwd(net.exp(i),x);
end;

% forward propagation for the gating network
switch net.tag
  case {'kernel','ker&var'}
    y_gate = gmmpost(net.gate,x);
  case {'mfa','mfa&var'}
    y_gate = mfapost(net.gate,x);
  case {'mpca','mpca&var'}
    y_gate = mpcapost(net.gate,x);  
  otherwise
    [y_gate,y_ghidden] = mlpfwd(net.gate,x);
end;

%  output of the mixture of experts network
y = zeros(ndata,nout);
for i=1:nexp, 
      temp = y_gate(:,i);
      y = y + diag(sparse(temp))*y_exp(:,:,i);
end;
    
