function C = quad3dcovmat(sigma_x, sigma_y, sigma_z, x, y, z)
% Theoretical noise covariance matrix corresponding to a 3D quadratic function.
%
% Input arguments:
% sigma_x, sigma_y, sigma_z:
%    vector of noise covariance components
% x, y, z:
%    vector of observed data

% Copyright 2008-2009 Levente Hunyadi

validateattributes(sigma_x, {'numeric'}, {'nonnegative','scalar'});
validateattributes(sigma_y, {'numeric'}, {'nonnegative','scalar'});
validateattributes(sigma_z, {'numeric'}, {'nonnegative','scalar'});

validateattributes(x, {'numeric'}, {'real','nonempty','vector'});
validateattributes(y, {'numeric'}, {'real','nonempty','vector'});
validateattributes(z, {'numeric'}, {'real','nonempty','vector'});
assert(numel(x) == numel(y) && numel(y) == numel(z), ...
    'quad3dcov:DimensionMismatch', 'Data vectors x, y and z must have the same number of elements.');
x = x(:);
y = y(:);
z = z(:);

C = ...
    [                          mean(-3.*sigma_x.^4 + 6.*sigma_x.^2.*x.^2),                                           mean(3.*sigma_x.^2.*x.*y),                                           mean(3.*sigma_x.^2.*x.*z), mean(-sigma_x.^2.*sigma_y.^2 + sigma_x.^2.*y.^2 + sigma_y.^2.*x.^2),                                              mean(sigma_x.^2.*y.*z), mean(-sigma_x.^2.*sigma_z.^2 + sigma_x.^2.*z.^2 + sigma_z.^2.*x.^2), mean(3.*sigma_x.^2.*x),    mean(sigma_x.^2.*y),    mean(sigma_x.^2.*z), mean(sigma_x.^2) ...
    ;                                           mean(3.*sigma_x.^2.*x.*y), mean(-sigma_x.^2.*sigma_y.^2 + sigma_x.^2.*y.^2 + sigma_y.^2.*x.^2),                                              mean(sigma_x.^2.*y.*z),                                           mean(3.*sigma_y.^2.*x.*y),                                              mean(sigma_y.^2.*x.*z),                                              mean(sigma_z.^2.*x.*y),    mean(sigma_x.^2.*y),    mean(sigma_y.^2.*x),                mean(0),          mean(0) ...
    ;                                           mean(3.*sigma_x.^2.*x.*z),                                              mean(sigma_x.^2.*y.*z), mean(-sigma_x.^2.*sigma_z.^2 + sigma_x.^2.*z.^2 + sigma_z.^2.*x.^2),                                              mean(sigma_y.^2.*x.*z),                                              mean(sigma_z.^2.*x.*y),                                           mean(3.*sigma_z.^2.*x.*z),    mean(sigma_x.^2.*z),                mean(0),    mean(sigma_z.^2.*x),          mean(0) ...
    ; mean(-sigma_x.^2.*sigma_y.^2 + sigma_x.^2.*y.^2 + sigma_y.^2.*x.^2),                                           mean(3.*sigma_y.^2.*x.*y),                                              mean(sigma_y.^2.*x.*z),                          mean(-3.*sigma_y.^4 + 6.*sigma_y.^2.*y.^2),                                           mean(3.*sigma_y.^2.*y.*z), mean(-sigma_y.^2.*sigma_z.^2 + sigma_y.^2.*z.^2 + sigma_z.^2.*y.^2),    mean(sigma_y.^2.*x), mean(3.*sigma_y.^2.*y),    mean(sigma_y.^2.*z), mean(sigma_y.^2) ...
    ;                                              mean(sigma_x.^2.*y.*z),                                              mean(sigma_y.^2.*x.*z),                                              mean(sigma_z.^2.*x.*y),                                           mean(3.*sigma_y.^2.*y.*z), mean(-sigma_y.^2.*sigma_z.^2 + sigma_y.^2.*z.^2 + sigma_z.^2.*y.^2),                                           mean(3.*sigma_z.^2.*y.*z),                mean(0),    mean(sigma_y.^2.*z),    mean(sigma_z.^2.*y),          mean(0) ...
    ; mean(-sigma_x.^2.*sigma_z.^2 + sigma_x.^2.*z.^2 + sigma_z.^2.*x.^2),                                              mean(sigma_z.^2.*x.*y),                                           mean(3.*sigma_z.^2.*x.*z), mean(-sigma_y.^2.*sigma_z.^2 + sigma_y.^2.*z.^2 + sigma_z.^2.*y.^2),                                           mean(3.*sigma_z.^2.*y.*z),                          mean(-3.*sigma_z.^4 + 6.*sigma_z.^2.*z.^2),    mean(sigma_z.^2.*x),    mean(sigma_z.^2.*y), mean(3.*sigma_z.^2.*z), mean(sigma_z.^2) ...
    ;                                              mean(3.*sigma_x.^2.*x),                                                 mean(sigma_x.^2.*y),                                                 mean(sigma_x.^2.*z),                                                 mean(sigma_y.^2.*x),                                                             mean(0),                                                 mean(sigma_z.^2.*x),       mean(sigma_x.^2),                mean(0),                mean(0),          mean(0) ...
    ;                                                 mean(sigma_x.^2.*y),                                                 mean(sigma_y.^2.*x),                                                             mean(0),                                              mean(3.*sigma_y.^2.*y),                                                 mean(sigma_y.^2.*z),                                                 mean(sigma_z.^2.*y),                mean(0),       mean(sigma_y.^2),                mean(0),          mean(0) ...
    ;                                                 mean(sigma_x.^2.*z),                                                             mean(0),                                                 mean(sigma_z.^2.*x),                                                 mean(sigma_y.^2.*z),                                                 mean(sigma_z.^2.*y),                                              mean(3.*sigma_z.^2.*z),                mean(0),                mean(0),       mean(sigma_z.^2),          mean(0) ...
    ;                                                    mean(sigma_x.^2),                                                             mean(0),                                                             mean(0),                                                    mean(sigma_y.^2),                                                             mean(0),                                                    mean(sigma_z.^2),                mean(0),                mean(0),                mean(0),          mean(0) ...
    ];
