function h=som_plotplane(varargin)

%SOM_PLOTPLANE  Visualize the map prototype vectors as line graphs
%
% h=som_plotplane(lattice, msize, data, [color], [scaling], [pos])
% h=som_plotplane(topol, data, [color], [scaling], [pos])
%
%  som_plotplane('hexa',[5 5], rand(25,4), jet(25))
%  som_plotplane(sM, sM.codebook)
%
% Input and output arguments ([]'s are optional)
%  lattice   (string) grid 'hexa' or 'rect'
%  msize     (vector) size 1x2, defines the grid size
%            (matrix) size Mx2, defines explicit coordinates: in
%             this case the first argument does not matter
%  topol     (struct) map or topology struct
%  data      (matrix) Mxd matrix, M=prod(msize)
%  [color]   (matrix) size Mx3, gives an individual color for each graph
%            (string) ColorSpec gives the same color for each
%             graph, default is 'k' (black)
%  [scaling] (string) 'on' or 'off', default is 'on'
%  [pos]     (vector) 1x2 vector that determines translation.
%             Default is no translation.
%
%  h         (vector) the object handles for the LINE objects
%
%  If scaling is set on, the data will be linearly scaled in each
%  unit so that min and max values span from lower to upper edge
%  in each unit. If scaling is 'off', the proper scaling is left to
%  the user: values in range [-.5,.5] will be plotted within the limits of the
%  unit while values exceeding this range will be out of the unit.
%  Axis are set as in SOM_CPLANE.
%
% For more help, try 'type som_plotplane' or check out online documentation.
% See also SOM_PLANE, SOM_PIEPLANE, SOM_BARPLANE

%%%%%%%%%%%%% DETAILED DESCRIPTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% som_plotplane
%
% PURPOSE
%
% Visualizes the map prototype vectors as line graph
%
% SYNTAX
%
%  h = som_plotplane(topol, data)
%  h = som_plotplane(lattice, msize, data)
%  h = som_plotplane(..., color)
%  h = som_plotplane(..., color, scaling)
%  h = som_plotplane(..., color, scaling, pos)
%
% DESCRIPTION
%
%  Visualizes the map prototype vectors as line graph
%
% KNOWN BUGS
%
%  It is not possible to specify explicit coordinates for map
%  consistig of just one unit as then the msize is interpreted as
%  map size.
%
% FEATURES
%
%  - the colors are fixed: changing colormap in the figure (see
%    COLORMAP) will not affect the coloring of the plots
%
% REQUIRED INPUT ARGUMENTS
%
% lattice  The basic topology
%
%   (string) 'hexa' or 'rect' positions the plots according to hexagonal or
%            rectangular map lattice.
%
% msize    The size of the map grid
%
%   (vector) [n1 n2] vector defines the map size (height n1 units, width n2
%            units, total M=n1 x n2 units). The units will be placed to their
%            topological locations in order to form a uniform hexagonal or
%            rectangular grid.
%   (matrix) Mx2 matrix defines arbitary coordinates for the M units.
%            In this case the argument 'lattice' has no effect.
%
% topol    Topology of the map grid
%
%   (struct) map or topology struct from which the topology is taken
%
% data     The data to be visualized
%
%   (matrix) Mxd matrix of data vectors.
%
% OPTIONAL INPUT ARGUMENTS
%
% If unspecified or given empty values ('' or []), default values
% will be used for optional input arguments.
%
% color    The color of the plots
%
%    (string) Matlab's ColorSpec (see help plot) string gives the same color
%             for each line.
%
%    (matrix) Mx3 matrix assigns an RGB color determined by the Nth row of
%             the matrix to the Nth plot.
%
%    (vector) 1x3 RGB vector gives the same color for each line.
%
% scaling  The data scaling mode
%
%    (string) 'on or 'off': if scaling is set on, the data will be
%             linearly scaled in each unit so that min and max values span from
%             lower to upper edge in each unit. If scaling is 'off', the proper
%             scaling is left to the user: values in range [-.5,.5] will be plotted
%             within the limits of the unit while values exceeding this
%             range will be out of the unit.
%
% pos      Position of the origin
%
%    (vector) This is meant for drawing the plane in arbitary location in a
%             figure. Note the operation: if this argument is given, the
%             axis limits setting part in the routine is skipped and the limits
%             setting will be left to be done by MATLAB's
%             defaults. By default no translation is done.
%
% OUTPUT ARGUMENTS
%
%  h (scalar)  Handle to the created patch object
%
% OBJECT TAG
%
% Object property 'Tag' is set to 'planePlot'.
%
% EXAMPLES
%
% %%% Create the data and make a map
%
% data=rand(1000,20); map=som_make(data);
%
% %%% Create a 'gray' colormap that has 64 levels
%
% color_map=gray(64);
%
% %%% Draw plots using red color
%
% som_plotplane(map, map.codebook,'r');
%
% %%% Calculate hits on the map and calculate colors so that
%     black = min. number of hits and white = max. number of hits
%
% hit=som_hits(map,data); color=som_normcolor(hit(:),color_map);
%
% %%% Draw plots again. Now the gray level indicates the number of hits to
%     each node
%
% som_plotplane(map, map.codebook, color);
%
% SEE ALSO
%
% som_cplane     Visualize a 2D component plane, u-matrix or color plane
% som_barplane   Visualize the map prototype vectors as bar diagrams.
% som_pieplane   Visualize the map prototype vectors as pie charts

% Copyright (c) 1999-2000 by the SOM toolbox programming team.
% http://www.cis.hut.fi/projects/somtoolbox/

% Version 2.0beta Johan 160799 juuso 151199 070600

%%% Init & Check arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

[nargin, lattice, msize, data, color, scaling, pos] = vis_planeGetArgs(varargin{:});
error(nargchk(3, 5, nargin));  % check no. of input args is correct

s=0.8; % size of plot

if nargin < 6 || isempty(pos)
  pos=NaN;
end

if nargin < 5 || isempty(scaling)
  scaling='on';
elseif ~vis_valuetype(scaling,{'string'}) || ...
      ~any(strcmp(scaling,{'on','off'})),
  error('Scaling should be string ''on'' or ''off''.');
end

l=size(data,2);

if ~isnumeric(msize) || ndims(msize) ~= 2 || size(msize,2)~=2,
  error('msize has to be 1x2 grid size vector or a Nx2 coordinate matrix.');
elseif size(msize,1) == 1,
   xdim=msize(2);
   ydim=msize(1);
   N=xdim*ydim;
   y=repmat(repmat([1:ydim]',xdim,1),1,l);
   x=reshape(repmat([1:xdim],ydim*l,1),l,N)';
else
   x=repmat(msize(:,1),1,l);y=repmat(msize(:,2),1,l);
   N=size(msize,1);
   lattice='rect';
   if isnan(pos),
      pos=[0 0];
   end
end

switch lattice
case {'hexa', 'rect'}
otherwise
  error(['Lattice' lattice ' not implemented!']);
end

if ~isnumeric(data) || size(data,1) ~= N
  error('Data matrix is invalid or has wrong size!');
end

if nargin < 4 || isempty(color),
  color='k';
elseif vis_valuetype(color, {'colorstyle',[N 3]}),
  if ischar(color) && strcmp(color,'none'),
    error('Colorstyle ''none'' not allowed in som_plotplane.');
  end
elseif vis_valuetype(color,{'1x3rgb'})
elseif ~vis_valuetype(color,{'nx3rgb',[N 3]},'all'),
  error('The color matrix has wrong size or contains invalid RGB values or colorstyle.');
end

[linesx, linesy]=vis_line(data,scaling);

%%%% Action %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Making the lattice.
% Command view([0 90]) shows the map in 2D properly oriented

switch lattice
case 'hexa'
  t=find(rem(y(:,1),2));                  % move even rows by .5
  x(t,:)=x(t,:)-.5;
  x=(x./s+linesx).*s+.5; y=(y./s+linesy).*s;      % scale with s
case 'rect'
  x=(x./s+linesx).*s; y=(y./s+linesy).*s;         % scale with s
end

%% Draw the map! ...

h_=plot(x',y');

if size(color,1) == 1
  set(h_,'Color',color);
else
  for i=1:N,
    set(h_(i,:),'Color',color(i,:));
  end
end

if ~isnan(pos)
  x=x+pos(1);y=y+pos(2);                    % move upper left corner
end                                         % to pos(1),pos(2)

%% Set axes properties

ax=gca;
vis_PlaneAxisProperties(ax, lattice, msize, pos);

%%% Build output %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

set(h_,'Tag','planePlot');                % tag the lineobject

if nargout>0, h=h_; end                   % Set h only,
                                          % if there really is output

%% Subfuntion %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [x,y]=vis_line(data, scaling)

s=size(data);
% normalization between [0,1] if scaling is on
if strcmp(scaling,'on')
  mn=repmat(min(data,[],2),1,s(2));
  mx=repmat(max(data,[],2),1,s(2));
  y=-((data-mn)./(mx-mn))+.5;
else                       % -sign is beacuse we do axis ij
  y=-data;
end

x=repmat(linspace(-.5, .5, size(data,2)), size(data,1),1);


function chopDoseOutsideStruct(doseNum,structureNum)
%function chopDoseOutsideStruct(doseNum,structureNum)
%
%This function creates a new dose which is same as doseNum, but which lies
%within structureNum.
%
%Usage: planC = chopDoseOutsideStruct(1,6)
%
%APA, 04/01/2010
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

global stateS planC
indexS = planC{end};

%Get associated scan number
scanNum = getStructureAssociatedScan(structureNum);
assocScanUID = planC{indexS.dose}(doseNum).assocScanUID;
scanNumDose = getAssociatedScan(assocScanUID);
tmDose = getTransM('dose',doseNum,planC);
if isempty(tmDose)
    tmDose = eye(4);
end
tmScan = getTransM('scan',scanNum,planC);
if isempty(tmScan)
    tmScan = eye(4);
end
if isempty(scanNumDose) && ~isequal(tmDose,tmScan)
    error('This function currently supports dose and structure with same transformation matrix')
end

%Get dose grid
[xDoseVals, yDoseVals, zDoseVals] = getDoseXYZVals(planC{indexS.dose}(doseNum));

%Get Uniformized structure and grid
[xUnifVals, yUnifVals, zUnifVals] = getUniformScanXYZVals(planC{indexS.scan}(scanNum));
structureMask3M = getUniformStr(structureNum);

[xDoseValsM, yDoseValsM, zDoseValsM] = meshgrid(xDoseVals, yDoseVals, zDoseVals);
xDoseValsV = xDoseValsM(:);
yDoseValsV = yDoseValsM(:);
zDoseValsV = zDoseValsM(:);

%Interpolate structure on to dose grid
structureOnDoseV = interp3(xUnifVals, yUnifVals, zUnifVals, single(structureMask3M), xDoseValsV, yDoseValsV, zDoseValsV, 'nearest',0);

structureOnDoseM = reshape(structureOnDoseV,[length(yDoseVals), length(xDoseVals), length(zDoseVals)]);

planC{indexS.dose}(end+1) = planC{indexS.dose}(doseNum);
planC{indexS.dose}(end).doseArray = planC{indexS.dose}(end).doseArray .* structureOnDoseM;
planC{indexS.dose}(end).doseUID = createUID('dose');

stateS.doseSet = length(planC{indexS.dose});

sliceCallBack('refresh');


clc;clear all;close all;
%***********************************************%
% This code runs on the Market-1501 dataset.    %
% Please modify the path to your own folder.    %
% We use the mAP and hit-1 rate as evaluation   %
%***********************************************%
% if you find this code useful in your research, please kindly cite our
% paper as,
% Liang Zheng, Liyue Sheng, Lu Tian, Shengjin Wang, Jingdong Wang, and Qi Tian,
% Scalable Person Re-identification: A Benchmark, ICCV, 2015.

% Please download Market-1501 dataset and unzip it in the "dataset" folder.
addpath(genpath('LOMO_XQDA/'));
addpath(genpath('utils/'));
addpath(genpath('KISSME/'));
run('KISSME/toolbox/init.m');

%% network name
netname = 'ResNet_50'; % network: CaffeNet  or ResNet_50

%% test info
galFea = importdata(['feat/IDE_' netname '_test.mat']);
galFea = double(galFea);
probFea = importdata(['feat/IDE_' netname '_query.mat']);
probFea = double(probFea);
label_gallery = importdata('data/testID.mat');
label_query = importdata('data/queryID.mat');
cam_gallery =   importdata('data/testCam.mat');
cam_query =  importdata('data/queryCam.mat');

%% normalize
sum_val = sqrt(sum(galFea.^2));
for n = 1:size(galFea, 1)
    galFea(n, :) = galFea(n, :)./sum_val;
end

sum_val = sqrt(sum(probFea.^2));
for n = 1:size(probFea, 1)
    probFea(n, :) = probFea(n, :)./sum_val;
end

% Instead of pdist2. 50 times faster than pdist2
my_pdist2 = @(A, B) sqrt( bsxfun(@plus, sum(A.^2, 2), sum(B.^2, 2)') - 2*(A*B'));
%% Euclidean

dist_eu = my_pdist2(galFea', probFea');
[CMC_eu, map_eu, ~, ~] = evaluation(dist_eu, label_gallery, label_query, cam_gallery, cam_query);

fprintf(['The IDE (' netname ') + Euclidean performance:\n']);
fprintf(' Rank1,  mAP\n');
fprintf('%5.2f%%, %5.2f%%\n\n', CMC_eu(1) * 100, map_eu(1)*100);


function plotIMPB(IMCalc)
% JC
% Plot the pb information for IMCalc. IM struct.
% To make sure the coordinates are alright. and pbs are adjacent to each
% other.
%

figure;
xPosV = IMCalc.beams.xPBPosV;
yPosV = IMCalc.beams.yPBPosV;
beamlet_delta_x = IMCalc.beams.beamletDelta_x;
beamlet_delta_y = IMCalc.beams.beamletDelta_y;
w_field = ones(size(xPosV));
%for i=1:length(xPosV)
for i = 250: 251
   patch([xPosV(i) - beamlet_delta_x(i)/2 xPosV(i) - beamlet_delta_x(i)/2 xPosV(i) + beamlet_delta_x(i)/2 xPosV(i) + beamlet_delta_x(i)/2 xPosV(i) - beamlet_delta_x(i)/2], [yPosV(i) - beamlet_delta_y(i)/2 yPosV(i) + beamlet_delta_y(i)/2 yPosV(i) + beamlet_delta_y(i)/2 yPosV(i) - beamlet_delta_y(i)/2 yPosV(i) - beamlet_delta_y(i)/2], w_field(i));
   hold on; plot(xPosV(i), yPosV(i), 'r.');
end


function [distAll, scoresAll, pointsAll] = assignGTinferenceMulti(keypointsAll,annolist,pidxsAll,parts,thresh_gt,marg_scores,nTrials)

if (nargin < 5)
    thresh_gt = 0.5;
end

scoresAll = cell(length(pidxsAll),1);
pointsAll = cell(length(pidxsAll),1);
distAll = cell(length(pidxsAll),1);

for i = 1:length(pidxsAll)
    scoresAll{i} = cell(length(annolist),1);
    pointsAll{i} = cell(length(annolist),1);
    distAll{i} = cell(length(annolist),1);
end

for imgidx = 1:length(annolist)

%     figure(200); clf; imagesc(imread(annolist(imgidx).image.name));
%     hold on; axis equal;

    det_c = {'g','b'};
    for trialidx = 1:nTrials/2
        if (isempty(keypointsAll(imgidx).det{trialidx}))
            continue;
        end
        dist = cell(2,1);
        for detidx = 1:2

            dist{detidx} = inf(length(pidxsAll),length(annolist(imgidx).annorect));
            for i = 1:length(pidxsAll)
                pidx = pidxsAll(i);
                % part is a joint
                assert(parts(pidx+1).pos(1) == parts(pidx+1).pos(2));
                jidx = parts(pidx+1).pos(1);

                det = keypointsAll(imgidx).det{trialidx}{jidx+1};
                assert(~isempty(det));
%                 [val,id] = max(det(:,4+detidx));
                id = detidx;
                val = det(id,4+detidx);
                pp = det(id,1:2);

                if (isnan(val))
                    val = -inf;
                end

                if (isnan(pp(1)))
                    assert(isnan(pp(2)));
                    pp = [0 0];
                end

                pointsAll{i}{imgidx} = [pointsAll{i}{imgidx}; pp];
                if (marg_scores)
                    scoresAll{i}{imgidx} = [scoresAll{i}{imgidx}; val];
                else
                    scoresAll{i}{imgidx} = [scoresAll{i}{imgidx}; det(id,3)];
                end

                for ridx = 1:length(annolist(imgidx).annorect)
                    rect = annolist(imgidx).annorect(ridx);
                    refDist = util_get_head_size(rect);
                    if (isfield(rect, 'annopoints') && isfield(rect.annopoints, 'point'))
                        p = util_get_annopoint_by_id(rect.annopoints.point, jidx);
                        if (~isempty(p))
                            dist{detidx}(i,ridx) = norm([p.x p.y] - pp)/refDist;
                            %                         plot(p.x,p.y,'ro','MarkerFaceColor','y','MarkerEdgeColor','k','MarkerSize',10);
                        else
                            dist{detidx}(i,ridx) = nan;
                        end
                    end
                end
                %             plot(pp(1),pp(2),'ro','MarkerFaceColor',det_c{detidx},'MarkerEdgeColor','k','MarkerSize',10);
            end
        end

        for detidx = 1:2
            pckSum = zeros(1,size(dist{detidx},2));
            idxsNotNaN = ~isnan(dist{detidx});
            for i=1:size(dist{detidx},2)
                pckSum(i) = sum(dist{detidx}(idxsNotNaN(:,i),i) <= thresh_gt);
            end
            [val,idx] = max(pckSum);
            idx2 = setdiff(1:size(dist{detidx},2),idx);
            dist{detidx}(idxsNotNaN(:,idx2),idx2) = inf;
            for i = 1:length(pidxsAll)
                distAll{i}{imgidx} = [distAll{i}{imgidx}; dist{detidx}(i,:)];
            end
        end
    end

end

end


function p = mpower(a,b)
	if isscalar(a) && isscalar(b)
		p = a.^b;
	else
		error('Int64 matrix powers not supported');
	end
end


%Once the image is processed using the gridextractor method, this function
%tries to fit the grid on the extraced points in order to establish the
%correspondences
%
%Input:     stats   The processed blobs of this image
%           id0     The index of the main bar
%           id1     The index of the second main bar
%           searchPoints    The potential grid points
%           doshow  1/0 to display / not display the results
%
%Output:    success The flag indicating whether it worked or not
%           x_      the 2D points of the grid points
%           X_      the corresponding 3D points of the grid points
%           searchPoints    The points
%
%This file uses some functions from Peter Kovesi's Matlab functions
%http://www.csse.uwa.edu.au/~pk/Research/MatlabFns/index.html
%
%Christian Wengert
%Computer Vision Laboratory
%ETH Zurich
%Sternwartstrasse 7
%CH-8092 Zurich
%www.vision.ee.ethz.ch/cwengert
%wengert@vision.ee.ethz.ch
function [success, x_, X_, searchPoints, error] = fitgrid(stats, searchPoints, id0, id1, dX, dY, show)

    %Grid small
    xmin = -12*dX;
    xmax = 12*dX;
    ymin = -12*dY;
    ymax = 12*dY;
    %Define a delta distance
    delta = 7; %[pixel]

    %Init
    x0 = [stats(id0).Centroid(1);stats(id0).Centroid(2)];
    x1 = [stats(id1).Centroid(1);stats(id1).Centroid(2)];
    dir = (x1-x0)/(norm(x1-x0));
    %Get a 90?angle
    dir90_ = [-dir(2);dir(1)];
    %get the orientation of main bar
    orientation = stats(id0).Orientation;
    y = tand(orientation);
    dir90 = [-1;y];
    dir90 = dir90/norm(dir90);

    %Compare direction of orientation with dir90_ and dir90
    sd90 = sign(dir90); sd90_  =sign(dir90_);
%     [dir90,dir90_]
    if(abs(1-abs(dir90_(1)))<0.01 & sd90(1)~=sd90_(1))
        dir90 = -dir90;
    elseif(abs(1-abs(dir90_(2)))<0.01 & sd90(2)~=sd90_(2))
        dir90 = -dir90;
    elseif(~(sd90(1)==sd90_(1) |sd90(2)==sd90_(2)))
        dir90 = -dir90;
    end

    error = 0;
    %Draw the initial lines
    if(show)
        line([x0(1), x0(1)+dir(1)*100], [x0(2), x0(2)+dir(2)*100],'Color','r');
        line([x0(1), x0(1)-dir(1)*100], [x0(2), x0(2)-dir(2)*100],'Color','r');
        line([x0(1), x0(1)+dir90(1)*100], [x0(2), x0(2)+dir90(2)*100]);
        line([x0(1), x0(1)-dir90(1)*100], [x0(2), x0(2)-dir90(2)*100]);
    end
    deltaDist2Line = 10;
    try
        %Create search Points
        a1 = x0+dir90*stats(id0).MajorAxisLength/2;
        a2 = x0-dir90*stats(id0).MajorAxisLength/2;
        b1 = x0-dir*stats(id1).MajorAxisLength/2;
        b2 = x1+dir*stats(id1).MajorAxisLength/2;
        if(show)
            plot(a1(1),a1(2),'mo','MarkerSize',40,'LineWidth',2)
            plot(a2(1),a2(2),'bo','MarkerSize',40,'LineWidth',2)
            plot(b1(1),b1(2),'co','MarkerSize',40,'LineWidth',2)
            plot(b2(1),b2(2),'ro','MarkerSize',40,'LineWidth',2)
        end
        da1 = [];da2 = []; db1 = []; db2 = [];
        for i=1:length(searchPoints)
            da1 = [da1;norm(a1 - searchPoints(2:3,i))];
            da2 = [da2;norm(a2 - searchPoints(2:3,i))];
            db1 = [db1;norm(b1 - searchPoints(2:3,i))];
            db2 = [db2;norm(b2 - searchPoints(2:3,i))];
        end
        [da1,ia1] = sort(da1);
        [da2,ia2] = sort(da2);
        [db1,ib1] = sort(db1);
        [db2,ib2] = sort(db2);
        ix0 = ia1(1);
        ix1 = ia2(1);
        iy(1) = ib1(1);
        iy(2) = ib2(1);

        %Show the points
        if(show)
            plot(searchPoints(2,ix0(1)),searchPoints(3,ix0(1)),'mx','MarkerSize',25,'LineWidth',2)
            plot(searchPoints(2,ix1(1)),searchPoints(3,ix1(1)),'bx','MarkerSize',25,'LineWidth',2)
            plot(searchPoints(2,iy(1)),searchPoints(3,iy(1)),'cx','MarkerSize',25,'LineWidth',2)
            plot(searchPoints(2,iy(2)),searchPoints(3,iy(2)),'rx','MarkerSize',25,'LineWidth',2)
        end
        %Refine the line
        dir = searchPoints(2:3,ix0(1)) - searchPoints(2:3,ix1(1));
        dir90 = searchPoints(2:3,iy(1)) - searchPoints(2:3,iy(2));

        %Make the initial grid
        [x,y] = meshgrid(xmin:dX:xmax, ymin:dY:ymax);
        x = reshape(x, 1, numel(x));
        y = reshape(y, 1, numel(y));
        xy = [x;y];
        usedPtsIndex = ones(1,length(x));
        %Get the homography
        %the points we have are: [pixels]
        xy__ = [searchPoints(2:3,ix0(1)), searchPoints(2:3,ix1(1)),searchPoints(2:3,iy(1)),searchPoints(2:3,iy(2))];
        xy_  = [[0;-2*dX],[0;2*dX], [-dY;0],[3*dY;0]];
        %Compute H
        [H, err] = invpersp(xy__, xy_);
        xyp = homoTrans(H,[xy;ones(1,length(xy))]);

        %Distance check
        for i=1:length(searchPoints)
            for j=1:length(xyp)
                d = norm(searchPoints(2:3,i)-xyp(1:2,j));
                error = error+d;
                %Check whether its good
                if(d<=delta)

                    if(show)
                        text(searchPoints(2,i)+5,searchPoints(3,i)+5,[num2str(xy(1,j)) ',' num2str(xy(2,j))],'Color','b')
                        plot(searchPoints(2,i), searchPoints(3,i),'r+');
                    end
                    searchPoints(4:5,i) = xy(1:2,j);
                    %Update the point vectors that they have been assigned
                    searchPoints(1,i) = 0;
                    usedPtsIndex(j) = 0;
                end
            end
        end
        success  = 1;
        finalindex = find(searchPoints(1,:)==0);
        x_ = searchPoints(2:3,finalindex);
        X_ = [searchPoints(4:5,finalindex)];
        X_ = [X_;zeros(1,length(X_))];

        error = error/length(x_)/length(xyp);
    catch
        disp('fitgrid::Could not find extension points')
        success = 0;
        x_ = []; X_ = [];
    end


% batch run full-clustering on all fish

% f.pushbutton_autoclus_Callback

global VAR;

data_masterdir = GetCurrentDataDir();

% range_fish = [5,6,7];
% M_ClusGroup = [2,2,2,2];
% M_Cluster = [1,1,1,1];
range_fish = 2:2;
M_ClusGroup = 1;
M_Cluster = 1;
M_stim = [1];
% M_fish_set = [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2];

%%
M_param = 5:5:20%0.3:0.1:0.8;

ParamScores = cell(length(M_param),length(range_fish));
ParamScores_raw = cell(length(M_param),length(range_fish));

for k_param = 1:length(M_param),
    numK2 = M_param(k_param);
    %thres_split = M_param(k_param);
    %setappdata(hfig,'thres_split',thres_split);

    for k_fish = 1:length(range_fish),
        i_fish = range_fish(k_fish);
        disp(i_fish);
        LoadFullFish(hfig,i_fish);
        absIX = getappdata(hfig,'absIX');

        %% partitions for CV
        timelists = getappdata(hfig,'timelists');
        timelists_names = getappdata(hfig,'timelists_names');
        periods = getappdata(hfig,'periods');
        %if length(periods)>1,
            timelistsCV = cell(length(M_stim),2);
            for k_stim = 1:length(M_stim), % :3
                i_stim = M_stim(k_stim);
                TL = timelists{i_stim};
                period = periods(i_stim);
                nrep = size(TL,2)/periods(i_stim); % integer
                n = floor(nrep/2);
                timelistsCV{k_stim,1} = TL(1):TL(n*period);
                timelistsCV{k_stim,2} = TL(1+n*period):TL(2*n*period);
            end
        %end

        %% CV loop: auto-clustering with the partitions
        Score = zeros(length(M_stim),2);

        for k_stim = 1:length(M_stim), % :3
            i_stim = M_stim(k_stim);
            NumClus = zeros(1,2);
            CIX = cell(1,2);
            GIX = cell(1,2);
            for k = 1:2,
                %% Cluster to start auto-clustering
                i_ClusGroup = M_ClusGroup(k_fish);
                i_Cluster = M_Cluster(k_fish);
                ClusGroup = VAR(i_fish).ClusGroup{i_ClusGroup};
                numK = ClusGroup(i_Cluster).numK;
                gIX = ClusGroup(i_Cluster).gIX;
                cIX_abs = ClusGroup(i_Cluster).cIX_abs; % convert absolute index to index used for this dataset
                [~,cIX] = ismember(cIX_abs,absIX);

                % ~UpdateTimeIndex
                tIX = timelistsCV{k_stim,k};
                M_0 = GetTimeIndexedData_Default_Direct(hfig,cIX,tIX,'isAllCells');

                isWkmeans = 1;
                [cIX,gIX] = AutoClustering(cIX,gIX,absIX,i_fish,M_0,isWkmeans,numK2);

                NumClus(k) = length(unique(gIX));
                CIX{k} = cIX;
                GIX{k} = gIX;
            end
            % plot cell-matching figure
            Score(k_stim,1) = HungarianCV(NumClus(1),NumClus(2),CIX{1},CIX{2},GIX{1},GIX{2});
            Score(k_stim,2) = HungarianCV(NumClus(2),NumClus(1),CIX{2},CIX{1},GIX{2},GIX{1});
        end

        ParamScores{k_param,k_fish} = mean(mean(Score));
        ParamScores_raw{k_param,k_fish} = Score;
    end

end


classdef BackgroundSubtractorMOG2 < handle
    %BACKGROUNDSUBTRACTORMOG2  Gaussian Mixture-based Background/Foreground Segmentation Algorithm
    %
    % The class implements the Gaussian mixture model background subtraction
    % described in [Zivkovic2004] and [Zivkovic2006].
    %
    % The code is very fast and performs also shadow detection. Number of
    % Gausssian components is adapted per pixel.
    %
    % The algorithm similar to the standard Stauffer&Grimson algorithm with
    % additional selection of the number of the Gaussian components based on
    % [Zivkovic04recursiveunsupervised].
    %
    % ## References
    % [Zivkovic2004]:
    % > Zoran Zivkovic. "Improved adaptive gaussian mixture model for
    % > background subtraction". In Pattern Recognition, 2004. ICPR 2004.
    % > Proceedings of the 17th International Conference on, volume 2,
    % > pages 28-31. IEEE, 2004.
    % > [PDF](http://www.zoranz.net/Publications/zivkovic2004ICPR.pdf).
    %
    % [Zivkovic2006]:
    % > Zoran Zivkovic and Ferdinand van der Heijden. "Efficient adaptive
    % > density estimation per image pixel for the task of background
    % > subtraction". Pattern recognition letters, 27(7):773-780, 2006.
    % > [PDF](http://www.zoranz.net/Publications/zivkovicPRL2006.pdf).
    %
    % [Zivkovic04recursiveunsupervised]:
    % > Zoran Zivkovic and Ferdinand van der Heijden, "Recursive unsupervised
    % > learning of finite mixture models", IEEE Trans. on Pattern Analysis
    % > and Machine Intelligence, vol.26, no.5, pages 651-656, 2004.
    % > [PDF](http://www.zoranz.net/Publications/zivkovic2004PAMI.pdf).
    %
    % [Prati03detectingmoving]:
    % > Andrea Prati, Ivana Mikic, Mohan M. Trivedi, Rita Cucchiara.
    % > "Detecting Moving Shadows: Algorithms and Evaluation", IEEE PAMI, 2003.
    %
    % See also: cv.BackgroundSubtractorMOG2.BackgroundSubtractorMOG2,
    %  cv.BackgroundSubtractorMOG2.apply,
    %  cv.BackgroundSubtractorMOG2.getBackgroundImage,
    %  vision.ForegroundDetector
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    properties (Dependent)
        % The number of last frames that affect the background model.
        History
        % The number of gaussian components in the background model.
        % The model needs to be reinitalized to reserve memory.
        NMixtures
        % The "background ratio" parameter of the algorithm.
        % If a foreground pixel keeps semi-constant value for about
        % `BackgroundRatio * History` frames, it's considered background and
        % added to the model as a center of a new component. It corresponds to
        % `TB` parameter in the paper.
        BackgroundRatio
        % The variance threshold for the pixel-model match.
        % The main threshold on the squared Mahalanobis distance to decide if
        % the sample is well described by the background model or not. Related
        % to `Cthr` from the paper.
        VarThreshold
        % The variance threshold for the pixel-model match used for new
        % mixture component generation.
        % Threshold for the squared Mahalanobis distance that helps decide
        % when a sample is close to the existing components (corresponds to
        % `Tg` in the paper). If a pixel is not close to any component, it is
        % considered foreground or added as a new component.
        % `3 sigma => Tg=3*3=9` is default. A smaller `Tg` value generates
        % more components. A higher `Tg` value may result in a small number of
        % components but they can grow too large.
        VarThresholdGen
        % The initial variance of gaussian components. default 15
        VarInit
        % Minimmum variance. default 4
        VarMin
        % Maximum variance. default 5*15
        VarMax
        % The complexity reduction threshold.
        % This parameter defines the number of samples needed to accept to
        % prove the component exists. `CT=0.05` is a default value for all the
        % samples. By setting `CT=0` you get an algorithm very similar to the
        % standard Stauffer&Grimson algorithm.
        ComplexityReductionThreshold
        % The shadow detection flag.
        % If true, the algorithm detects shadows and marks them. See
        % cv.BackgroundSubtractorMOG2.BackgroundSubtractorMOG2 for details.
        DetectShadows
        % The shadow value.
        % Shadow value is the value used to mark shadows in the foreground
        % mask. Default value is 127. Value 0 in the mask always means
        % background, 255 means foreground.
        ShadowValue
        % The shadow threshold.
        % A shadow is detected if pixel is a darker version of the background.
        % The shadow threshold (Tau in the paper) is a threshold defining how
        % much darker the shadow can be. Tau=0.5 means that if a pixel is more
        % than twice darker then it is not shadow.
        % See [Prati03detectingmoving].
        ShadowThreshold
    end

    %% BackgroundSubtractor
    methods
        function this = BackgroundSubtractorMOG2(varargin)
            %BACKGROUNDSUBTRACTORMOG2  Creates MOG2 Background Subtractor
            %
            %     bs = cv.BackgroundSubtractorMOG2()
            %     bs = cv.BackgroundSubtractorMOG2('OptionName', optionValue, ...)
            %
            % ## Options
            % * __History__ Length of the history. default 500
            % * __VarThreshold__ Threshold on the squared Mahalanobis distance
            %   between the pixel and the model to decide whether a pixel is
            %   well described by the background model. This parameter does
            %   not affect the background update. default 16
            % * __DetectShadows__ If true, the algorithm will detect shadows
            %   and mark them. It decreases the speed a bit, so if you do not
            %   need this feature, set the parameter to false. default true
            %
            % See also: cv.BackgroundSubtractorMOG2
            %
            this.id = BackgroundSubtractorMOG2_(0, 'new', varargin{:});
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     bs.delete()
            %
            % See also: cv.BackgroundSubtractorMOG2
            %
            if isempty(this.id), return; end
            BackgroundSubtractorMOG2_(this.id, 'delete');
        end

        function fgmask = apply(this, im, varargin)
            %APPLY  Updates the background model and computes the foreground mask
            %
            %     fgmask = bs.apply(im)
            %     fgmask = bs.apply(im, 'OptionName', optionValue, ...)
            %
            % ## Input
            % * __im__ Next video frame, uint8 or single. Floating point frame
            %   will be used without scaling and should be in range [0,255].
            %
            % ## Output
            % * __fgmask__ The output foreground mask as an 8-bit binary image
            %   (0 for background, 255 for foregound, and `ShadowValue` for
            %   shadows if `DetectShadows` is true).
            %
            % ## Options
            % * __LearningRate__ The value between 0 and 1 that indicates how
            %   fast the background model is learnt. Negative parameter value
            %   makes the algorithm to use some automatically chosen learning
            %   rate. 0 means that the background model is not updated at all,
            %   1 means that the background model is completely reinitialized
            %   from the last frame. default -1
            %
            % See also: cv.BackgroundSubtractorMOG2.getBackgroundImage
            %
            fgmask = BackgroundSubtractorMOG2_(this.id, 'apply', im, varargin{:});
        end

        function bgImg = getBackgroundImage(this)
            %GETBACKGROUNDIMAGE  Computes a background image
            %
            %     bgImg = bs.getBackgroundImage()
            %
            % ## Output
            % * __bgImg__ The output background image, which is the mean of
            %   all background Gaussians.
            %
            % ### Note
            % Sometimes the background image can be very blurry, as it contain
            % the average background statistics.
            %
            % See also: cv.BackgroundSubtractorMOG2.apply
            %
            bgImg = BackgroundSubtractorMOG2_(this.id, 'getBackgroundImage');
        end
    end

    %% Algorithm
    methods (Hidden)
        function clear(this)
            %CLEAR  Clears the algorithm state
            %
            %     obj.clear()
            %
            % See also: cv.BackgroundSubtractorMOG2.empty
            %
            BackgroundSubtractorMOG2_(this.id, 'clear');
        end

        function b = empty(this)
            %EMPTY  Returns true if the algorithm is empty
            %
            %     b = obj.empty()
            %
            % ## Output
            % * __b__ Returns true if the algorithm is empty (e.g. in the very
            %   beginning or after unsuccessful read).
            %
            % See also: cv.BackgroundSubtractorMOG2.clear
            %
            b = BackgroundSubtractorMOG2_(this.id, 'empty');
        end

        function name = getDefaultName(this)
            %GETDEFAULTNAME  Returns the algorithm string identifier
            %
            %     name = obj.getDefaultName()
            %
            % ## Output
            % * __name__ This string is used as top level XML/YML node tag
            %   when the object is saved to a file or string.
            %
            % See also: cv.BackgroundSubtractorMOG2.save, cv.BackgroundSubtractorMOG2.load
            %
            name = BackgroundSubtractorMOG2_(this.id, 'getDefaultName');
        end

        function save(this, filename)
            %SAVE  Saves the algorithm to a file
            %
            %     obj.save(filename)
            %
            % ## Input
            % * __filename__ Name of the file to save to.
            %
            % This method stores the algorithm parameters in a file storage.
            %
            % See also: cv.BackgroundSubtractorMOG2.load
            %
            BackgroundSubtractorMOG2_(this.id, 'save', filename);
        end

        function load(this, fname_or_str, varargin)
            %LOAD  Loads algorithm from a file or a string
            %
            %     obj.load(fname)
            %     obj.load(str, 'FromString',true)
            %     obj.load(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __fname__ Name of the file to read.
            % * __str__ String containing the serialized model you want to
            %   load.
            %
            % ## Options
            % * __ObjName__ The optional name of the node to read (if empty,
            %   the first top-level node will be used). default empty
            % * __FromString__ Logical flag to indicate whether the input is a
            %   filename or a string containing the serialized model.
            %   default false
            %
            % This method reads algorithm parameters from a file storage.
            % The previous model state is discarded.
            %
            % See also: cv.BackgroundSubtractorMOG2.save
            %
            BackgroundSubtractorMOG2_(this.id, 'load', fname_or_str, varargin{:});
        end
    end

    %% Getters/Setters
    methods
        function value = get.History(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'History');
        end
        function set.History(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'History', value);
        end

        function value = get.NMixtures(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'NMixtures');
        end
        function set.NMixtures(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'NMixtures', value);
        end

        function value = get.BackgroundRatio(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'BackgroundRatio');
        end
        function set.BackgroundRatio(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'BackgroundRatio', value);
        end

        function value = get.VarThreshold(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'VarThreshold');
        end
        function set.VarThreshold(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'VarThreshold', value);
        end

        function value = get.VarThresholdGen(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'VarThresholdGen');
        end
        function set.VarThresholdGen(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'VarThresholdGen', value);
        end

        function value = get.VarInit(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'VarInit');
        end
        function set.VarInit(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'VarInit', value);
        end

        function value = get.VarMin(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'VarMin');
        end
        function set.VarMin(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'VarMin', value);
        end

        function value = get.VarMax(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'VarMax');
        end
        function set.VarMax(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'VarMax', value);
        end

        function value = get.ComplexityReductionThreshold(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'ComplexityReductionThreshold');
        end
        function set.ComplexityReductionThreshold(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'ComplexityReductionThreshold', value);
        end

        function value = get.DetectShadows(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'DetectShadows');
        end
        function set.DetectShadows(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'DetectShadows', value);
        end

        function value = get.ShadowValue(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'ShadowValue');
        end
        function set.ShadowValue(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'ShadowValue', value);
        end

        function value = get.ShadowThreshold(this)
            value = BackgroundSubtractorMOG2_(this.id, 'get', 'ShadowThreshold');
        end
        function set.ShadowThreshold(this, value)
            BackgroundSubtractorMOG2_(this.id, 'set', 'ShadowThreshold', value);
        end
    end

end


function [optimState,vp,gp,timer] = ...
    activesample_vbmc(optimState,Ns,funwrapper,vp,vp_old,gp,stats,timer,options)
%ACTIVESAMPLE_VBMC Actively sample points iteratively based on acquisition function.

NSsearch = options.NSsearch;    % Number of points for acquisition fcn
t_func = 0;

time_active = tic;

if isempty(gp)

    % No GP yet, just use provided points or sample from plausible box
    [optimState,t_func] = ...
        initdesign_vbmc(optimState,Ns,funwrapper,t_func,options);

else                    % Active uncertainty sampling

    % One or multiple acquisition functions (most commonly only one)
    SearchAcqFcn = options.SearchAcqFcn;

    % Use "hedge" strategy to propose an acquisition function? (unused)
    if options.AcqHedge && numel(SearchAcqFcn) > 1
        % Choose acquisition function via hedge strategy
        optimState.hedge = acqhedge_vbmc('acq',optimState.hedge,[],options);
        idxAcq = optimState.hedge.chosen;
    end

    % Compute time cost (used by some acquisition functions)
    if optimState.iter > 2
        deltaNeff = max(1,stats.Neff(optimState.iter-1) - stats.Neff(optimState.iter-2));
    else
        deltaNeff = stats.Neff(1);
    end
    timer_iter = stats.timer(optimState.iter-1);
    % t_base = timer_iter.activeSampling + timer_iter.variationalFit + timer_iter.finalize;
    gpTrain_vec = [stats.timer.gpTrain];

    if options.ActiveVariationalSamples > 0 % Unused
        options_activevar = options;
        options_activevar.TolWeight = 0;
        options_activevar.NSentFine = options.NSent;
        options_activevar.ELCBOmidpoint = false;
        Ns_activevar = options.ActiveVariationalSamples;
    end

    % Perform GP (and possibly variational) update after each active sample
    ActiveSampleFullUpdate_flag = ...
        (options.ActiveSampleVPUpdate || options.ActiveSampleGPUpdate) && ...
        (((optimState.iter - options.ActiveSampleFullUpdatePastWarmup) <= optimState.LastWarmup) ...
        || (stats.rindex(end) > options.ActiveSampleFullUpdateThreshold));

    if ActiveSampleFullUpdate_flag && Ns > 1
        % Temporarily change options for local updates

        RecomputeVarPost_old = optimState.RecomputeVarPost;
        entropy_alpha_old = optimState.entropy_alpha;

        % optimState.RecomputeVarPost = false;
        options_update = options;
        % options_update.GPRetrainThreshold = Inf;
        % options_update.GPSampleThin = 1;
        options_update.GPTolOpt = options.GPTolOptActive;
        options_update.GPTolOptMCMC = options.GPTolOptMCMCActive;
        options_update.TolWeight = 0;
        options_update.NSent = options.NSentActive;
        options_update.NSentFast = options.NSentFastActive;
        options_update.NSentFine = options.NSentFineActive;
%        options_update.ELCBOWeight = -options.OptimisticVariationalBound;

%        options_update.TolFunStochastic = 3*options.TolFunStochastic;
%        options_update.DetEntTolOpt = 3*options.DetEntTolOpt;
%        options_update.NSgpMaxMain = 3;
%        options_update.NSgpMaxWarmup = 3;
        hypstruct = [];
        vp0 = vp;
    end

    % if Ns > 1; vp_old = vp; end

    %% Active sampling loop (sequentially acquire Ns new points)
    for is = 1:Ns

        optimState.N = optimState.Xn;  % Number of training inputs
        optimState.Neff = sum(optimState.nevals(optimState.X_flag));

        if options.ActiveVariationalSamples > 0 % Unused
            [vp,~,output] = vpsample_vbmc(Ns_activevar,0,vp,gp,optimState,options_activevar,options.ScaleLowerBound);
            if isfield(output,'stepsize'); optimState.mcmc_stepsize = output.stepsize; end
%            output.stepsize
%            ELCBOWeight = sqrt(0.2*2*log(vp.D*optimState.Neff^2*pi^2/(6*0.1)));
%            options_temp.ELCBOWeight = -log(rand())*ELCBOWeight;
%            vp = vpoptimize_vbmc(0,1,vp,gp,vp.K,optimState,options_temp,0);
%            vbmc_iterplot(vp,gp,optimState,stats,stats.elbo(end));
%            vbmc_iterplot(vp_old,gp,optimState,stats,stats.elbo(end));
        end

        Nextra = evaloption_vbmc(options.SampleExtraVPMeans,vp.K);
        if Nextra > 0   % Unused
            vp_base = vp;
            NsFromGP = 4e3;
            Nextra = evaloption_vbmc(options.SampleExtraVPMeans,vp.K);
            gpbeta = -options.OptimisticVariationalBound;

            xrange = max(gp.X) - min(gp.X);
            LB_extra = min(gp.X) - 0.1*xrange; UB_extra = max(gp.X) + 0.1*xrange;
            if 0
                x0 = vbmc_rnd(vp,1,0);
                xx = gplite_sample(gp,NsFromGP,x0,[],[],gpbeta,Inf,[],[],[LB_extra;UB_extra]);
            elseif 0
                K = 2*(vp.D+1);
                x0 = vbmc_rnd(vp,K,0);
                xx = gplite_sample(gp,NsFromGP,x0,'parallel',[],gpbeta,Inf,[],[],[LB_extra;UB_extra]);
            else
                [X_hpd,y_hpd] = gethpd_vbmc(gp.X,gp.y,options.HPDFrac);
                Nextra = min(size(X_hpd,1),Nextra);
                xx = gp.X(randperm(size(X_hpd,1),Nextra),:);
                xx = gp.X;
                Nextra = size(xx,1);
            end
            OptimizeMu = vp.optimize_mu;
            OptimizeWeights = vp.optimize_weights;
            vp.optimize_mu = false;
            vp.optimize_weights = true;
            vp.K = vp.K + Nextra;
            vp.mu = [vp.mu,xx(round(linspace(1,size(xx,1),Nextra)),:)'];
            vp.sigma = [vp.sigma,exp(mean(log(vp.sigma)))*ones(1,Nextra)];
            vp.w = [vp.w,exp(mean(log(vp.w)))*ones(1,Nextra)];
            vp.w = vp.w(:)'/sum(vp.w);
            options_vp = options;
            options_vp.NSent = 0;
            options_vp.NSentFast = 0;
            options_vp.NSentFine = 0;
            options_vp.TolWeight = 0;
%            options_vp.ELCBOWeight = 0;
%            vp2 = vpoptimize_vbmc(0,1,vp,gp,[],optimState,options_vp,0);
%            xrnd = vbmc_rnd(vp2,1e5); cornerplot(xrnd);
            options_vp.ELCBOWeight = -options.OptimisticVariationalBound;
            vp = vpoptimize_vbmc(0,1,vp,gp,[],optimState,options_vp,0);
%            xrnd = vbmc_rnd(vp,1e5); cornerplot(xrnd);
            vp.optimize_mu = OptimizeMu;
            vp.optimize_weights = OptimizeWeights;
        end

        if ~options.AcqHedge
            % If multiple acquisition functions are provided and not
            % following a "hedge" strategy, pick one at random
            idxAcq = randi(numel(SearchAcqFcn));
        end

        %% Pre-computations for acquisition functions

        % Re-evaluate variance of the log joint if requested
        if isfield(optimState.acqInfo{idxAcq},'compute_varlogjoint') ...
                && optimState.acqInfo{idxAcq}.compute_varlogjoint
            [~,~,varF] = gplogjoint(vp,gp,0,0,0,1);
            optimState.varlogjoint_samples = varF;
        end

        % Evaluate noise at each training point
        Ns_gp = numel(gp.post);
        sn2new = zeros(size(gp.X,1),Ns_gp);
        for s = 1:Ns_gp
            hyp_noise = gp.post(s).hyp(gp.Ncov+1:gp.Ncov+gp.Nnoise); % Get noise hyperparameters
            if isfield(optimState,'S')
                s2 = (optimState.S(optimState.X_flag).^2).*optimState.nevals(optimState.X_flag);
            else
                s2 = [];
            end
            if options.NoiseShaping
                s2 = noiseshaping_vbmc(s2,gp.y,options);
            end
            sn2new(:,s) = gplite_noisefun(hyp_noise,gp.X,gp.noisefun,gp.y,s2);
        end
        gp.sn2new = mean(sn2new,2);

        % Evaluate GP input length scale (use geometric mean)
        D = size(gp.X,2);
        ln_ell = zeros(D,Ns_gp);
        for s = 1:Ns_gp; ln_ell(:,s) = gp.post(s).hyp(1:D); end
        optimState.gplengthscale = exp(mean(ln_ell,2))';

        % Rescale GP training inputs by GP length scale
        gp.X_rescaled = bsxfun(@rdivide,gp.X,optimState.gplengthscale);

        % Algorithmic time per iteration (from last iteration)
        t_base = timer_iter.activeSampling + timer_iter.variationalFit + timer_iter.finalize + timer_iter.gpTrain;

        % Estimated increase in cost for a new training input
        if optimState.iter > 3
            len = 10;
            xx = log(stats.N(max(end-len,ceil(end/2)):end));
            yy = log(gpTrain_vec(max(end-len,ceil(end/2)):end));
            if numel(unique(xx)) > 1
                p = polyfit(xx,yy,1);
                gpTrain_diff = diff(exp(polyval(p,log([stats.N(end),stats.N(end)+1]))));
            else
                gpTrain_diff = 0;
            end
        else
            gpTrain_diff = 0;
        end

        % Algorithmic cost per function evaluation
        optimState.t_algoperfuneval = t_base/deltaNeff + max(0,gpTrain_diff);
        % [t_base/deltaNeff,gpTrain_diff]

        % Prepare for importance sampling based acquisition function
        if isfield(optimState.acqInfo{idxAcq},'importance_sampling') ...
                && optimState.acqInfo{idxAcq}.importance_sampling
            optimState.ActiveImportanceSampling = activeimportancesampling_vbmc(vp,gp,SearchAcqFcn{idxAcq},optimState.acqInfo{idxAcq},options);
        end

        %% Start active search

        optimState.acqrand = rand();    % Seed for random acquisition fcn

        % Create fast search set from cache and randomly generated
        [Xsearch,idx_cache] = getSearchPoints(NSsearch,optimState,vp,gp,options);
        Xsearch = real2int_vbmc(Xsearch,vp.trinfo,optimState.integervars);

%        acqEval = @(Xs_,vp_,gp_,optimState_,transpose_flag_) ...
%            SearchAcqFcn{idxAcq}(Xs_,vp_,gp_,optimState_,transpose_flag_);
        acqEval = @(Xs_,vp_,gp_,optimState_,transpose_flag_) ...
            acqwrapper_vbmc(Xs_,vp_,gp_,optimState_,transpose_flag_,...
            SearchAcqFcn{idxAcq},optimState.acqInfo{idxAcq});

        % Evaluate acquisition function
        acq_fast = acqEval(Xsearch,vp,gp,optimState,0);

        if options.SearchCacheFrac > 0
            [~,ord] = sort(acq_fast,'ascend');
            optimState.SearchCache = Xsearch(ord,:);
            idx = ord(1);
        else
            [~,idx] = min(acq_fast);
        end
        % idx/numel(acq_fast)
        Xacq = Xsearch(idx,:);
        idx_cache_acq = idx_cache(idx);

        % Remove selected points from search set
        Xsearch(idx,:) = []; idx_cache(idx) = [];
        % [size(Xacq,1),size(Xacq2,1)]

        % Additional search via optimization
        if ~strcmpi(options.SearchOptimizer,'none')
            fval_old = acqEval(Xacq(1,:),vp,gp,optimState,0);
            x0 = real2int_vbmc(Xacq(1,:),vp.trinfo,optimState.integervars);
            if all(isfinite([optimState.LB_search,optimState.UB_search]))
                LB = min([x0;optimState.LB_search]);
                UB = max([x0;optimState.UB_search]);
            else
                xrange = max(gp.X) - min(gp.X);
                LB = min([gp.X;x0]) - 0.1*xrange; UB = max([gp.X;x0]) + 0.1*xrange;
            end

            if isfield(optimState.acqInfo{idxAcq},'log_flag') ...
                    && optimState.acqInfo{idxAcq}.log_flag
                TolFun = 1e-2;
            else
                TolFun = max(1e-12,abs(fval_old*1e-3));
            end

            try
                switch lower(options.SearchOptimizer)
                    case 'cmaes'
                        if options.SearchCMAESVPInit
                            [~,Sigma] = vbmc_moments(vp,0);
                            %[~,idx_nearest] = min(sum(bsxfun(@minus,vp.mu,x0(:)).^2,1));
                            %Sigma = diag(vp.sigma(idx_nearest)^2.*vp.lambda.^2);
                        else
                            X_hpd = gethpd_vbmc(gp.X,gp.y,options.HPDFrac);
                            Sigma = cov(X_hpd,1);
                        end
                        insigma = sqrt(diag(Sigma));
                        cmaes_opts = options.CMAESopts;
                        cmaes_opts.TolFun = TolFun;
                        cmaes_opts.MaxFunEvals = options.SearchMaxFunEvals;
                        cmaes_opts.LBounds = LB(:);
                        cmaes_opts.UBounds = UB(:);
%                        [xsearch_optim,fval_optim,~,~,out_optim,bestever] = cmaes_modded(func2str(SearchAcqFcn{idxAcq}),x0(:),insigma,cmaes_opts,vp,gp,optimState,1);
                        [xsearch_optim,fval_optim,~,~,out_optim,bestever] = ...
                            cmaes_modded('acqwrapper_vbmc',x0(:),insigma,cmaes_opts,vp,gp,optimState,1,SearchAcqFcn{idxAcq},optimState.acqInfo{idxAcq});
                        nevals = out_optim.evals;
                        if options.SearchCMAESbest
                            xsearch_optim = bestever.x;
                            fval_optim = bestever.f;
                        end
                        % out_optim.evals
                        xsearch_optim = xsearch_optim';
                    case 'fmincon'
                        fmincon_opts.Display = 'off';
                        fmincon_opts.TolFun = TolFun;
                        fmincon_opts.MaxFunEvals = options.SearchMaxFunEvals;
                        [xsearch_optim,fval_optim,~,out_optim] = fmincon(@(x) acqEval(x,vp,gp,optimState,0),x0,[],[],[],[],LB,UB,[],fmincon_opts);
                        nevals = out_optim.funcCount;
                        % out_optim
                    case 'bads'
                        bads_opts.Display = 'off';
                        bads_opts.TolFun = TolFun;
                        bads_opts.MaxFunEvals = options.SearchMaxFunEvals;
                        [xsearch_optim,fval_optim,~,out_optim] = bads(@(x) acqEval(x,vp,gp,optimState,0),x0,LB,UB,LB,UB,[],bads_opts);
                    case 'slicesample'
                        samplefun = @(x) -acqEval(x,vp,gp,optimState,0);
                        sampleopts.Thin = 1;
                        sampleopts.Burnin = 10+D;
                        sampleopts.Display = 'off';
                        sampleopts.Diagnostics = false;
                        Widths = (UB - LB)/sqrt(12);
                        [xsearch_optim,fval_optim,~,out_optim] = ...
                            slicesamplebnd(samplefun,x0,1,Widths,LB,UB,sampleopts);
                        [x0;xsearch_optim]

                    otherwise
                        error('vbmc:UnknownOptimizer','Unknown acquisition function search optimization method.');
                end
            catch
                fprintf('Active search failed.\n');
                fval_optim = Inf;
            end

            % [fval_old, fval_optim,nevals]

            if fval_optim < fval_old
                Xacq(1,:) = real2int_vbmc(xsearch_optim,vp.trinfo,optimState.integervars);
                idx_cache_acq(1) = 0;
                % idx_cache = [idx_cache(:); 0];
                % Double check if the cache indexing is correct
            end
        end

        % [acq,tr_p] = acqEval(Xacq(1,:),vp,gp,optimState,0)

        if options.UncertaintyHandling && options.MaxRepeatedObservations > 0
            if optimState.RepeatedObservationsStreak >= options.MaxRepeatedObservations
                % Maximum number of consecutive repeated observations
                % (to prevent getting stuck in a wrong belief state)
                optimState.RepeatedObservationsStreak = 0;
            else
                % Re-evaluate acquisition function on training set
                X_train = get_traindata_vbmc(optimState,options);

                % Disable variance-based regularization first
                oldflag = optimState.VarianceRegularizedAcqFcn;
                optimState.VarianceRegularizedAcqFcn = false;
                % Use current cost of GP instead of future cost
                old_t_algoperfuneval = optimState.t_algoperfuneval;
                optimState.t_algoperfuneval = t_base/deltaNeff;
                acq_train = acqEval(X_train,vp,gp,optimState,0);
                optimState.VarianceRegularizedAcqFcn = oldflag;
                optimState.t_algoperfuneval = old_t_algoperfuneval;
                [acq_train,idx_train] = min(acq_train);

                acq_now = acqEval(Xacq(1,:),vp,gp,optimState,0);

                % [acq_train,acq_now]

                if acq_train < options.RepeatedAcqDiscount*acq_now
                    Xacq(1,:) = X_train(idx_train,:);
                    optimState.RepeatedObservationsStreak = optimState.RepeatedObservationsStreak + 1;
                else
                    optimState.RepeatedObservationsStreak = 0;
                end
            end
        end

        y_orig = [NaN; optimState.Cache.y_orig(:)]; % First position is NaN (not from cache)
        yacq = y_orig(idx_cache_acq+1);
        idx_nn = ~isnan(yacq);
        if any(idx_nn)
            yacq(idx_nn) = yacq(idx_nn) + warpvars_vbmc(Xacq(idx_nn,:),'logp',optimState.trinfo);
        end

        xnew = Xacq(1,:);
        idxnew = 1;

        % See if chosen point comes from starting cache
        idx = idx_cache_acq(idxnew);
        if idx > 0; y_orig = optimState.Cache.y_orig(idx); else; y_orig = NaN; end
        timer_func = tic;
        if isnan(y_orig)    % Function value is not available, evaluate
            try
                [ynew,optimState,idx_new] = funlogger_vbmc(funwrapper,xnew,optimState,'iter');
            catch func_error
                % pause
            end
        else
            [ynew,optimState,idx_new] = funlogger_vbmc(funwrapper,xnew,optimState,'add',y_orig);
            % Remove point from starting cache
            optimState.Cache.X_orig(idx,:) = [];
            optimState.Cache.y_orig(idx) = [];
        end
        t_func = t_func + toc(timer_func);

        % ynew = outputwarp(ynew,optimState,options);
        if isfield(optimState,'S')
            s2new = optimState.S(idx_new)^2;
        else
            s2new = [];
        end
        tnew = optimState.funevaltime(idx_new);

        if 1
            % Store acquisition information (mostly for debug)
            if ~isfield(optimState,'acqtable'); optimState.acqtable = []; end
            [~,~,fmu,fs2] = gplite_pred(gp,xnew);
            v = [idxAcq,ynew,fmu,sqrt(fs2)];
            optimState.acqtable = [optimState.acqtable; v];
        end

        if Nextra > 0
            vp = vp_base;
        end

        if is < Ns
            % If not the last sample, update GP and possibly other things
            % (no need perform updates after the last sample)

%             w_orig = optimState.UB_orig - optimState.LB_orig;
%             x_min = warpvars_vbmc(optimState.LB_orig + 1e-6*w_orig,'d',vp.trinfo);
%             x_max = warpvars_vbmc(optimState.UB_orig - 1e-6*w_orig,'d',vp.trinfo);
%             if is == 1
%                 [optimState.LB_search;x_min]
%                 [optimState.UB_search;x_max]
%             end
%             optimState.LB_search = max(optimState.LB_search,x_min);
%             optimState.UB_search = min(optimState.UB_search,x_max);

            if ActiveSampleFullUpdate_flag
                % If performing full updates with active sampling, the GP
                % hyperparameters are updated after each acquisition

                % Quick GP update
                if isempty(hypstruct); hypstruct = optimState.hypstruct; end

                fESS_thresh = options.ActiveSamplefESSThresh;
                gptmp = [];
                if fESS_thresh < 1
                    gptmp = gpreupdate(gp,optimState,options);
                    fESS = fess_vbmc(vp,gptmp,100);
                else
                    fESS = 0;
                end

                if fESS <= fESS_thresh
                    if options.ActiveSampleGPUpdate
                        t = tic;
                        [gp,hypstruct,Ns_gp,optimState] = ...
                            gptrain_vbmc(hypstruct,optimState,stats,options_update);
                        timer.gpTrain = timer.gpTrain + toc(t);
                    else
                        if isempty(gptmp)
                            gp = gpreupdate(gp,optimState,options);
                        else
                            gp = gptmp;
                        end
                    end

                    if options.ActiveSampleVPUpdate
                        % Quick variational optimization
                        t = tic;
                        % Decide number of fast optimizations
                        Nfastopts = ceil(options_update.NSelboIncr * evaloption_vbmc(options_update.NSelbo,vp.K));
                        if options.UpdateRandomAlpha
                            optimState.entropy_alpha = 1 - sqrt(rand());
                        end
                        vp = vpoptimize_vbmc(Nfastopts,1,vp,gp,[],optimState,options_update,0);
                        optimState.vp_repo{end+1} = get_vptheta(vp);
                        timer.variationalFit = timer.variationalFit + toc(t);
                    end
                else
                    gp = gptmp;
                end

            else
                % If NOT performing full updates with active sampling, only
                % the GP posterior is updated (but not the hyperparameters)

                % Perform simple rank-1 update if no noise and first sample
                t = tic;
                update1 = (isempty(s2new) || optimState.nevals(idx_new) == 1) && ~options.NoiseShaping;
                if update1
                    gp = gplite_post(gp,xnew,ynew,[],[],[],s2new,1);
                    gp.t(end+1) = tnew;
                else
                    gp = gpreupdate(gp,optimState,options);
                end
                timer.gpTrain = timer.gpTrain + toc(t);
            end
        end

        % Check if active search bounds need to be expanded
        delta_search = 0.05*(optimState.UB_search - optimState.LB_search);

        % ADD DIFFERENT CHECKS FOR INTEGER VARIABLES!
        idx = abs(xnew - optimState.LB_search) < delta_search;
        optimState.LB_search(idx) = max(optimState.LB(idx), ...
            optimState.LB_search(idx) - delta_search(idx));
        idx = abs(xnew - optimState.UB_search) < delta_search;
        optimState.UB_search(idx) = min(optimState.UB(idx), ...
            optimState.UB_search(idx) + delta_search(idx));

        % Hard lower/upper bounds on search
        prange = optimState.PUB - optimState.PLB;
        LB_searchmin = max(optimState.PLB - 2*prange*options.ActiveSearchBound,optimState.LB);
        UB_searchmin = min(optimState.PUB + 2*prange*options.ActiveSearchBound,optimState.UB);
%         optimState.LB_search = max(optimState.LB_search,LB_searchmin);
%         optimState.UB_search = min(optimState.UB_search,UB_searchmin);

        % [[optimState.LB_search, min(gp.X)]; [optimState.UB_search, max(gp.X)]]

    end

    if ActiveSampleFullUpdate_flag && Ns > 1
        % Reset OPTIMSTATE
        optimState.RecomputeVarPost = RecomputeVarPost_old;
        optimState.entropy_alpha = entropy_alpha_old;
        optimState.hypstruct = hypstruct;

        % If variational posterior has changed, check if old variational
        % posterior is better than current
        theta0 = get_vptheta(vp0);
        theta = get_vptheta(vp);
        if numel(theta0) ~= numel(theta) || any(theta0 ~= theta)
            NSentFineK = ceil(evaloption_vbmc(options.NSentFineActive,vp0.K)/vp0.K);
            elbo0 = -negelcbo_vbmc(theta0,0,vp0,gp,NSentFineK,0,1);
            if elbo0 > vp.stats.elbo(end); vp = vp0; end
            % [elbo0,vp.stats.elbo]
        end
    end
end

timer.activeSampling = timer.activeSampling + toc(time_active) ...
    - t_func - timer.gpTrain - timer.variationalFit;
timer.funEvals = timer.funEvals + t_func;

% Remove temporary fields (unnecessary here because GP is not returned)
% if isfield(gp,'sn2new'); gp = rmfield(gp,'sn2new'); end
% if isfield(gp,'X_rescaled'); gp = rmfield(gp,'X_rescaled'); end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [Xsearch,idx_cache] = getSearchPoints(NSsearch,optimState,vp,gp,options)
%GETSEARCHPOINTS Get search points from starting cache or randomly generated.

% Take some points from starting cache, if not empty
x0 = optimState.Cache.X_orig;

if ~isempty(x0)
    cacheFrac = options.CacheFrac;  % Fraction of points from cache (if nonempty)
    Ncache = ceil(NSsearch*cacheFrac);
    idx_cache = randperm(size(x0,1),min(Ncache,size(x0,1)));
    Xsearch = warpvars_vbmc(x0(idx_cache,:),'d',optimState.trinfo);
else
    Xsearch = []; idx_cache = [];
end

% Randomly sample remaining points
if size(Xsearch,1) < NSsearch
    Nrnd = NSsearch-size(Xsearch,1);

    Xrnd = [];
    Nsearchcache = round(options.SearchCacheFrac*Nrnd);
    if Nsearchcache > 0 % Take points from search cache
        Xrnd = [Xrnd; optimState.SearchCache(1:min(end,Nsearchcache),:)];
    end
    Nheavy = round(options.HeavyTailSearchFrac*Nrnd);
    if Nheavy > 0
        Xrnd = [Xrnd; vbmc_rnd(vp,Nheavy,0,1,3)];
    end
    Nmvn = round(options.MVNSearchFrac*Nrnd);
    if Nmvn > 0
        [mubar,Sigmabar] = vbmc_moments(vp,0);
        Xrnd = [Xrnd; mvnrnd(mubar,Sigmabar,Nmvn)];
    end
    Nhpd = round(options.HPDSearchFrac*Nrnd);
    if Nhpd > 0
        hpd_min = options.HPDFrac/8;
        hpd_max = options.HPDFrac;
        hpdfracs = sort([rand(1,4)*(hpd_max-hpd_min) + hpd_min,hpd_min,hpd_max]);
        Nhpd_vec = diff(round(linspace(0,Nhpd,numel(hpdfracs)+1)));
        X = optimState.X(optimState.X_flag,:);
        y = optimState.y(optimState.X_flag);
        D = size(X,2);
        for ii = 1:numel(hpdfracs)
            if Nhpd_vec(ii) == 0; continue; end
            X_hpd = gethpd_vbmc(X,y,hpdfracs(ii));
            if isempty(X_hpd)
                [~,idxmax] = max(y);
                mubar = X(idxmax,:);
                Sigmabar = cov(X);
            else
                mubar = mean(X_hpd,1);
                Sigmabar = cov(X_hpd,1);
            end
            if isscalar(Sigmabar); Sigmabar = Sigmabar*ones(D,D); end
            %[~,idxmax] = max(y);
            %x0 = optimState.X(idxmax,:);
            %[Sigmabar,mubar] = covcma(X,y,x0,[],hpdfracs(ii));
            Xrnd = [Xrnd; mvnrnd(mubar,Sigmabar,Nhpd_vec(ii))];
        end
    end
    Nbox = round(options.BoxSearchFrac*Nrnd);
    if Nbox > 0
        X = optimState.X(optimState.X_flag,:);
        D = size(X,2);
        X_diam = max(X) - min(X);
        plb = optimState.PLB;
        pub = optimState.PUB;
        if all(isfinite([optimState.LB_search,optimState.UB_search]))
            box_lb = optimState.LB_search;
            box_ub = optimState.UB_search;
            box_lb = max(min(X) - 0.5*X_diam,box_lb);
            box_ub = min(max(X) + 0.5*X_diam,box_ub);
        else
            box_lb = plb - 3*(pub - plb);
            box_ub = pub + 3*(pub - plb);
            box_lb = max(min(X) - 0.5*X_diam,box_lb);
            box_ub = min(max(X) + 0.5*X_diam,box_ub);
        end
        Xrnd = [Xrnd; ...
            bsxfun(@plus,bsxfun(@times,rand(Nbox,D),box_ub-box_lb),box_lb)];
    end

    Nvp = max(0,Nrnd-Nsearchcache-Nheavy-Nmvn-Nhpd-Nbox);
    if Nvp > 0
        Xrnd = [Xrnd; vbmc_rnd(vp,Nvp,0,1)];
    end

    Xsearch = [Xsearch; Xrnd];
    idx_cache = [idx_cache(:); zeros(Nrnd,1)];
end

% Apply search bounds
Xsearch = bsxfun(@min,bsxfun(@max,Xsearch,optimState.LB_search),optimState.UB_search);

end


classdef IN1KMOP7 < EvoXBenchProblem
% <multi> <real> <large/none> <expensive/none>

%------------------------------- Reference --------------------------------
% Z. Lu, R. Cheng, Y. Jin, K. C. Tan, and K. Deb, Neural architecture
% search as multiobjective optimization benchmarks: Problem formulation and
% performance assessment, IEEE Transactions on Evolutionary Computation,
% 2023.
%--------------------------------------------------------------------------

    methods
        %% Default settings of the problem
        function Setting(obj)
            config.name = 'mnv3';
            config.args.objs = 'err&params';
            config.args.normalized_objectives = false;
            obj.Setting@EvoXBenchProblem(config);
        end
    end
end


function prob = mosekProb(H,f,A,rl,ru,Q,l,qrl,qru,lb,ub,xint,sdcone,x0,opts)
%MOSEKPROB  From general inputs check then build MOSEK problem
%
%   prob = mosekProb(H,f,A,rl,ru,Q,l,qrl,qru,lb,ub,xint,sdcone,x0,opts)

%   This function is based in parts on examples from the MOSEK Toolbox,
%   Copyright (c) 1998-2011 MOSEK ApS, Denmark.

%   Copyright (C) 2012 Jonathan Currie (IPL)

%Get warning status
warn = strcmpi(opts.warnings,'all');

%Get sizes
ndec = length(f);
[nlin,Ad] = size(A);

%Error checks
if(~isempty(H))
    [r1,c1] = size(H);
    if(r1 ~= ndec || c1 ~= ndec), error('H is the wrong size, expected %d x %d',ndec,ndec); end
    %Symmetry check is done in OPTI, won't repeat here
end
if(isempty(f)), error('You must supply the f vector to a MOSEK problem!'); end
if(xor(isempty(A),isempty(rl)) || xor(isempty(A),isempty(ru))), error('You must supply A + rl + ru for linear constraints'); end
if(~isempty(A))
    if(Ad ~= ndec), error('A is the wrong size, expected %d x %d',nineq,ndec); end
    if(nlin ~= length(rl)), error('The sizes of A and rl do not correspond'); end
    if(nlin ~= length(ru)), error('The sizes of A and ru do not correspond'); end
end
if(~isempty(lb) && length(lb) ~= ndec), error('lb is the wrong length, expected %d x 1',ndec); end
if(~isempty(ub) && length(ub) ~= ndec), error('ub is the wrong length, expected %d x 1',ndec); end
if(~isempty(xint))
    if(length(xint) ~= ndec), error('xint is the wrong length, expected %d x 1',ndec); end
    if(~ischar(xint)), error('xint should be a char array with characters ''C'', ''I'' or ''B'''); end
end
if(~isempty(x0) && length(x0) ~= ndec), error('x0 is the wrong length, expected %d x 1',ndec); end

%Quadratic Objective
if(~isempty(H))
    if(~issparse(H))
        if(warn)
            optiwarn('mosek:sparse','The H matrix should be sparse, correcting: [sparse(H)]');
        end
        [prob.qosubi,prob.qosubj,prob.qoval] = find(sparse(tril(H)));
    else
        [prob.qosubi,prob.qosubj,prob.qoval] = find(tril(H));
    end
end

%Linear Objective (if not sd)
if(isempty(sdcone))
    prob.c = f;
else
    prob.c = zeros(size(f));
end

%Linear constraints
prob.a = A;
if(isempty(prob.a))
    prob.a = sparse(0,length(f));
elseif(~issparse(prob.a))
    if(warn)
        optiwarn('mosek:sparse','The A matrix should be sparse, correcting: [sparse(A)]');
    end
    prob.a = sparse(prob.a);
end
if(size(f,2) > 1), f = f'; end
if(size(rl,2) > 1), rl = rl'; end
if(size(ru,2) > 1), ru = ru'; end
prob.blc = rl;
prob.buc = ru;

%Quadratic constraints
if(~isempty(Q))
    prob = genQC(prob,Q,l,qrl,qru,warn);
end

%Semidefinite Constraints
if(~isempty(sdcone))
    prob = genSDCONE(prob,f,sdcone);
end

%Integer variables
if(~isempty(xint))
    xint = lower(xint); [r,c] = size(xint);
    if(r > c), xint = xint'; end
    cind = strfind(xint,'c');
    bind = strfind(xint,'b');
    iind = strfind(xint,'i');
    if(length([cind bind iind]) ~= ndec) %double check no other chars
        error('xint should be a char array with characters ''C'', ''I'' or ''B''');
    end
    %Only need to setup if integer vars exist
    if(~isempty(bind) || ~isempty(iind))
        prob.ints.sub = sort([bind iind]); %sorted indices of all binary and integer vars
        %If binary, need to setup binary bounds
        if(~isempty(bind))
            if(isempty(lb)), lb = -Inf(size(f)); end %create false bounds if required
            lb(bind) = 0;
            if(isempty(ub)), ub = Inf(size(f)); end %create false bounds if required
            ub(bind) = 1;
        end
    end
end

%Bounds (note must be done after binary stuff above)
prob.blx = lb;
prob.bux = ub;

%Initial guess
if(~isempty(x0))
    if(isfield(prob,'ints'))
        prob.sol.int.xx = x0;
    else
        prob.sol.itr.xx = x0;
    end
end

%Determine problem type
if(isempty(H)) %linear or sdp
    if(isempty(xint))
        if(isempty(sdcone))
            prob.names.name = 'OPTI MOSEK LP Problem';
        else
            prob.names.name = 'OPTI MOSEK SDP Problem';
        end
    elseif(all(lower(xint) == 'b'))
        prob.names.name = 'OPTI MOSEK BILP Problem';
    else
        prob.names.name = 'OPTI MOSEK MILP Problem';
    end
else %quadratic
    if(isempty(Q))
        if(isempty(xint))
            prob.names.name = 'OPTI MOSEK QP Problem';
        else
            prob.names.name = 'OPTI MOSEK MIQP Problem';
        end
    else %quadratically constrained
        if(isempty(xint))
            prob.names.name = 'OPTI MOSEK QCQP Problem';
        else
            prob.names.name = 'OPTI MOSEK MIQCQP Problem';
        end
    end
end

function prob = genQC(prob,Q,l,qrl,qru,warn)
%Generate MOSEK quadratic constraints

%Create default fields
prob.qcsubi = [];
prob.qcsubj = [];
prob.qcsubk = [];
prob.qcval = [];

ndec = length(prob.c);

%Error checks
if(~isempty(Q))
    if(isempty(l) || isempty(qrl) || isempty(qru))
        error('You must supply Q, l, qrl and qru for quadratic constraints');
    end
end

%Process cell by cell
if(iscell(Q))
   if(iscell(l) || iscell(qrl) || iscell(qru))
       error('Only Quadratic Constraints Q may be a cell!');
   end
   %Check overall sizes
   [r0,c0] = size(Q);
   [r1,c1] = size(l);
   [r2,c2] = size(qrl);
   [r3,c3] = size(qru);
   if(r0 > c0)
       Q = Q';
       [~,c0] = size(Q);
   end
   if(r1 ~= c1) %not square
       if(r1 == c0)
           l = l';
           c1 = size(l,2);
       end
   end
   if(r2 > c2)
       qrl = qrl';
       [~,c2] = size(qrl);
   end
   if(r3 > c3)
       qru = qru';
       [~,c3] = size(qru);
   end
   if(c0 ~= c1 || c0 ~= c2 || c0 ~= c3)
       error('Quadratic Constraints Q + l + qrl + qru are not the same length!');
   end
   %For each cell
   for i = 1:c2
        Qt = Q{i};
        lt = l(:,i);
        rlt = qrl(i);
        rut = qru(i);
        %Error Check
        checkQC(Qt,lt,rlt,rut,ndec,sprintf('in cell %d',i),sprintf('in column %d',i));
        %Check sparsity
        if(~issparse(Qt))
            if(warn)
                optiwarn('mosek:sparse','The Q matrix in cell %d should be sparse, correcting: [sparse(Q)]',i);
            end
            Qt = sparse(Qt);
        end
        %Build structure fields
        [qcsubi,qcsubj,qcval] = find(tril(Qt));
        qcval = 2*qcval; %MOSEK includes 1/2x'Qx
        %Concatenate to original vectors
        prob.qcsubi = [prob.qcsubi; qcsubi];
        prob.qcsubj = [prob.qcsubj; qcsubj];
        prob.qcval = [prob.qcval; qcval];
        %Insert linear part into a matrix
        prob = insertQClin(prob,lt,rlt,rut,length(qcval));
   end
else  %Single Quadratic Constraint
    if(size(l,2) > size(l,1))
        l = l';
    end
    %Error Check
    checkQC(Q,l,qrl,qru,ndec,'','');
    %Check sparsity
    if(~issparse(Q))
        if(warn)
            optiwarn('mosek:sparse','The Q matrix should be sparse, correcting: [sparse(Q)]');
        end
        Q = sparse(Q);
    end
    %Build structure fields
    [prob.qcsubi,prob.qcsubj,prob.qcval] = find(tril(Q));
    prob.qcval = 2*prob.qcval; %MOSEK includes 1/2x'Qx
    %Insert linear part into a matrix
    prob = insertQClin(prob,l,qrl,qru,length(prob.qcval));
end

function prob = genSDCONE(prob,f,sdcone)
%Generate MOSEK semidefinite constraints
if(~iscell(sdcone)), sdcone = {sdcone}; end
ndec = length(f);
%Create default fields
prob.bardim    = [];
prob.barc.subj = []; %which cone
prob.barc.subk = []; %row
prob.barc.subl = []; %col
prob.barc.val  = [];
prob.bara.subi = []; %which A matrix
prob.bara.subj = []; %which cone
prob.bara.subk = []; %row
prob.bara.subl = []; %col
prob.bara.val  = [];

%For each sdcone
for i = 1:length(sdcone)
    dim = chkSDDim(sdcone{i},ndec,i);
    %Extract C, enter
    prob.bardim = [prob.bardim dim];
    [ci,cj,cv] = find(tril(reshape(sdcone{i}(:,1),dim,dim)));
    prob.barc.subj = [prob.barc.subj repmat(i,1,length(ci))];
    prob.barc.subk = [prob.barc.subk ci'];
    prob.barc.subl = [prob.barc.subl cj'];
    prob.barc.val = [prob.barc.val -cv'];
    %For each A, enter
    for j = 1:ndec
        [ai,aj,av] = find(tril(reshape(sdcone{i}(:,j+1),dim,dim)));
        prob.bara.subi = [prob.bara.subi repmat(j,1,length(ai))];
        prob.bara.subj = [prob.bara.subj repmat(i,1,length(ai))];
        prob.bara.subk = [prob.bara.subk ai'];
        prob.bara.subl = [prob.bara.subl aj'];
        prob.bara.val = [prob.bara.val av'];
    end
end
%Modify a
prob.a = [prob.a; sparse(ndec,ndec)];
%Set bounds
prob.blc = [prob.blc;f];
prob.buc = [prob.buc;f];

function checkQC(Q,l,qrl,qru,ndec,msgC,msgV)
%Complete QC checks
if((ndec ~= size(Q,1)) || (ndec ~= size(Q,2)))
    error('Constraint Q matrix %s is the wrong size! Expected %d x %d',msgC,ndec,ndec);
end
if(ndec ~= size(l,1))
   error('Constraint l vector %s is the wrong size! Expected %d x 1',msgV,ndec);
end
if(~isscalar(qrl))
   error('Constraint qrl %s is the wrong size! Expected 1 x 1 ',msgV);
end
if(~isscalar(qru))
   error('Constraint qru %s is the wrong size! Expected 1 x 1 ',msgV);
end
try
    e = eig(Q);
catch
    e = eigs(Q);
end
if(any(e < 0))
   error('Constraint Q matrix %s is not positive semidefinite!',msgC);
end
if(all(e == 0))
   error('Constraint Q matrix %s is indefinite!',msgC);
end
sym = abs(tril(Q,-1)-triu(Q,1)') > 1e-9; %tol may need to be adjusted
if(any(any(sym)))
    error('Constraint Q matrix %s is not symmetric',msgC);
end

function dim = chkSDDim(cone,ndec,i)
if(size(cone,2) ~= ndec+1)
    error('Semidefinite Cone %d does not have the correct number of columns',i);
end
dim = sqrt(size(cone,1));
if(floor(dim) ~= dim)
    error('Semidefinite Cone %d does not have the correct number of rows to form a square matrix');
end

function prob = insertQClin(prob,l,qrl,qru,n)
%Insert linear components of qc into prob structure

%Generate k vector
k = size(prob.a,1) + 1;
prob.qcsubk = [prob.qcsubk; k*ones(n,1)];
%Augment to linear a and constraint bounds
prob.a = [prob.a; l'];
prob.blc = [prob.blc; qrl];
prob.buc = [prob.buc; qru];


function rez = merge_posthoc2(rez)
%fracse = 0.1;
mu = rez.mu;
fracse = rez.ops.fracse;

ops = rez.ops;
LAM = ops.lam(3) * (20./mu).^2;
Nfilt = rez.ops.Nfilt;

Cmerge = Inf *ones(Nfilt);
tfi = rez.iNeigh;
tf = rez.cProj;
clusterIDs = rez.st3(:,2);
%
nSpikes = size(rez.st3,1);

fmax = zeros(nSpikes,1, 'single');
pairs = {};
for testID = 1:Nfilt
    spikesTest = clusterIDs==testID;
%     tfnew = bsxfun(@plus, tf(spikesTest, :), LAM(tfi(:, testID))'.*mu(tfi(:, testID))');
%     tf(spikesTest, :) = bsxfun(@rdivide, tfnew, sqrt(1+LAM(tfi(:, testID)))');

    pp = tfi(:, testID);
    pp(pp==testID) = [];
    pairs{testID} = pp;
    [~, isame] = min( abs(tfi(:, testID)-testID));
    fmax(spikesTest, 1) = tf(spikesTest, isame);
end

%
inewclust = 0;
clear iMegaC
picked = zeros(Nfilt, 1);
% tic
while 1
    [maxseed, iseed] = max(rez.nbins(1:Nfilt) .* (1-picked), [], 1);
%     [maxseed, iseed] = max(mu(1:Nfilt) .* (1-picked), [], 1);
    if maxseed<500
        break;
    end
    picked(iseed) = 1;
    % 21, 69,
    %
%     iseed = 410;

    run_list = [iseed];
    pair_list = pairs{iseed};
    strun = find(clusterIDs==iseed);

    while ~isempty(pair_list)
        %
%         picked_pairs = rez.nbins(pair_list);

        [mmax, ipair] = max(rez.nbins(pair_list));

        if mmax<100
            break;
        end

        ipair = pair_list(ipair);

        %
        imm = ismember(tfi(:, ipair), run_list);
        if sum(imm)
            %
            new_spikes = find(clusterIDs==ipair);
            f1new = max(tf(new_spikes, imm), [], 2);

            f2new = fmax(new_spikes);

            f1old = fmax(strun);
            f2old = NaN * ones(numel(f1old), 1, 'single');
            i0 = 0;
            for j = 1:length(run_list)
                ifeat = find(tfi(:, run_list(j))==ipair);
                if ~isempty(ifeat)
                    f2old(i0 + (1:rez.nbins(run_list(j))),1) = ...
                        tf(clusterIDs==run_list(j), ifeat);
                    i0 = i0 + rez.nbins(run_list(j));
                end
            end

            f1old(isnan(f2old))=[];
            f2old(isnan(f2old))=[];
            mo = merging_score(f1old - f2old, f1new-f2new, ops.fracse);

            if mo<3
                strun = cat(1, strun, new_spikes);
                run_list(end+1) = ipair;
                picked(ipair)   = 1;
                if mmax>300
                    pair_list = unique(cat(1, pair_list, pairs{ipair}));
                    pair_list(ismember(pair_list, run_list)) = [];
                end
            end
        end
        pair_list(pair_list==ipair) = [];
    end

    inewclust = inewclust + 1;

    iMegaC{inewclust} = run_list;
%     [sum(picked) run_list]
end

% toc
%

iMega = zeros(Nfilt, 1);
for i = 1:length(iMegaC)
   iMega(iMegaC{i}) = iMegaC{i}(1);
end
rez.iMega = iMega;
rez.iMegaC = iMegaC;

rez.st3(:,5) = iMega(rez.st3(:,2));


% TEST_STOKES_3D_SYMDRIVCAV_MP_H_DRCHLT: data function for Dirichlet boundary condition.

function h  = test_stokes_3d_symdrivcav_mp_h_drchlt (x, y, z, iside)
switch (iside)
 case {1, 2, 5, 6}
  h = zeros ([3, size(x)]);
 case 3
  h1 = -ones ([1, size(x)]);
  h2 = zeros ([1, size(x)]);
  h3 = zeros ([1, size(x)]);
  h  = cat (1, h1, h2, h3);
 case 4
  h1 = ones ([1, size(x)]);
  h2 = zeros ([1, size(x)]);
  h3 = zeros ([1, size(x)]);
  h  = cat (1, h1, h2, h3);
end
end


function test_glm
%Validate calculation of general linear model
%
%  test_glm()
%
% Tests: applyGlm, computeContrastMap2
%
% INPUTS
%  No inputs
%
% RETURNS
%  No returns
%
% Example: test_glm()
%
% See also MRVTEST
%
% Copyright Stanford team, mrVista, 2013

%% Initialize the key variables and data path
% Data directory (where the mrSession file is located)
dataDir = mrtInstallSampleData('functional','vwfaLoc');

% This is the validation file
storedGLM = mrtGetValididationData('glm');

% These are the items we stored in the validation file
%
% val.dim             = size(contrastMap);
% val.contrastMean    = nanmean(contrastMap(:));
% val.contrastMed     = median(contrastMap(:));
% val.contrastMax     = max(contrastMap(:));
% val.contrastVoc     = contrastMap(40,40,10);
%
% save(vFile, '-struct', 'val')

%% Retain original directory, change to data directory
curDir = pwd;
cd(dataDir);

% There can be several data types - name the one you want to use for
% computing GLM.
dataType = 'MotionComp';

% We will compute a GLM for 2 scans ...
scans = 1:2;

%% Get data structure and calculate glm

% open a session
vw = initHiddenInplane;

% set to motion comp dataTYPES
vw = viewSet(vw, 'current data type', dataType);

% get the GLM params
params = er_getParams(vw, scans(1), dataType);

% run the GLM
vw = applyGlm(vw, dataType, scans, params, 'GLM');

% Compute a contrast map from command line
stim     = er_concatParfiles(vw);
active   = find(strcmpi(stim.condNames, 'Word'));
control  = find(strcmpi(stim.condNames, 'Fix'));
saveName = 'WordVFix';
vw       = computeContrastMap2(vw, active, control, saveName);

contrastMap = viewGet(vw, 'map', 1); contrastMap = contrastMap{1};

%% Return to original directory
cd(curDir)

%% Validate the results

assertEqual(storedGLM.dim, size(contrastMap));
assertElementsAlmostEqual(storedGLM.contrastMean, nanmean(contrastMap(:)), 'relative', .00001);
assertElementsAlmostEqual(storedGLM.contrastMed,  median(contrastMap(:)), 'relative', .00001);
assertElementsAlmostEqual(storedGLM.contrastMax,  max(contrastMap(:)), 'relative', .00001);
assertElementsAlmostEqual(storedGLM.contrastVoc,  contrastMap(40,40,10), 'relative', .00001);

mrvCleanWorkspace;


function [p,pss] = propagate_bounds_from_qualities(p)
pss = [];
if isempty(p.nonlinear) && p.feasible
    if p.K.f>0
        Aeq = -p.F_struc(1:p.K.f,2:end);
        beq = p.F_struc(1:p.K.f,1);
        A = [Aeq;-Aeq];
        b = [beq;-beq];
        [p.lb,p.ub,redundant,pss] = tightenbounds(A,b,p.lb,p.ub,p.integer_variables,p.binary_variables,ones(length(p.lb),1));
    end
    pss=[];
    if p.K.l>0
        A = -p.F_struc(1+p.K.f:p.K.f+p.K.l,2:end);
        b = p.F_struc(1+p.K.f:p.K.f+p.K.l,1);
        [p.lb,p.ub,redundant,pss] = tightenbounds(A,b,p.lb,p.ub,p.integer_variables,p.binary_variables,ones(length(p.lb),1));
        if length(redundant)>0
            pss.AL0A(redundant,:)=[];
            pss.AG0A(redundant,:)=[];
            p.F_struc(p.K.f+redundant,:)=[];
            p.K.l = p.K.l - length(redundant);
        end
    end
end


% IMAGE_SCAT_LAYER engine function of IMAGE_SCAT
%
% Usage
%     big_img = image_scat_layer(Scatt, renorm, dsp_legend)
%
% Input
%	Scatt (struct): a layer of  scattering (either U or S)
%	renorm (boolean): if 1 renormalize each path by its max. Default
%	value is set to 1.
%	dsp_legend (boolean): if set to 1, display legend. Default value is 1
%
% Output
%	big_img (numerical): a large image where all paths are concatenated

function big_img = image_scat_layer(Scatt, renorm, dsp_legend)
	if (numel(size(Scatt.signal{1})) == 3)
		p2 = 1;
		for p = 1:numel(Scatt.signal)
			for theta = 1:size(Scatt.signal{1},3)
				ScattBis.signal{p2} = Scatt.signal{p}(:,:,theta);
				ScattBis.meta.j(:,p2) = Scatt.meta.j(:,p);
				ScattBis.meta.theta2(:,p2) = Scatt.meta.theta2(:,p);
				ScattBis.meta.theta(:,p2) = theta;
				ScattBis.meta.k2(:,p2) = Scatt.meta.k2(:,p);
				p2 = p2 + 1;
			end
		end

		if ~exist('renorm','var');
			renorm  = 1;
		end
		if ~exist('dsp_legend','var');
			dsp_legend  = 1;
		end
		big_img = image_scat_layer(ScattBis, renorm, dsp_legend);
		return
	end
	if ~exist('renorm','var');
		renorm  = 1;
	end
	if ~exist('dsp_legend','var');
		dsp_legend  = 1;
	end

	numel_per_width= zeros(10000,1);
	numel_per_height = zeros(10000,1);
	if (~isfield(Scatt,'signal'))
		Scatt2 = Scatt;
		clear Scatt; % avoid warning
		Scatt.signal = Scatt2;
	end
	if (size(Scatt.signal{1},3)==3)
		for rgb = 1:3
			for p=1:numel(Scatt.signal)
				Scattrgb{rgb}.signal{p}=squeeze(Scatt.signal{p}(:,:,rgb));
			end
			big_img(:,:,rgb) = display_scatt_2d_all_layer(Scattrgb{rgb});
		end
	else
		for p = 1:numel(Scatt.signal)
			curr_sz = size(Scatt.signal{p});
			numel_per_width(curr_sz(2)) = numel_per_width(curr_sz(2)) + 1;
			numel_per_height(curr_sz(1)) = numel_per_height(curr_sz(1)) + 1;
		end

		% block style
		widths = find(numel_per_width);

		total_width = ceil(sqrt(numel_per_width(max(widths))))* max(widths);
		curr_y = 0;

		% first pass to compute size and allocate

		for j = numel(widths):-1:1
			w= widths(j);
			curr_x = 0;

			for p = 1:numel(Scatt.signal)
				curr_sig = Scatt.signal{p};
				if (size(curr_sig,2) == w)
					h = size(curr_sig,1);
					if (curr_x >= total_width)
						curr_x = 0;
						curr_y = curr_y + size(curr_sig,1);
					end
					curr_x = curr_x + w;
				end
			end
			curr_y = curr_y + h;

		end
		big_img = zeros(curr_y,total_width);
		% second pass to put in the matrix what has to be put in
		curr_y = 0;
		for j = numel(widths):-1:1
			w= widths(j);
			curr_x = 0;

			for p = 1:numel(Scatt.signal)
				curr_sig = Scatt.signal{p};
				if (size(curr_sig,2) == w)
					h = size(curr_sig,1);
					if (curr_x >= total_width)
						curr_x = 0;
						curr_y = curr_y + size(curr_sig,1);
					end
					K = max(max(abs(Scatt.signal{p})));
					if (renorm==0)
						ds = size(Scatt.signal{1},1)/size(Scatt.signal{p},1);
						K = ds;
					end
					if (renorm==3)
						K=1 ;% preserve_l2_norm is off;
					end
					if (renorm == 2) % input is in log2 : substract the constant !
						ds = size(Scatt.signal{1},1)/size(Scatt.signal{p},1);
						K = log2(ds);
						big_img( (1:size(Scatt.signal{p},1)) + curr_y , (1:size(Scatt.signal{p},2)) + curr_x ) = Scatt.signal{p} -K;
					else
						big_img( (1:size(Scatt.signal{p},1)) + curr_y , (1:size(Scatt.signal{p},2)) + curr_x ) = Scatt.signal{p}/K;
					end
					curr_x = curr_x + w;
				end
			end
			curr_y = curr_y + h;

		end

		% compute min and max for future renormalization of legend
		img_min = min(big_img(:));
		img_max = max(big_img(:));
		%big_img =  (big_img-m)/(M-m);

		% last pass for legend
		curr_y = 0;
		for j = numel(widths):-1:1
			w= widths(j);
			curr_x = 0;

			for p = 1:numel(Scatt.signal)
				curr_sig = Scatt.signal{p};
				if (size(curr_sig,2) == w)
					h = size(curr_sig,1);
					if (curr_x >= total_width)
						curr_x = 0;
						curr_y = curr_y + size(curr_sig,1);
					end

					if (isstruct(Scatt) && isfield(Scatt,'meta'))
						str_legend = meta2str(Scatt.meta,p);
						if (numel(str_legend)>0)
							str_legend_split = textscan(str_legend,'%s','delimiter',' ');
						else
							str_legend_split{1} ={};
						end
					else % no meta to display
						str_legend_split{1}={};
					end
					if (dsp_legend ==0)
						str_legend_split{1}={};
					end
					str_legend_split = str_legend_split{1};
					for jl = 1:numel(str_legend_split)

						str = str_legend_split{jl};

						imstr = str2imfast(str);
						% renormalize imstr
						imstr = img_min + (img_max-img_min)*imstr;
						[n,m] = size(imstr);

						y_min =   n*(jl-1) + 1 +  curr_y;
						y_max =   n*(jl-1) + n + curr_y;
						x_min =   curr_x + 1;
						x_max =   curr_x + m;

						y_min = min(y_min,size(big_img,1));
						x_min = min(x_min,size(big_img,2));
						y_max = min(y_max,size(big_img,1));
						x_max = min(x_max,size(big_img,2));
						ny = y_max - y_min +1;
						nx = x_max - x_min +1;
						big_img(y_min:y_max,x_min:x_max) = max(imstr(1:ny,1:nx),0.5* big_img(y_min:y_max,x_min:x_max));
					end

					curr_x = curr_x + w;
				end
			end
			curr_y = curr_y + h;

		end

	end
	imagesc(big_img);
end


function mpc = case6ww
%CASE6WW  Power flow data for 6 bus, 3 gen case from Wood & Wollenberg.
%   Please see CASEFORMAT for details on the case file format.
%
%   This is the 6 bus example from pp. 104, 112, 119, 123-124, 549 of
%   "Power Generation, Operation, and Control, 2nd Edition",
%   by Allen. J. Wood and Bruce F. Wollenberg, John Wiley & Sons, NY, Jan 1996.

%   MATPOWER

%% MATPOWER Case Format : Version 2
mpc.version = '2';

%%-----  Power Flow Data  -----%%
%% system MVA base
mpc.baseMVA = 100;

%% bus data
%	bus_i	type	Pd	Qd	Gs	Bs	area	Vm	Va	baseKV	zone	Vmax	Vmin
mpc.bus = [
	1	3	0	0	0	0	1	1.05	0	230	1	1.05	1.05;
	2	2	0	0	0	0	1	1.05	0	230	1	1.05	1.05;
	3	2	0	0	0	0	1	1.07	0	230	1	1.07	1.07;
	4	1	70	70	0	0	1	1	0	230	1	1.05	0.95;
	5	1	70	70	0	0	1	1	0	230	1	1.05	0.95;
	6	1	70	70	0	0	1	1	0	230	1	1.05	0.95;
];

%% generator data
%	bus	Pg	Qg	Qmax	Qmin	Vg	mBase	status	Pmax	Pmin	Pc1	Pc2	Qc1min	Qc1max	Qc2min	Qc2max	ramp_agc	ramp_10	ramp_30	ramp_q	apf
mpc.gen = [
	1	0	0	100	-100	1.05	100	1	200	50	0	0	0	0	0	0	0	0	0	0	0;
	2	50	0	100	-100	1.05	100	1	150	37.5	0	0	0	0	0	0	0	0	0	0	0;
	3	60	0	100	-100	1.07	100	1	180	45	0	0	0	0	0	0	0	0	0	0	0;
];

%% branch data
%	fbus	tbus	r	x	b	rateA	rateB	rateC	ratio	angle	status	angmin	angmax
mpc.branch = [
	1	2	0.1	0.2	0.04	40	40	40	0	0	1	-360	360;
	1	4	0.05	0.2	0.04	60	60	60	0	0	1	-360	360;
	1	5	0.08	0.3	0.06	40	40	40	0	0	1	-360	360;
	2	3	0.05	0.25	0.06	40	40	40	0	0	1	-360	360;
	2	4	0.05	0.1	0.02	60	60	60	0	0	1	-360	360;
	2	5	0.1	0.3	0.04	30	30	30	0	0	1	-360	360;
	2	6	0.07	0.2	0.05	90	90	90	0	0	1	-360	360;
	3	5	0.12	0.26	0.05	70	70	70	0	0	1	-360	360;
	3	6	0.02	0.1	0.02	80	80	80	0	0	1	-360	360;
	4	5	0.2	0.4	0.08	20	20	20	0	0	1	-360	360;
	5	6	0.1	0.3	0.06	40	40	40	0	0	1	-360	360;
];

%%-----  OPF Data  -----%%
%% generator cost data
%	1	startup	shutdown	n	x1	y1	...	xn	yn
%	2	startup	shutdown	n	c(n-1)	...	c0
mpc.gencost = [
	2	0	0	3	0.00533	11.669	213.1;
	2	0	0	3	0.00889	10.333	200;
	2	0	0	3	0.00741	10.833	240;
];