Skip to content
/ gptoolbox Public
Switch branches/tags
Could not load branches
Nothing to show

# Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Cannot retrieve contributors at this time
406 lines (389 sloc) 12.4 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
 function [W,f] = monotonic_biharmonic(varargin) % MONOTONIC_BIHARMONIC Compute "monotonic biharmonic" coordinates, using % quadratic programming optimization. Each weight funciton minimizes % laplacian energy subject to monotonicity constraints taken from harmonic % coordinates % % W = monotonic_biharmonic(V,F,b,bc,'ParameterName',ParameterValue) % % Inputs: % V list of vertex positions % F list of face indices, for 3D F is #F by 4, for 2D F is #F by 3 % b list of boundary vertices % bc list of boundary conditions, size(boundary) by # handles matrix of % boundary conditions where bc(:,i) are the boundary conditions for the % ith handle % Optional: % 'k' followed by integer, solve k-harmonic problem {2} % 'QuadProgParam' followed by mosek param struct, see optimset. If not % given then *some* default options are used % 'MonotonicityGraph' followed A a #handles cell of #n by #n % monotonicity graph (sparse adjacency matrix) with A{k}(i,j) != % 0 if we want that W(i,k) <= W(j,k), default is to use graph % from harmonic coordinates % 'MonotonicityTGraph' followed AT a #handles cell of #F by #F set of % constraints on triangle (averages) % 'Data' followed by #W by #handles data term to be % 'as-close-as-possible', {[]} % 'DataWeight' follow by weight of Data energy term, {1} % 'Algorithm' followed by solver name {'interior-point'}: % 'interior-point' % 'active-set' Alec's active set solver % (min_quad_with_fixed_active_set) % 'OptType' % optimize using {'conic'} or 'quad' or 'legacy-quad' % 'SubGraph' followed by true or false, whether to iteratively resolve % using exponentially larger subgraphs of the monotonicity graph, % {false} % 'IterateConstraints' Iterate on monotonicity constraints % 'ExtremaBC' Followed by bc to be used for computing monotonicitygraph % 0 means min, 1 means max % 'MaxIter' maximum number of iterations {inf} % 'Quiet' followed by 'echo(0)' or '' to be quite or loud % 'MonotonicityEpsilon' followed by epsilon used for enforcing % monotonicity. {0} Increase this value if constraints are being % violated. % 'LEQScale' followed by scale applied to linear inequality constraints % to help mosek know that our constraints are not to be violated {1000}. % This is probably tied to the implicit scaling of the data and % smoothness terms. Increase this value if constraints are being % violated % Output: % W weights, # vertices by # handles matrix of weights % % Copyright 2011, Alec Jacobson (jacobson@inf.ethz.ch) % % See also: boundary_conditions, biharmonic_bounded % V = varargin{1}; F = varargin{2}; b = varargin{3}; bc = varargin{4}; % number of vertices n = size(V,1); % number of handles m = size(bc,2); % default options k = 2; algorithm = 'interior-point'; opt_type = 'conic'; subgraph = false; iterate_constraints = false; extrema_bc = bc; max_iter = inf; % check for mosek and set its parameters [param,mosek_exists] = default_quadprog_param(); if mosek_exists opt_type = 'conic'; else opt_type = 'legacy-quad'; end %param.MSK_DPAR_INTPNT_CO_TOL_PFEAS = 0; %param.MSK_DPAR_INTPNT_CO_TOL_DFEAS = 0; S = []; data_weight = 1; A = {}; AT = cell(m,1); quiet = 'echo(0)'; monotonicity_epsilon = 0; leq_scale = 1; % parse optional inputs ii = 5; while(ii <= nargin) switch varargin{ii} case 'Quiet' ii = ii + 1; assert(ii<=nargin); quiet = varargin{ii}; case 'MonotonicityGraph' ii = ii + 1; assert(ii<=nargin); A = varargin{ii}; case 'MonotonicityTGraph' ii = ii + 1; assert(ii<=nargin); AT = varargin{ii}; case 'Data' ii = ii + 1; assert(ii<=nargin); S = varargin{ii}; case 'DataWeight' ii = ii + 1; assert(ii<=nargin); data_weight = varargin{ii}; case 'k' ii = ii + 1; assert(ii<=nargin); k = varargin{ii}; case 'QuadProgParam' ii = ii + 1; assert(ii<=nargin); param = varargin{ii}; case 'Algorithm' ii = ii + 1; assert(ii<=nargin); algorithm = varargin{ii}; case 'OptType' ii = ii + 1; assert(ii<=nargin); opt_type = varargin{ii}; case 'SubGraph' ii = ii + 1; assert(ii<=nargin); subgraph = varargin{ii}; case 'IterateConstraints' ii = ii + 1; assert(ii<=nargin); iterate_constraints = varargin{ii}; case 'ExtremaBC' ii = ii + 1; assert(ii<=nargin); extrema_bc = varargin{ii}; case 'MaxIter' ii = ii + 1; assert(ii<=nargin); max_iter = varargin{ii}; case 'MonotonicityEpsilon' ii = ii + 1; assert(ii<=nargin); monotonicity_epsilon = varargin{ii}; case 'LEQScale' ii = ii + 1; assert(ii<=nargin); leq_scale = varargin{ii}; otherwise error(['Unsupported parameter: ' varargin{ii}]); end ii = ii+1; end % Build discrete laplacian and mass matrices used by all handles' solves if(size(F,2)==4) %fprintf('Solving over volume...\n'); L = cotmatrix3(V,F); M = massmatrix3(V,F,'barycentric'); % Build pieces of sqrt(L) for odd powers if mod(k,2) ~= 0 % area is really volume dblA = abs(volume(V,F)); TA = repdiag(diag(sparse(dblA)),size(V,2)); G = grad3(V,F); end else L = cotmatrix_embedded(V,F); M = massmatrix_embedded(V,F,'voronoi'); % Build pieces of sqrt(L) for odd powers if mod(k,2) ~= 0 dblA = doublearea(V,F); TA = repdiag(diag(sparse(dblA)/2),size(V,2)); G = grad(V,F); end end % Normalize mass matrix (important!) M = M./max(abs(diag(M))); % build quadratic coefficient matrix (bilaplacian operator) switch opt_type case 'legacy-quad' Q = -L; % Construct quadratic coefficients matrix for ii = 2:k Q = -L*(M\Q); end % Symmetrize for high-order if k >= 3 Q = (Q+Q')*0.5; end save('mbQ.mat','Q'); case {'quad','conic'} % build possibly (odd k) rectangular sqrt of quadratic coefficient matrix if mod(k,2)==0 FF = -L; FFstr = '-L'; % even k for ii = 2:(k/2) FF = -L*(M\FF); FFstr = ['-L(M\' FFstr ')']; end FF = sqrt(M)\FF; FFstr = ['sqrt(M)\(' FFstr ')']; else % odd k FF = speye(n,n); FFstr = ''; for ii = 1:((k-1)/2) FF = M\(-L*FF); FFstr = ['M\(-L ' FFstr ')']; end FF = sqrt(TA)*G*FF; FFstr = ['sqrt(TA)G(' FFstr ')']; end otherwise error(['Unsupported OptType: ' opt_type]); end % No linear terms l = zeros(n,m); if ~isempty(S) % build quadratic and linear data term if numel(data_weight) == 1 data_weight = repmat(data_weight,n,1); end % L2 norm scaling data_scale = 1/sqrt(sum(S(:).^2)); switch opt_type case 'legacy-quad' % Mosek assumes quadratic terms will be multiplied by 1/2 Q = Q+2*data_scale*diag(sparse(data_weight)); case {'quad','conic'} FF = [FF;diag(sqrt(2)*sparse(sqrt(data_scale*data_weight)))]; end l = bsxfun(@plus,l,-2*bsxfun(@times,data_scale*data_weight,S)); end if isempty(A) % initial monotonic guess assert(all(extrema_bc(:)==0 | extrema_bc(:)==1)); WH = kharmonic(V,F,b,extrema_bc); A = cell(m,1); % loop over handles for i = 1:m A{i} = monotonicity_matrix(WH(:,i),F,'OneInOneOut',true,'EnforceExtrema',true); end elseif isnumeric(A) assert(~iterate_constraints); A = {A}; end if isnumeric(AT) AT = {AT}; end tic; % loop over handles for i = 1:m iter = 1; fullgraph = false; while(iter <= max_iter) Ai = A{i}; ATi = AT{i}; % Unpublished idea to only enforce some subset of the constraints, you % may safely ignore this section if subgraph assert(isempty(ATi)); [AiI,AiJ,AiV] = find(Ai); step_base = 2; num_edges = round(step_base^(1.1*(iter+1))-1); if num_edges < numel(AiI) %fprintf('Num edges in subgraph: %d\n',num_edges); randorder = randperm(numel(AiI)); sel = randorder(1:num_edges); Ai = sparse(AiI(sel),AiJ(sel),AiV(sel),size(Ai,1),size(Ai,2)); else num_edges = numel(AiI); %fprintf('Num edges in fullgraph: %d\n',numel(AiI)); fullgraph = true; end end % monotonicity constraints, as less than or equals constraints [Aleq,ATleq] = inequality_constraints_from_graphs(F,Ai,ATi); Aleq = [Aleq;ATleq]; nleq = size(Aleq,1); bleq = zeros(nleq,1); % boundary conditions Aeq = speye(n,n); Aeq = Aeq(b,:); % Optimize according to algorithm and opt_type choice switch algorithm case 'interior-point' % Constant bounds seem to help performance lx = min(bc(:,i))*ones(n,1); ux = max(bc(:,i))*ones(n,1); switch opt_type case 'legacy-quad' if(mosek_exists) %fprintf('Quadratic optimization using mosek...\n'); else %fprintf('Quadratic optimization using matlab...\n'); end %fprintf( [ ... % ' minimize: x''LM\\Lx\n' ... % 'subject to: xi <= xj, ???j, j parent to i\n' ]); [x,fval,err] = quadprog(Q,l(:,i),leq_scale*Aleq,-monotonicity_epsilon+leq_scale*bleq, ... Aeq,bc(:,i),lx,ux,[],param); if(err ~= 1) fprintf([... '----------------------------------------------------------\n' ... 'ERROR (' num2str(err) ',' num2str(fval) '):' ... ' solution may be inaccurate...\n' ... '----------------------------------------------------------\n' ... ]); end case {'quad','conic'} %fprintf( [ ... % ' minimize: ||Fx||^2\n' ... % 'subject to: xi <= xj, ???j, j parent to i\n' ]); [x,f] = conic( ... FF,l(:,i), ... [],[], ... leq_scale*Aleq,-monotonicity_epsilon+leq_scale*bleq, ... lx,ux, ... b,bc(:,i), ... 'Param',param, ... 'Quiet',quiet, ... 'OptType',opt_type); end % number of violated constraints diffleq = Aleq*x - bleq; vc = sum(diffleq>=0); if vc>0 warning(['%d violated constraints, ' ... 'try increasing MonotonicityEpsilon by max violation: +%g ' ... 'or increasing LEQScale '], ... vc,max(diffleq(diffleq>0))); end % Unpublished home-brewed active set solver, likely this will not work. % Safe to ignore case 'active-set' %fprintf('Quadratic optimization using active set...\n'); [x,preF] = min_quad_with_fixed_active_set(Q,zeros(n,1),b,bc(:,i),[],[],[],[]); otherwise error(['Unsupported algorithm type: ''' algorithm '''']); end % set weights to solution in weight matrix W(:,i) = x(1:n); %fprintf('Lap time: %gs\n',toc); if ~subgraph && ~iterate_constraints break; elseif subgraph % Again, unpublished and safe to ignore this section if size(V,2) == 2 Z = W(:,i); else Z = V(:,3); end t = trisurf(F,V(:,1),V(:,2),Z,'FaceLighting','phong','FaceColor','interp','CData',W(:,i),'EdgeColor','none'); colormap(jet(20)); mes = mark_extrema(t,W(:,i)); drawnow; if max_iter == inf %input(['iter: ' num2str(iter)]); end elseif iterate_constraints % Rebuild constraints based on previous solution A{i} = monotonicity_matrix(W(:,i),F,'OneInOneOut',true,'EnforceExtrema',true); if max_iter == inf %input(['iter: ' num2str(iter)]); end end % Unpublished, safe to ignore if fullgraph break; end % Unpublished, safe to ignore if iter == max_iter %fprintf('Reached maximum iterations (%d) with convergence\n',max_iter); break; end iter = iter + 1; end end t = toc; % Print some time information %fprintf('Total elapsed time: %gs\n',t); %fprintf('Average time per handle: %gs\n',t/m); end