├── LICENSE ├── README.md ├── data.sh ├── demoH36M.m ├── demoHG.m ├── demoMPII.m ├── dict ├── poseDict-Posing-K64.mat ├── poseDict-all-K128.mat └── tennis_forehand.mat ├── em ├── PoseFromVideo.m ├── estimateC_fused.m ├── estimateR_fused.m ├── findWmax.m └── rotateS.m ├── general ├── alignHuman.m ├── centralize.m ├── compareStructs.m ├── computeError2D.m ├── computeError3D.m ├── computeErrorPCK.m ├── findRotation.m ├── findWmax.m ├── generateRotation.m ├── limbLength.m ├── meanShape.m ├── normalizeS.m ├── perspAdj.m ├── proj22D.m ├── reshapeS.m ├── sampleShapes.m ├── viewStruct.m ├── vis2Dcar.m ├── vis2Dmarker.m ├── vis2Dskel.m ├── vis3Dcar.m ├── vis3Dmarker.m └── vis3Dskel.m ├── manopt ├── CLA.txt ├── COPYING.txt ├── CREDITS.txt ├── LICENSE.txt ├── README.txt ├── checkinstall │ └── basicexample.m ├── examples │ ├── dominant_invariant_subspace.m │ ├── dominant_invariant_subspace_complex.m │ ├── essential_svd.m │ ├── generalized_eigenvalue_computation.m │ ├── generalized_procrustes.m │ ├── low_rank_dist_completion.m │ ├── low_rank_matrix_completion.m │ ├── low_rank_tensor_completion.m │ ├── maxcut.m │ ├── nonlinear_eigenspace.m │ ├── packing_on_the_sphere.m │ ├── positive_definite_karcher_mean.m │ ├── radio_interferometric_calibration.m │ ├── robust_pca.m │ ├── shapefit_smoothed.m │ ├── sparse_pca.m │ └── truncated_svd.m ├── importmanopt.m ├── manopt │ ├── core │ │ ├── StoreDB.m │ │ ├── applyStatsfun.m │ │ ├── canGetApproxHessian.m │ │ ├── canGetCost.m │ │ ├── canGetDirectionalDerivative.m │ │ ├── canGetEuclideanGradient.m │ │ ├── canGetGradient.m │ │ ├── canGetHessian.m │ │ ├── canGetLinesearch.m │ │ ├── canGetPrecon.m │ │ ├── canGetSqrtPrecon.m │ │ ├── getApproxHessian.m │ │ ├── getCost.m │ │ ├── getCostGrad.m │ │ ├── getDirectionalDerivative.m │ │ ├── getEuclideanGradient.m │ │ ├── getGlobalDefaults.m │ │ ├── getGradient.m │ │ ├── getHessian.m │ │ ├── getHessianFD.m │ │ ├── getLinesearch.m │ │ ├── getPrecon.m │ │ ├── getSqrtPrecon.m │ │ ├── getStore.m │ │ ├── handle_light.m │ │ ├── mergeOptions.m │ │ ├── purgeStoredb.m │ │ ├── setStore.m │ │ └── stoppingcriterion.m │ ├── manifolds │ │ ├── complexcircle │ │ │ └── complexcirclefactory.m │ │ ├── essential │ │ │ ├── README_Essential.txt │ │ │ ├── essential_costE2cost.m │ │ │ ├── essential_egradE2egrad.m │ │ │ ├── essential_ehessE2ehess.m │ │ │ ├── essential_flat.m │ │ │ ├── essential_hat3.m │ │ │ ├── essential_sharp.m │ │ │ ├── essentialfactory.m │ │ │ └── privateessential │ │ │ │ ├── essential_closestRepresentative.m │ │ │ │ ├── essential_distMinAngle.m │ │ │ │ ├── essential_distMinAnglePair.m │ │ │ │ ├── essential_distMinAnglePair_base.m │ │ │ │ ├── essential_distMinAnglePair_computeDfBreak.m │ │ │ │ ├── essential_distMinAnglePair_dfNewton.m │ │ │ │ ├── essential_distMinAnglePair_discontinuityDistance.m │ │ │ │ ├── essential_distMinAnglePair_ft.m │ │ │ │ ├── essential_distMinAnglePair_ftFromQ.m │ │ │ │ ├── essential_distMinAnglePair_test.m │ │ │ │ └── modAngle.m │ │ ├── euclidean │ │ │ ├── centeredmatrixfactory.m │ │ │ ├── euclideancomplexfactory.m │ │ │ ├── euclideanfactory.m │ │ │ ├── shapefitfactory.m │ │ │ └── symmetricfactory.m │ │ ├── fixedrank │ │ │ ├── fixedrankMNquotientfactory.m │ │ │ ├── fixedrankembeddedfactory.m │ │ │ ├── fixedrankfactory_2factors.m │ │ │ ├── fixedrankfactory_2factors_preconditioned.m │ │ │ ├── fixedrankfactory_2factors_subspace_projection.m │ │ │ ├── fixedrankfactory_3factors.m │ │ │ └── fixedrankfactory_3factors_preconditioned.m │ │ ├── fixedranktensors │ │ │ ├── fixedrankfactory_tucker_preconditioned.m │ │ │ └── tucker2multiarray.m │ │ ├── grassmann │ │ │ ├── grassmanncomplexfactory.m │ │ │ ├── grassmannfactory.m │ │ │ └── grassmanngeneralizedfactory.m │ │ ├── multinomial │ │ │ └── multinomialfactory.m │ │ ├── oblique │ │ │ └── obliquefactory.m │ │ ├── rotations │ │ │ ├── randrot.m │ │ │ ├── randskew.m │ │ │ └── rotationsfactory.m │ │ ├── specialeuclidean │ │ │ └── specialeuclideanfactory.m │ │ ├── sphere │ │ │ ├── spherecomplexfactory.m │ │ │ ├── spherefactory.m │ │ │ └── spheresymmetricfactory.m │ │ ├── stiefel │ │ │ ├── stiefelcomplexfactory.m │ │ │ ├── stiefelfactory.m │ │ │ ├── stiefelgeneralizedfactory.m │ │ │ └── stiefelstackedfactory.m │ │ └── symfixedrank │ │ │ ├── elliptopefactory.m │ │ │ ├── spectrahedronfactory.m │ │ │ ├── symfixedrankYYcomplexfactory.m │ │ │ ├── symfixedrankYYfactory.m │ │ │ └── sympositivedefinitefactory.m │ ├── solvers │ │ ├── conjugategradient │ │ │ └── conjugategradient.m │ │ ├── hessianapproximations │ │ │ └── approxhessianFD.m │ │ ├── linesearch │ │ │ ├── linesearch.m │ │ │ ├── linesearch_adaptive.m │ │ │ ├── linesearch_decrease.m │ │ │ └── linesearch_hint.m │ │ ├── neldermead │ │ │ ├── centroid.m │ │ │ └── neldermead.m │ │ ├── preconditioners │ │ │ └── preconhessiansolve.m │ │ ├── pso │ │ │ └── pso.m │ │ ├── steepestdescent │ │ │ └── steepestdescent.m │ │ └── trustregions │ │ │ ├── license for original GenRTR code.txt │ │ │ ├── tCG.m │ │ │ └── trustregions.m │ └── tools │ │ ├── checkdiff.m │ │ ├── checkgradient.m │ │ ├── checkhessian.m │ │ ├── dexpm.m │ │ ├── dfunm.m │ │ ├── diagsum.m │ │ ├── dlogm.m │ │ ├── dsqrtm.m │ │ ├── hashmd5.m │ │ ├── hessianextreme.m │ │ ├── hessianspectrum.m │ │ ├── identify_linear_piece.m │ │ ├── manoptsolve.m │ │ ├── matrixlincomb.m │ │ ├── multihconj.m │ │ ├── multiherm.m │ │ ├── multiprod.m │ │ ├── multiprodmultitransp_license.txt │ │ ├── multiscale.m │ │ ├── multiskew.m │ │ ├── multisqnorm.m │ │ ├── multisym.m │ │ ├── multitrace.m │ │ ├── multitransp.m │ │ ├── plotprofile.m │ │ ├── powermanifold.m │ │ ├── productmanifold.m │ │ ├── statsfunhelper.m │ │ ├── surfprofile.m │ │ ├── tangentspacefactory.m │ │ └── tangentspherefactory.m └── manopt_version.m ├── pose-hg-demo ├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── img.lua ├── model.sh ├── residual.lua ├── run-hg.lua ├── stacked-hourglass-model.lua └── util.lua ├── ssr ├── composeShape.m ├── estimateC.m ├── estimateR_manopt.m ├── estimateR_proj.m ├── learnPoseDict.m ├── nnscDL.m ├── proj_deformable_approx.m ├── prox_2norm.m ├── ssr2D3D_alm.m ├── ssr2D3D_alt.m ├── ssr2D3D_wrapper.m └── syncRot.m ├── startup.m └── utils ├── getMPIIdict.m └── transformMPII.m /README.md: -------------------------------------------------------------------------------- 1 | This repository implements the 3D human pose estimation algorithm introduced in the following paper: 2 | > Monocap: Monocular human motion capture using a CNN coupled with a geometric prior. X. Zhou, M. Zhu, G. Pavlakos, S. Leonardos, K.G. Derpanis, K. Daniilidis. IEEE Transactions on Pattern Analysis and Machine Intelligence (T-PAMI), 2018. Accepted. 3 | 4 | ## How to use? 5 | 1. Download data by running the following script in command line: 6 | ```bash data.sh``` 7 | 2. Open MATLAB and run: 8 | ```startup``` 9 | 3. Run the demo scripts: 10 | - demoH36M for an example from Human3.6M dataset 11 | - demoHG for an example of how to use our algorithm combined with the "Stacked hourglass network" 12 | - demoMPII for an example of how to reconstruct 3D poses from a single image from MPII dataset 13 | 14 | ## Notes: 15 | - The code for hourglass network in pose-hg-demo is from Newell et al., https://github.com/anewell/pose-hg-demo 16 | - See the comments in demoHG.m for how to run hourglass network on your images and save heatmaps 17 | - If you want to use the hourglass network, you need to first install Torch and make it work 18 | - Generally "Hourglass network" + "poseDict-all-K128" (pose dictionary learned from Human3.6M) work well. For better 3D reconstruction, you can learn a 3D pose dictionary using your own mocap data. For more details on pose dictionary learning, please see the following project: [sparse representation for shape estimation](http://cis.upenn.edu/~xiaowz/shapeconvex.html) 19 | - The optimization could be accelerated by changing the initialization method to alternating by changing the option when calling PoseFromVideo: 20 | ```PoseFromVideo(...,'InitialMethod','altern')``` -------------------------------------------------------------------------------- /data.sh: -------------------------------------------------------------------------------- 1 | # Download demo data 2 | wget http://visiondata.cis.upenn.edu/monocap/data.zip 3 | unzip data.zip 4 | rm data.zip -------------------------------------------------------------------------------- /demoH36M.m: -------------------------------------------------------------------------------- 1 | % This script demonstrates how to use: 2 | % the proposed EM algorithm + pose dictionary learned from Human3.6M 3 | % + the 2D joint detector described in the paper 4 | % We use a Human3.6M sequence as example 5 | 6 | clear 7 | 8 | %% load data 9 | % load data including heatmaps, images, etc ... 10 | data = load('data/h36m/S9-Posing 1.55011271.mat'); 11 | % load camera parameters 12 | cam = load('data/h36m/camera/S9-Posing 1.55011271.mat'); 13 | % load dictionary 14 | dict = load('dict/poseDict-Posing-K64.mat'); 15 | 16 | %% pose estimation using orthographic camera model 17 | Given2DPose = false; 18 | if Given2DPose 19 | output = PoseFromVideo('W_gt',data.W_gt,'dict',dict); 20 | else 21 | output = PoseFromVideo('heatmap',data.heatmap,'dict',dict); 22 | end 23 | 24 | %% using perspective camera model if camera parameters are known 25 | output.dict = dict; 26 | output.rootID = 1; % root node in the skeleton tree 27 | output.camera = cam; 28 | output.bbox = data.bbox; 29 | output = perspAdj(output); 30 | 31 | %% visualization 32 | 33 | nPlot = 4; 34 | figure('position',[300 300 200*nPlot 200]); 35 | for i = 1:length(data.frames) 36 | clf; 37 | % heatmap 38 | subplot('position',[0/nPlot 0 1/nPlot 1]); 39 | cmap = colormap('jet'); 40 | hmap = size(cmap,1)*mat2gray(sum(data.heatmap(:,:,:,i),3)); 41 | imshow(hmap,cmap); 42 | % 2D optimized pose 43 | subplot('position',[1/nPlot 0 1/nPlot 1]); 44 | imshow(data.img(:,:,:,i)); 45 | vis2Dskel(output.W_proj(2*i-1:2*i,:)*data.scale,dict.skel); 46 | % 3D reconstructed pose 47 | subplot('position',[2/nPlot 0 1/nPlot 1]); 48 | vis3Dskel(output.S_refine(3*i-2:3*i,:),dict.skel); 49 | % 3D reconstructed pose in novel view 50 | subplot('position',[3/nPlot 0 1/nPlot 1]); 51 | vis3Dskel(output.S_refine(3*i-2:3*i,:),dict.skel,'viewpoint',[-90 0]); 52 | camroll(5); 53 | pause(0.01); 54 | end -------------------------------------------------------------------------------- /demoHG.m: -------------------------------------------------------------------------------- 1 | % This script demonstrates how to use: 2 | % the proposed EM algorithm + pose dictionary learned from Human3.6M 3 | % + the most recent CNN based 2D detector "Hourglass network" 4 | % (https://github.com/anewell/pose-hg-demo) 5 | % to reconstruct 3D human poses from a sequence of images 6 | % The images should have been centered at the subject and cropped 7 | % and all cropped images are saved in a folder 8 | % the heatmaps can be generated by running the HG model: 9 | % (1) go to pose-hg-demo folder 10 | % (2) run in command line 11 | % > bash model.sh 12 | % to download the pre-trained hourglass model 13 | % (3) run in command line: 14 | % > th run-hg.lua ImageFolderName ImageFileExtension 15 | % for example: th run-hg.lua ../data/tennis jpg 16 | % make sure Torch has been installed and run correctly 17 | 18 | clear 19 | startup 20 | 21 | %% 22 | 23 | datapath = 'data/tennis/'; 24 | 25 | % read images 26 | filelist = dir([datapath '/*.jpg']); 27 | imagelist = {filelist.name}; 28 | nImg = length(imagelist); 29 | image = []; 30 | for i = 1:nImg 31 | image = cat(4,image,imread(sprintf('%s/%s',datapath,imagelist{i}))); 32 | end 33 | 34 | % read heatmaps generated by the Hourglass model 35 | % and stack the heatmaps of all frames 36 | heatmap = []; 37 | for i = 1:nImg 38 | hm = hdf5read(sprintf('%s/%s.h5',datapath,imagelist{i}(1:end-4)),'heatmap'); 39 | % transpose heatmaps to make it consistent with the MATLAB x-y directions 40 | heatmap = cat(4,heatmap,permute(hm,[2,1,3])); 41 | end 42 | 43 | %% load dictionary learned from Human3.6M or CMU 44 | 45 | % dict = load('dict/poseDict-all-K128'); % a general pose dict 46 | % dictDataset = 'hm36m'; 47 | dict = load('dict/tennis_forehand.mat'); % a motion-specific dict 48 | dictDataset = 'cmu'; 49 | 50 | % convert dictionary format 51 | % because the joint order in MPII is different from that in Human3.6M 52 | dict = getMPIIdict(dict,dictDataset); 53 | numKp = length(dict.skel.tree); 54 | 55 | %% EM 56 | output = PoseFromVideo('heatmap',heatmap,'dict',dict); 57 | % get estimated poses coordinates for EM output 58 | % the estimated 2D joint location is w.r.t. the bounding box 59 | % need to be converted to the original image coordinates 60 | preds_2d = zeros(2,16,nImg); 61 | preds_3d = zeros(3,16,nImg); 62 | for i = 1:nImg 63 | center = [size(image,2);size(image,1)]/2; 64 | scale = size(image,1)/200; 65 | preds_2d(:,:,i) = transformMPII(output.W_final(2*i-1:2*i,:),center,scale,[size(heatmap,1) size(heatmap,2)],1); 66 | preds_3d(:,:,i) = output.S_final(3*i-2:3*i,:); 67 | end 68 | 69 | %% visualize 70 | 71 | nPlot = 4; 72 | figure('position',[300 300 200*nPlot 200]); 73 | 74 | for i = 1:nImg 75 | 76 | clf 77 | 78 | subplot(1,nPlot,1); 79 | imshow(image(:,:,:,i)); 80 | 81 | subplot(1,nPlot,2); 82 | imagesc(mat2gray(sum(heatmap(:,:,:,i),3))); 83 | axis equal off 84 | 85 | subplot(1,nPlot,3); 86 | imshow(image(:,:,:,i)); 87 | vis2Dskel(preds_2d(:,:,i),dict.skel); 88 | 89 | subplot(1,nPlot,4); 90 | vis3Dskel(preds_3d(:,:,i),dict.skel,'viewpoint',[-90 0]); 91 | 92 | pause(0.01) 93 | 94 | end 95 | 96 | -------------------------------------------------------------------------------- /demoMPII.m: -------------------------------------------------------------------------------- 1 | % This script demonstrates how to use: 2 | % the proposed EM algorithm + pose dictionary learned from Human3.6M 3 | % + the most recent CNN based 2D detector "Hourglass network" 4 | % (https://github.com/anewell/pose-hg-demo) 5 | % We use the first image in the validation set of MPII as example 6 | 7 | clear 8 | 9 | datapath = 'data/mpii/'; 10 | 11 | % list of validation images in MPII 12 | fileID = fopen([datapath 'annot/valid_images.txt']); 13 | imgList = textscan(fileID,'%s'); 14 | fclose(fileID); 15 | 16 | % load dictionary learned from Human3.6M 17 | dict = load('dict/poseDict-all-K128'); 18 | dictDataset = 'hm36m'; 19 | 20 | % convert dictionary format 21 | % because the joint order in MPII is different from that in Human3.6M 22 | dict = getMPIIdict(dict,dictDataset); 23 | numKp = length(dict.skel.tree); 24 | 25 | % read MPII annotation 26 | h5File = [datapath 'annot/valid.h5']; 27 | scales = hdf5read(h5File,'scale'); 28 | centers = hdf5read(h5File,'center'); 29 | parts = hdf5read(h5File,'part'); 30 | 31 | %% process the first image 32 | i = 1; 33 | 34 | % read heatmaps generated by the Hourglass model 35 | % see data/mpii/main-heatmaps.lua for how to run Hourglass on MPII and save heatmaps 36 | % if you are processing a seqeunce, stack the heatmaps of all frames see demoHG for example 37 | heatmap = hdf5read(sprintf('%s/test-valid/valid%d.h5',datapath,i),'heatmaps'); 38 | % transpose heatmaps to make it consistent with the MATLAB x-y directions 39 | heatmap = permute(heatmap,[2,1,3]); 40 | 41 | % EM 42 | % set beta and gamma to be zero because you are processing single images 43 | output = PoseFromVideo('heatmap',heatmap,'dict',dict); 44 | % get estimated poses coordinates for EM output 45 | % the estimated 2D joint location is w.r.t. the bounding box 46 | % need to be converted to the original image coordinates 47 | preds_2d = transformMPII(output.W_final,centers(:,i),scales(i),[size(heatmap,1) size(heatmap,2)],1); 48 | preds_3d = output.S_final; 49 | 50 | 51 | %% visualize 52 | 53 | nPlot = 4; 54 | figure('position',[300 300 200*nPlot 200]); 55 | 56 | subplot(1,nPlot,1); 57 | I = imread(sprintf('%s/images/%s',datapath,imgList{1}{i})); 58 | imshow(I); hold on 59 | vis2Dmarker(parts(:,:,i)); 60 | title('image+gt') 61 | 62 | subplot(1,nPlot,2); 63 | imagesc(mat2gray(sum(heatmap,3))); 64 | axis equal off 65 | title('heatmap') 66 | 67 | subplot(1,nPlot,3); 68 | imshow(I); 69 | vis2Dskel(preds_2d,dict.skel); 70 | title('2D estimates') 71 | 72 | subplot(1,nPlot,4); 73 | vis3Dskel(preds_3d(:,:,i),dict.skel,'viewpoint',[-90 0]); 74 | title('3D (novel view)') 75 | 76 | -------------------------------------------------------------------------------- /dict/poseDict-Posing-K64.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/dict/poseDict-Posing-K64.mat -------------------------------------------------------------------------------- /dict/poseDict-all-K128.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/dict/poseDict-all-K128.mat -------------------------------------------------------------------------------- /dict/tennis_forehand.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/dict/tennis_forehand.mat -------------------------------------------------------------------------------- /em/estimateC_fused.m: -------------------------------------------------------------------------------- 1 | function [C,info] = estimateC_fused(W,R,B,C,alpha,beta,tol) 2 | 3 | % assume W and B have been centralized!!! 4 | 5 | % INPUT: 6 | % W: 2F-by-P matrix 7 | % R: 2F-by-3 matrix 8 | % B: 3K-by-P matrx 9 | % C: F-by-K vector 10 | 11 | P = size(W,2); 12 | F = size(W,1)/2; 13 | K = size(B,1)/3; 14 | 15 | % reshape R 16 | Rdiag = zeros(2*F,3*F); 17 | for i = 1:F 18 | Rdiag(2*i-1:2*i,3*i-2:3*i) = R(2*i-1:2*i,:); 19 | end 20 | 21 | C0 = C; % C0: the previous estimate 22 | t = 1; % auxiliary variable for nesterov 23 | t0 = 1; % auxiliary variable for nesterov 24 | fval = inf; 25 | 26 | % next we work on the linear system yi = X(Ri)*Ci 27 | % compute gradient for each Ci 28 | ytX = zeros(F,K); 29 | XtX = zeros(K,K,F); 30 | for i = 1:F 31 | y = W(2*i-1:2*i,:); 32 | y = y(:); 33 | X = zeros(2*P,K); % each column is a rotated Bk 34 | for k = 1:K 35 | RBk = R(2*i-1:2*i,:)*B(3*k-2:3*k,:); 36 | X(:,k) = RBk(:); 37 | end 38 | ytX(i,:) = y'*X; 39 | XtX(:,:,i) = X'*X; 40 | end 41 | % for fused term 42 | A = zeros(F-1,F); 43 | A(1:F:end) = 1; 44 | A(F:F:end) = -1; 45 | AtA = A'*A; 46 | 47 | % mu should be larger than the 2-norm of the Hessian of f(C) 48 | mu = (norm(XtX(:,:,1))+beta*norm(AtA))*2; 49 | 50 | for iter = 1:500 51 | 52 | % Z is an auxiliary variable in nesterov method 53 | Z = C + (t0-1)/t*(C-C0); 54 | 55 | % gradient descent 56 | G = zeros(F,K); 57 | for i = 1:F 58 | G(i,:) = - ytX(i,:) + Z(i,:)*XtX(:,:,i); 59 | end 60 | G = G + beta*AtA*Z; 61 | Z = Z - G/mu; 62 | 63 | % nonegative thresholding 64 | % Z = Z - alpha/mu; 65 | % Z = max(Z,0); 66 | 67 | % soft thresholding 68 | Z = sign(Z).*max(abs(Z)-alpha/mu,0); 69 | 70 | % update C 71 | C0 = C; 72 | C = Z; 73 | 74 | % update t 75 | t0 = t; 76 | t = (1+sqrt(1+4*t^2))/2; 77 | 78 | % function value 79 | fval_pre = fval; 80 | S = composeShape(B,C); 81 | loss = 1/2 * norm(W-Rdiag*S,'fro')^2; 82 | penalty = alpha * sum(abs(C(:))) ... 83 | + beta/2 * norm(C(1:end-1,:)-C(2:end,:),'fro')^2; 84 | fval = loss + penalty; 85 | if fval > fval_pre 86 | t0 = 1; % APG with restart 87 | t = 1; 88 | end 89 | % fprintf('Iter %d: FunVal = %f, RelChg = %f\n',iter,fval,RelChg); 90 | 91 | % check convergence 92 | RelChg = norm(C-C0,'fro')/(norm(C0,'fro')+eps); 93 | if RelChg < tol 94 | break 95 | end 96 | 97 | end 98 | 99 | info.fval = fval; 100 | info.loss = loss; 101 | info.penalty = penalty; 102 | 103 | end 104 | 105 | function S = composeShape(B,C) 106 | 107 | f = size(C,1); 108 | p = size(B,2); 109 | k = size(B,1)/3; 110 | 111 | B = reshape(B',3*p,k); 112 | S = B*C'; 113 | S = reshape(S,p,3*f)'; 114 | 115 | end -------------------------------------------------------------------------------- /em/estimateR_fused.m: -------------------------------------------------------------------------------- 1 | function [R,fval] = estimateR_fused(S,W,lambda,R0,tol) 2 | 3 | F = size(S,1)/3; 4 | P = size(S,2); 5 | S1 = zeros(3,P,F); 6 | W1 = zeros(2,P,F); 7 | R1 = zeros(3,3,F); 8 | for i = 1:F 9 | S1(:,:,i) = S(3*i-2:3*i,:); 10 | W1(:,:,i) = W(2*i-1:2*i,:); 11 | R1(:,:,i) = [R0(2*i-1:2*i,:);cross(R0(2*i-1,:),R0(2*i,:))]; 12 | end 13 | 14 | [R2,fval] = updateRotations(W1,S1,lambda,R1,tol); 15 | R = zeros(size(R0)); 16 | for i = 1:F 17 | R(2*i-1:2*i,:) = R2(1:2,:,i); 18 | end 19 | 20 | end 21 | 22 | 23 | function [R,fval,info] = updateRotations(W,S,lambda,R0,tol) 24 | %function R = updateRotations(W,S,lambda,R0) 25 | % minimize .5* sum_{i=1}^F ||W(:,:,i)-I_{23}*R(:,:,i)*S(:,:,i)||_F^2 + 26 | % .5*lambda * sum_{i=1}^{F-1} ||R_i-R_{i+1}||_F^2 27 | % w.r.t. R in SO(3)^F 28 | % 29 | % F : number of frames 30 | % P : number of points 31 | % W : 2xPxF 32 | % S : 3xPxF 33 | % R0: 3x3xF 34 | % R : 3x3xF 35 | 36 | warning('off','manopt:getHessian:approx'); 37 | DebugMode = false; 38 | options.verbosity = 0; 39 | options.tolgradnorm = tol; 40 | options.maxiter = 50; 41 | % options.verbosity = 3; 42 | 43 | % initialization 44 | if nargin < 4 45 | X0 = repmat(eye(3),[1 1 F]); 46 | else 47 | X0 = R0; 48 | end 49 | 50 | F = size(W,3); 51 | 52 | % Create the problem structure. 53 | manifold = rotationsfactory(3, F); 54 | problem.M = manifold; 55 | problem.cost = @cost; 56 | problem.egrad = @egrad; 57 | 58 | 59 | % Cost function 60 | function totalcost = cost(X) 61 | 62 | P2 = [1 0 0; 0 1 0]; 63 | 64 | totalcost = 0; 65 | for i=1:F 66 | totalcost = totalcost + .5*norm(W(:,:,i)- P2*X(:,:,i)*S(:,:,i),'fro')^2; 67 | if i < F 68 | totalcost = totalcost + .5*lambda*norm(X(:,:,i)-X(:,:,i+1),'fro')^2; 69 | end 70 | end 71 | end 72 | 73 | % Euclidean gradient of the cost function 74 | function g = egrad(X) 75 | 76 | P2 = [1 0 0; 0 1 0]; 77 | 78 | g = zeros(size(X)); 79 | 80 | for i=1:F 81 | g(:,:,i) =g(:,:,i) - P2'*W(:,:,i)*S(:,:,i)' + ... 82 | (P2'*P2)*X(:,:,i)*S(:,:,i)*S(:,:,i)'; 83 | if i < F 84 | g(:,:,i) =g(:,:,i)-lambda*X(:,:,i+1); 85 | end 86 | 87 | if i>1 88 | g(:,:,i) = g(:,:,i)-lambda*X(:,:,i-1); 89 | end 90 | end 91 | 92 | end 93 | 94 | % Numerically check gradient consistency (optional). 95 | if DebugMode 96 | checkgradient(problem); 97 | pause(0.1) 98 | end 99 | 100 | % solve 101 | [R, fval, info] = trustregions(problem,X0,options); 102 | 103 | % Display some statistics. 104 | if DebugMode 105 | figure, 106 | semilogy([info.iter], [info.cost], '.-'); 107 | xlabel('Iteration number'); 108 | ylabel('Cost'); 109 | end 110 | 111 | end 112 | 113 | -------------------------------------------------------------------------------- /em/findWmax.m: -------------------------------------------------------------------------------- 1 | function [W_max,score] = findWmax(heatmap) 2 | 3 | W_max = zeros(2*size(heatmap,4),size(heatmap,3)); 4 | score = zeros(size(heatmap,4),size(heatmap,3)); 5 | for j = 1:size(W_max,1)/2 6 | for i = 1:size(heatmap,3) 7 | score(j,i) = max(max(heatmap(:,:,i,j))); 8 | [u,v] = find(heatmap(:,:,i,j)==score(j,i),1); 9 | W_max(2*j-1:2*j,i) = [v;u]; 10 | end 11 | end -------------------------------------------------------------------------------- /em/rotateS.m: -------------------------------------------------------------------------------- 1 | function S = rotateS(S,R) 2 | 3 | nFrame = size(S,1)/3; 4 | T = mean(S,2); 5 | S = bsxfun(@minus,S,T); 6 | 7 | for i = 1:nFrame 8 | Ri = [R(2*i-1:2*i,:);cross(R(2*i-1,:),R(2*i,:))]; 9 | S(3*i-2:3*i,:) = Ri * S(3*i-2:3*i,:); 10 | end 11 | 12 | S = bsxfun(@plus,S,T); 13 | -------------------------------------------------------------------------------- /general/alignHuman.m: -------------------------------------------------------------------------------- 1 | function S = alignHuman(S,torso) 2 | 3 | F = size(S,1)/3; 4 | S = bsxfun(@minus,S,mean(S,2)); 5 | 6 | St = S(:,torso); 7 | for i = 2:F 8 | % Procrust Alignment of Torso 9 | Y = findRotation(St(1:3,:),St(3*i-2:3*i,:)); 10 | S(3*i-2:3*i,:) = Y*S(3*i-2:3*i,:); 11 | end 12 | -------------------------------------------------------------------------------- /general/centralize.m: -------------------------------------------------------------------------------- 1 | function S = centralize(S) 2 | 3 | S = bsxfun(@minus,S,mean(S,2)); 4 | -------------------------------------------------------------------------------- /general/compareStructs.m: -------------------------------------------------------------------------------- 1 | function [dist,S2] = compareStructs(S1,S2,rot) 2 | 3 | if nargin < 3 4 | rot = 0; 5 | end 6 | 7 | % compare two structures and align S2 to S1 with similarity transformation 8 | 9 | T1 = mean(S1,2); 10 | S1 = bsxfun(@minus,S1,T1); 11 | S2 = bsxfun(@minus,S2,mean(S2,2)); 12 | 13 | [f,p] = size(S1); 14 | f = f/3; 15 | dist = zeros(f,p); 16 | 17 | if rot == 0 18 | Y = eye(3); 19 | else 20 | Y = findRotation(S1,S2); 21 | end 22 | 23 | for i = 1:f 24 | A = S1(3*i-2:3*i,:); 25 | B = S2(3*i-2:3*i,:); 26 | if rot == 1 27 | Y = findRotation(A,B); 28 | end 29 | % rotate B 30 | B = Y*B; 31 | % scale B 32 | w = trace(A'*B)/(trace(B'*B)+eps); 33 | B = w*B; 34 | % output 35 | dist(i,:) = sqrt(sum((A-B).^2,1)); % average distance 36 | S2(3*i-2:3*i,:) = B; 37 | end 38 | 39 | S2 = bsxfun(@plus,S2,T1); 40 | 41 | end 42 | 43 | function R = findRotation(S1,S2) 44 | [F,P] = size(S1); 45 | F = F/3; 46 | S1 = reshape(S1,3,F*P); 47 | S2 = reshape(S2,3,F*P); 48 | R = S1*S2'; 49 | [U,~,V] = svd(R); 50 | R = U*V'; 51 | % R = U*diag([1 1 det(R)])*V'; 52 | end 53 | -------------------------------------------------------------------------------- /general/computeError2D.m: -------------------------------------------------------------------------------- 1 | function dist = computeError2D(W1,W2) 2 | 3 | dist = zeros(size(W1,1)/2,size(W1,2)); 4 | for i = 1:size(W1,1)/2 5 | dist(i,:) = sqrt(sum((W1(2*i-1:2*i,:)-W2(2*i-1:2*i,:)).^2,1)); 6 | end -------------------------------------------------------------------------------- /general/computeError3D.m: -------------------------------------------------------------------------------- 1 | function dist = computeError3D(S1,S2) 2 | 3 | dist = zeros(size(S1,1)/3,size(S1,2)); 4 | for i = 1:size(S1,1)/3 5 | dist(i,:) = sqrt(sum((S1(3*i-2:3*i,:)-S2(3*i-2:3*i,:)).^2,1)); 6 | end -------------------------------------------------------------------------------- /general/computeErrorPCK.m: -------------------------------------------------------------------------------- 1 | function label = computeErrorPCK(W1,W2,th) 2 | 3 | dist = zeros(size(W1,1)/2,size(W1,2)); 4 | for i = 1:size(W1,1)/2 5 | dist(i,:) = sqrt(sum((W1(2*i-1:2*i,:)-W2(2*i-1:2*i,:)).^2,1)); 6 | end 7 | 8 | label = dist 44 | -------------------------------------------------------------------------------- /manopt/CREDITS.txt: -------------------------------------------------------------------------------- 1 | The core developers of Manopt are 2 | 3 | * Nicolas Boumal 4 | * Bamdev Mishra 5 | 6 | Through the RANSO group, Manopt is supported by 7 | 8 | * Pierre-Antoine Absil 9 | * Yurii Nesterov 10 | * Rodolphe Sepulchre 11 | 12 | We are grateful for the excellent contributions of 13 | 14 | * Pierre Borckmans 15 | * Bart Vandereycken 16 | * Hiroyuki Sato 17 | * Roberto Tron 18 | * Sarod Yatawatta 19 | * Hiroyuki Kasai 20 | 21 | Furthermore, code written by the following people can be found in Manopt: 22 | 23 | * Chris Baker 24 | * Pierre-Antoine Absil 25 | * Kyle Gallivan 26 | * Paolo de Leva 27 | * Wynton Moore 28 | * Michael Kleder 29 | 30 | Each person's contribution is marked by their name in the relevant files. 31 | See http://www.manopt.org/about.html for a more precise breakdown. 32 | -------------------------------------------------------------------------------- /manopt/LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/LICENSE.txt -------------------------------------------------------------------------------- /manopt/README.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/README.txt -------------------------------------------------------------------------------- /manopt/checkinstall/basicexample.m: -------------------------------------------------------------------------------- 1 | function basicexample() 2 | 3 | % Verify that Manopt was indeed added to the Matlab path. 4 | if isempty(which('spherefactory')) 5 | error(['You should first add Manopt to the Matlab path.\n' ... 6 | 'Please run importmanopt first.']); 7 | end 8 | 9 | % Generate the problem data. 10 | n = 1000; 11 | A = randn(n); 12 | A = .5*(A+A'); 13 | 14 | % Create the problem structure. 15 | manifold = spherefactory(n); 16 | problem.M = manifold; 17 | 18 | % Define the problem cost function and its gradient. 19 | problem.cost = @(x) -x'*(A*x); 20 | problem.egrad = @(x) -2*A*x; 21 | problem.ehess = @(x, xdot) -2*A*xdot; 22 | 23 | % Numerically check gradient and Hessian consistency. 24 | figure; 25 | checkgradient(problem); 26 | figure; 27 | checkhessian(problem); 28 | 29 | % Solve. 30 | [x, xcost, info] = trustregions(problem); %#ok 31 | 32 | % Display some statistics. 33 | figure; 34 | semilogy([info.iter], [info.gradnorm], '.-'); 35 | xlabel('Iteration #'); 36 | ylabel('Gradient norm'); 37 | title('Convergence of the trust-regions algorithm on the sphere'); 38 | 39 | end 40 | -------------------------------------------------------------------------------- /manopt/examples/dominant_invariant_subspace_complex.m: -------------------------------------------------------------------------------- 1 | function [X, info] = dominant_invariant_subspace_complex(A, p) 2 | % Returns a unitary basis of the dominant invariant p-subspace of A. 3 | % 4 | % function X = dominant_invariant_subspace(A, p) 5 | % 6 | % Input: A complex, Hermitian matrix A of size nxn and an integer p < n. 7 | % Output: A complex, unitary matrix X of size nxp such that trace(X'*A*X) 8 | % is maximized. That is, the columns of X form a unitary basis 9 | % of a dominant subspace of dimension p of A. 10 | % 11 | % The optimization is performed on the complex Grassmann manifold, since 12 | % only the space spanned by the columns of X matters. 13 | % 14 | % See dominant_invariant_subspace for more details in the real case. 15 | % 16 | % See also: dominant_invariant_subspace grassmanncomplexfactory 17 | 18 | % This file is part of Manopt and is copyrighted. See the license file. 19 | % 20 | % Main author: Nicolas Boumal, June 30, 2015 21 | % Contributors: 22 | % 23 | % Change log: 24 | 25 | % Generate some random data to test the function 26 | if ~exist('A', 'var') || isempty(A) 27 | A = randn(128) + 1i*randn(128); 28 | A = (A+A')/2; 29 | end 30 | if ~exist('p', 'var') || isempty(p) 31 | p = 3; 32 | end 33 | 34 | % Make sure the input matrix is Hermitian 35 | n = size(A, 1); 36 | assert(size(A, 2) == n, 'A must be square.'); 37 | assert(norm(A-A', 'fro') < n*eps, 'A must be Hermitian.'); 38 | assert(p<=n, 'p must be smaller than n.'); 39 | 40 | % Define the cost and its derivatives on the complex Grassmann manifold 41 | Gr = grassmanncomplexfactory(n, p); 42 | problem.M = Gr; 43 | problem.cost = @(X) -real(trace(X'*A*X)); 44 | problem.egrad = @(X) -2*A*X; 45 | problem.ehess = @(X, H) -2*A*H; 46 | 47 | % Execute some checks on the derivatives for early debugging. 48 | % These can be commented out. 49 | % checkgradient(problem); 50 | % pause; 51 | % checkhessian(problem); 52 | % pause; 53 | 54 | % Issue a call to a solver. A random initial guess will be chosen and 55 | % default options are selected except for the ones we specify here. 56 | options.Delta_bar = 8*sqrt(p); 57 | [X, costX, info, options] = trustregions(problem, [], options); %#ok 58 | 59 | fprintf('Options used:\n'); 60 | disp(options); 61 | 62 | % For our information, Manopt can also compute the spectrum of the 63 | % Riemannian Hessian on the tangent space at (any) X. Computing the 64 | % spectrum at the solution gives us some idea of the conditioning of 65 | % the problem. If we were to implement a preconditioner for the 66 | % Hessian, this would also inform us on its performance. 67 | % 68 | % Notice that (typically) all eigenvalues of the Hessian at the 69 | % solution are positive, i.e., we find an isolated minimizer. If we 70 | % replace the Grassmann manifold by the Stiefel manifold, hence still 71 | % optimizing over orthonormal matrices but ignoring the invariance 72 | % cost(XQ) = cost(X) for all Q orthogonal, then we see 73 | % dim O(p) = p(p-1)/2 zero eigenvalues in the Hessian spectrum, making 74 | % the optimizer not isolated anymore. 75 | if Gr.dim() < 512 76 | evs = hessianspectrum(problem, X); 77 | stairs(sort(evs)); 78 | title(['Eigenvalues of the Hessian of the cost function ' ... 79 | 'at the solution']); 80 | xlabel('Eigenvalue number (sorted)'); 81 | ylabel('Value of the eigenvalue'); 82 | end 83 | 84 | end 85 | -------------------------------------------------------------------------------- /manopt/examples/essential_svd.m: -------------------------------------------------------------------------------- 1 | function essential_svd 2 | % Sample solution of an optimization problem on the essential manifold. 3 | % 4 | % Solves the problem \sum_{i=1}^N ||E_i-A_i||^2, where E_i are essential 5 | % matrices. Essential matrices are used in computer vision to represent the 6 | % epipolar constraint between projected points in two perspective views. 7 | % 8 | % Note: the essentialfactory file uses a quotient R1/R2 representation to 9 | % work with essential matrices. On the other hand, from a user point of 10 | % view, it is convenient to use the E representation (a matrix of size 11 | % 3-by-3) to give cost, gradient, and Hessian information. To this end, we 12 | % provide auxiliary files essential_costE2cost, essential_egradE2egrad, and 13 | % essential_ehessE2ehess that convert these ingredients to their R1/R2 14 | % counterparts. 15 | % 16 | % See also: essentialfactory essential_costE2cost essential_egradE2egrad 17 | % essential_ehessE2ehess 18 | 19 | % This file is part of Manopt: www.manopt.org. 20 | % Original author: Roberto Tron, Aug. 8, 2014 21 | % Contributors: Bamdev Mishra, May 15, 2015. 22 | 23 | 24 | % Make data for the test 25 | N = 2; % Number of matrices to process in parallel. 26 | A = multiprod(multiprod(randrot(3, N), essential_hat3([0; 0; 1])), randrot(3, N)); 27 | 28 | % The essential manifold 29 | M = essentialfactory(N); 30 | problem.M = M; 31 | 32 | % Function handles of the essential matrix E and Euclidean gradient and Hessian 33 | costE = @(E) 0.5*sum(multisqnorm(E-A)); 34 | egradE = @(E) E - A; 35 | ehessE = @(E, U) U; 36 | 37 | 38 | % Manopt descriptions 39 | problem.cost = @cost; 40 | function val = cost(X) 41 | val = essential_costE2cost(X, costE); % Cost 42 | end 43 | 44 | problem.egrad = @egrad; 45 | function g = egrad(X) 46 | g = essential_egradE2egrad(X, egradE); % Converts gradient in E to X. 47 | end 48 | 49 | problem.ehess = @ehess; 50 | function gdot = ehess(X, S) 51 | gdot = essential_ehessE2ehess(X, egradE, ehessE, S); % Converts Hessian in E to X. 52 | end 53 | 54 | 55 | % Numerically check the differentials. 56 | % checkgradient(problem); pause; 57 | % checkhessian(problem); pause; 58 | 59 | %Solve the problem 60 | Xsol = trustregions(problem); 61 | 62 | % Distance between original matrices and decompositions 63 | val = essential_costE2cost(Xsol, costE); 64 | fprintf('Distance between original matrices and decompositions is %e \n', val); 65 | 66 | end 67 | -------------------------------------------------------------------------------- /manopt/examples/generalized_eigenvalue_computation.m: -------------------------------------------------------------------------------- 1 | function [Xsol, Ssol] = generalized_eigenvalue_computation(A, B, p) 2 | % Returns orthonormal basis of the dominant invariant p-subspace of B^-1 A. 3 | % 4 | % function [Xsol, Ssol] = generalized_eigenvalue_computation(A, B, p) 5 | % 6 | % Input: A is a real, symmetric matrix of size nxn, 7 | % B is a symmetric positive definite matrix, same size as A, and 8 | % an integer p < n. 9 | % Output: Xsol: a real, orthonormal matrix X of size nxp such that 10 | % trace(X'*A*X) is maximized, subject to X'*B*X being identity. 11 | % That is, the columns of X form an orthonormal basis of a dominant 12 | % subspace of dimension p of B^(-1)*A. These are thus eigenvectors 13 | % associated with the largest eigenvalues of B^(-1)*A (in no 14 | % particular order). Sign is important: 2 is deemed a larger 15 | % eigenvalue than -5. 16 | % Ssol: the eigenvalues associated with the eigenvectors Xsol. 17 | % 18 | % We intend to solve the homogeneous system A*X = B*X*S, 19 | % where S is a diagonal matrix of dominant eigenvalues of B^-1 A. 20 | % 21 | % 22 | % The optimization is performed on the generalized Grassmann manifold, 23 | % since only the space spanned by the columns of X matters. 24 | % 25 | % The optimization problem that we are solving here is 26 | % maximize trace(X'*A*X) subject to X'*B*X = eye(p). 27 | % Consequently, the solutions remain invariant to transformation 28 | % X --> XO, where O is a p-by-p orthogonal matrix. The search space, in 29 | % essence, is set of equivalence classes 30 | % [X] = {XO : X'*B*X = I and O is orthogonal matrix}. This space is called 31 | % the generalized Grassmann manifold. 32 | % 33 | % See also dominant_invariant_subspace nonlinear_eigenspace 34 | 35 | 36 | % This file is part of Manopt and is copyrighted. See the license file. 37 | % 38 | % Main author: Bamdev Mishra, June 30, 2015. 39 | % Contributors: 40 | % Change log: 41 | 42 | % Generate some random data to test the function 43 | if ~exist('A', 'var') || isempty(A) 44 | n = 128; 45 | A = randn(n); 46 | A = (A+A')/2; 47 | end 48 | if ~exist('B', 'var') || isempty(B) 49 | n = size(A, 1); 50 | e = ones(n, 1); 51 | B = spdiags([-e 2*e -e], -1:1, n, n); % Symmetric positive definite 52 | end 53 | 54 | if ~exist('p', 'var') || isempty(p) 55 | p = 3; 56 | end 57 | 58 | % Make sure the input matrix is square and symmetric 59 | n = size(A, 1); 60 | assert(isreal(A), 'A must be real.') 61 | assert(size(A, 2) == n, 'A must be square.'); 62 | assert(norm(A-A', 'fro') < n*eps, 'A must be symmetric.'); 63 | assert(p <= n, 'p must be smaller than n.'); 64 | 65 | % Define the cost and its derivatives on the generalized 66 | % Grassmann manifold, i.e., the column space of all X such that 67 | % X'*B*X is identity. 68 | gGr = grassmanngeneralizedfactory(n, p, B); 69 | 70 | problem.M = gGr; 71 | problem.cost = @(X) -trace(X'*A*X); 72 | problem.egrad = @(X) -2*(A*X); % Only Euclidean gradient needed. 73 | problem.ehess = @(X, H) -2*(A*H); % Only Euclidean Hessian needed. 74 | 75 | % Execute some checks on the derivatives for early debugging. 76 | % These things can be commented out of course. 77 | % checkgradient(problem); 78 | % pause; 79 | % checkhessian(problem); 80 | % pause; 81 | 82 | % Issue a call to a solver. A random initial guess will be chosen and 83 | % default options are selected except for the ones we specify here. 84 | options.Delta_bar = 8*sqrt(p); 85 | [Xsol, costXsol, info] = trustregions(problem, [], options); %#ok 86 | 87 | % To extract the eigenvalues, solve the small p-by-p symmetric 88 | % eigenvalue problem. 89 | Ssol = eig(Xsol'*(A*Xsol)); 90 | 91 | end 92 | -------------------------------------------------------------------------------- /manopt/examples/nonlinear_eigenspace.m: -------------------------------------------------------------------------------- 1 | function Xsol = nonlinear_eigenspace(L, k, alpha) 2 | % Example of nonlinear eigenvalue problem: total energy minimization. 3 | % 4 | % function Xsol = nonlinear_eigenspace(L, k, alpha) 5 | % 6 | % L is a discrete Laplacian operator, 7 | % alpha is a given constant, and 8 | % k corresponds to the dimension of the least eigenspace sought. 9 | % 10 | % This example demonstrates how to use the Grassmann geometry factory 11 | % to solve the nonlinear eigenvalue problem as the optimization problem: 12 | % 13 | % minimize 0.5*trace(X'*L*X) + (alpha/4)*(rho(X)*L\(rho(X))) 14 | % over X such that X'*X = Identity, 15 | % 16 | % where L is of size n-by-n, 17 | % X is an n-by-k matrix, and 18 | % rho(X) is the diagonal part of X*X'. 19 | % 20 | % This example is motivated in the paper 21 | % "A Riemannian Newton Algorithm for Nonlinear Eigenvalue Problems", 22 | % Zhi Zhao, Zheng-Jian Bai, and Xiao-Qing Jin, 23 | % SIAM Journal on Matrix Analysis and Applications, 36(2), 752-774, 2015. 24 | % 25 | 26 | 27 | % This file is part of Manopt and is copyrighted. See the license file. 28 | % 29 | % Main author: Bamdev Mishra, June 19, 2015. 30 | % Contributors: 31 | % 32 | % Change log: 33 | 34 | 35 | % If no inputs are provided, generate a discrete Laplacian operator. 36 | % This is for illustration purposes only. 37 | % The default example corresponds to Case (c) of Example 6.2 of the 38 | % above referenced paper. 39 | 40 | if ~exist('L', 'var') || isempty(L) 41 | n = 100; 42 | L = gallery('tridiag', n, -1, 2, -1); 43 | end 44 | 45 | n = size(L, 1); 46 | assert(size(L, 2) == n, 'L must be square.'); 47 | 48 | if ~exist('k', 'var') || isempty(k) || k > n 49 | k = 10; 50 | end 51 | 52 | if ~exist('alpha', 'var') || isempty(alpha) 53 | alpha = 1; 54 | end 55 | 56 | 57 | % Grassmann manifold description 58 | Gr = grassmannfactory(n, k); 59 | problem.M = Gr; 60 | 61 | % Cost function evaluation 62 | problem.cost = @cost; 63 | function val = cost(X) 64 | rhoX = sum(X.^2, 2); % diag(X*X'); 65 | val = 0.5*trace(X'*(L*X)) + (alpha/4)*(rhoX'*(L\rhoX)); 66 | end 67 | 68 | % Euclidean gradient evaluation 69 | % Note: Manopt automatically converts it to the Riemannian counterpart. 70 | problem.egrad = @egrad; 71 | function g = egrad(X) 72 | rhoX = sum(X.^2, 2); % diag(X*X'); 73 | g = L*X + alpha*diag(L\rhoX)*X; 74 | end 75 | 76 | % Euclidean Hessian evaluation 77 | % Note: Manopt automatically converts it to the Riemannian counterpart. 78 | problem.ehess = @ehess; 79 | function h = ehess(X, U) 80 | rhoX = sum(X.^2, 2); %diag(X*X'); 81 | rhoXdot = 2*sum(X.*U, 2); 82 | h = L*U + alpha*diag(L\rhoXdot)*X + alpha*diag(L\rhoX)*U; 83 | end 84 | 85 | 86 | % Check whether gradient and Hessian computations are correct. 87 | % checkgradient(problem); 88 | % pause; 89 | % checkhessian(problem); 90 | % pause; 91 | 92 | 93 | % Initialization as suggested in above referenced paper. 94 | X = randn(n, k); 95 | [U, S, V] = svd(X, 0); %#ok 96 | X = U*V'; 97 | [U0, S0, V0] = eigs(L + alpha*diag(L\(sum(X.^2, 2))), k,'sm'); %#ok 98 | X0 = U0; 99 | 100 | % Call manoptsolve to automatically call an appropriate solver. 101 | % Note: it calls the trust regions solver as we have all the required 102 | % ingredients, namely, gradient and Hessian, information. 103 | Xsol = manoptsolve(problem, X0); 104 | 105 | end 106 | -------------------------------------------------------------------------------- /manopt/importmanopt.m: -------------------------------------------------------------------------------- 1 | % Add Manopt to the path to make all manopt components available. 2 | 3 | % This file is part of Manopt: www.manopt.org. 4 | % Original author: Nicolas Boumal, Jan. 3, 2013. 5 | % Contributors: 6 | % Change log: 7 | % Aug. 7, 2013 (NB): Changed to work without the import command 8 | % (new structure of the toolbox). 9 | % Aug. 8, 2013 (NB): Changed to use addpath_recursive, home brewed. 10 | % Aug. 22, 2013 (NB): Using genpath instead of home cooked 11 | % addpath_recursive. 12 | 13 | addpath(pwd); 14 | 15 | % Recursively add Manopt directories to the Matlab path. 16 | cd manopt; 17 | addpath(genpath(pwd)); 18 | cd ..; 19 | -------------------------------------------------------------------------------- /manopt/manopt/core/applyStatsfun.m: -------------------------------------------------------------------------------- 1 | function stats = applyStatsfun(problem, x, storedb, key, options, stats) 2 | % Apply the statsfun function to a stats structure (for solvers). 3 | % 4 | % function stats = applyStatsfun(problem, x, storedb, key, options, stats) 5 | % 6 | % Applies the options.statsfun user supplied function (if it was provided) 7 | % to the stats structure, and returns the (possibly) modified stats 8 | % structure. 9 | % 10 | % storedb is a StoreDB object, key is the StoreDB key to point x. 11 | % 12 | % Note: if statsfun accepts a store structure as input, this structure can 13 | % be read but not modified (modifications will be lost) ; the store 14 | % structure will contain the store.shared field. 15 | % 16 | % See also: 17 | 18 | % This file is part of Manopt: www.manopt.org. 19 | % Original author: Nicolas Boumal, April 3, 2013. 20 | % Contributors: 21 | % Change log: 22 | % 23 | % April 3, 2015 (NB): 24 | % Works with the new StoreDB class system. 25 | 26 | if isfield(options, 'statsfun') 27 | 28 | switch nargin(options.statsfun) 29 | case 3 30 | stats = options.statsfun(problem, x, stats); 31 | case 4 32 | % Obtain, pass along, and save the store for x. 33 | % get/setWithShared must come in pairs. 34 | store = storedb.getWithShared(key); 35 | stats = options.statsfun(problem, x, stats, store); 36 | storedb.setWithShared(store, key); 37 | otherwise 38 | warning('manopt:statsfun', ... 39 | 'statsfun unused: wrong number of inputs'); 40 | end 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetApproxHessian.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetApproxHessian(problem) 2 | % Checks whether an approximate Hessian can be computed for this problem. 3 | % 4 | % function candoit = canGetApproxHessian(problem) 5 | % 6 | % Returns true if an approximate Hessian of the cost function is provided 7 | % in the given problem description, false otherwise. 8 | % If a Hessian is defined but no approximate Hessian is defined explicitly, 9 | % returns false. 10 | % 11 | % Even if this returns false, calls to getApproxHessian may succeed, as 12 | % they will be redirected to getHessianFD. The latter simply requires 13 | % availability of gradients in problem, and vector transports in problem.M. 14 | % 15 | % See also: canGetHessian getHessianFD 16 | 17 | % This file is part of Manopt: www.manopt.org. 18 | % Original author: Nicolas Boumal, April 8, 2015. 19 | % Contributors: 20 | % Change log: 21 | 22 | candoit = isfield(problem, 'approxhess'); 23 | 24 | end 25 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetCost.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetCost(problem) 2 | % Checks whether the cost function can be computed for a problem structure. 3 | % 4 | % function candoit = canGetCost(problem) 5 | % 6 | % Returns true if the cost function can be computed given the problem 7 | % description, false otherwise. 8 | % 9 | % See also: getCost canGetDirectionalDerivative canGetGradient canGetHessian 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, Dec. 30, 2012. 13 | % Contributors: 14 | % Change log: 15 | 16 | 17 | candoit = isfield(problem, 'cost') || isfield(problem, 'costgrad'); 18 | 19 | end 20 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetDirectionalDerivative.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetDirectionalDerivative(problem) 2 | % Checks whether dir. derivatives can be computed for a problem structure. 3 | % 4 | % function candoit = canGetDirectionalDerivative(problem) 5 | % 6 | % Returns true if the directional derivatives of the cost function can be 7 | % computed given the problem description, false otherwise. 8 | % 9 | % See also: canGetCost canGetGradient canGetHessian 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, Dec. 30, 2012. 13 | % Contributors: 14 | % Change log: 15 | 16 | candoit = isfield(problem, 'diff') || canGetGradient(problem); 17 | 18 | end 19 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetEuclideanGradient.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetEuclideanGradient(problem) 2 | % Checks whether the Euclidean gradient can be computed for a problem. 3 | % 4 | % function candoit = canGetEuclideanGradient(problem) 5 | % 6 | % Returns true if the Euclidean gradient can be computed given the problem 7 | % description, false otherwise. 8 | % 9 | % See also: canGetGradient getEuclideanGradient 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, Dec. 30, 2012. 13 | % Contributors: 14 | % Change log: 15 | 16 | 17 | candoit = isfield(problem, 'egrad'); 18 | 19 | end 20 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetGradient.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetGradient(problem) 2 | % Checks whether the gradient can be computed for a problem structure. 3 | % 4 | % function candoit = canGetGradient(problem) 5 | % 6 | % Returns true if the gradient of the cost function can be computed given 7 | % the problem description, false otherwise. 8 | % 9 | % See also: canGetCost canGetDirectionalDerivative canGetHessian 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, Dec. 30, 2012. 13 | % Contributors: 14 | % Change log: 15 | 16 | candoit = isfield(problem, 'grad') || isfield(problem, 'costgrad') || ... 17 | canGetEuclideanGradient(problem); 18 | 19 | end 20 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetHessian.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetHessian(problem) 2 | % Checks whether the Hessian can be computed for a problem structure. 3 | % 4 | % function candoit = canGetHessian(problem) 5 | % 6 | % Returns true if the Hessian of the cost function can be computed given 7 | % the problem description, false otherwise. 8 | % 9 | % See also: canGetCost canGetDirectionalDerivative canGetGradient 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, Dec. 30, 2012. 13 | % Contributors: 14 | % Change log: 15 | 16 | candoit = isfield(problem, 'hess') || ... 17 | (isfield(problem, 'ehess') && canGetEuclideanGradient(problem)); 18 | 19 | if ~candoit && ... 20 | (isfield(problem, 'ehess') && ~canGetEuclideanGradient(problem)) 21 | warning('manopt:canGetHessian', ... 22 | ['If the Hessian is supplied as a Euclidean Hessian (ehess), ' ... 23 | 'then the Euclidean gradient must also be supplied (egrad).']); 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetLinesearch.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetLinesearch(problem) 2 | % Checks whether the problem structure can give a line-search a hint. 3 | % 4 | % function candoit = canGetLinesearch(problem) 5 | % 6 | % Returns true if the the problem description includes a mechanism to give 7 | % line-search algorithms a hint as to "how far to look", false otherwise. 8 | % 9 | % See also: getLinesearch 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, July 17, 2014. 13 | % Contributors: 14 | % Change log: 15 | 16 | 17 | candoit = isfield(problem, 'linesearch'); 18 | 19 | end 20 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetPrecon.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetPrecon(problem) 2 | % Checks whether a preconditioner was specified in the problem description. 3 | % 4 | % function candoit = canGetPrecon(problem) 5 | % 6 | % Returns true if a preconditioner was specified, false otherwise. Notice 7 | % that even if this function returns false, it is still possible to call 8 | % getPrecon, as the default preconditioner is simply the identity operator. 9 | % This check function is mostly useful to tell whether that default 10 | % preconditioner will be in use or not. 11 | % 12 | % See also: getPrecon getSqrtPrecon canGetSqrtPrecon getHessian 13 | 14 | % This file is part of Manopt: www.manopt.org. 15 | % Original author: Nicolas Boumal, July 3, 2013. 16 | % Contributors: 17 | % Change log: 18 | 19 | candoit = isfield(problem, 'precon') || canGetSqrtPrecon(problem); 20 | 21 | end 22 | -------------------------------------------------------------------------------- /manopt/manopt/core/canGetSqrtPrecon.m: -------------------------------------------------------------------------------- 1 | function candoit = canGetSqrtPrecon(problem) 2 | % Checks whether a square root of preconditioner was specified in problem. 3 | % 4 | % function candoit = canGetSqrtPrecon(problem) 5 | % 6 | % Returns true if the problem structure allows for applying the square root 7 | % of a preconditioner to tangent vectors at a given point. The square root 8 | % of the preconditioner at x must be a symmetric, positive definite 9 | % operator Q such that applying Q twice (Q o Q) amounts to applying the 10 | % preconditioner once. If both a preconditioner and a square root of 11 | % preconditioner are provided, it is the user's responsibility to ensure 12 | % their compatibility. 13 | % 14 | % Similarly to getPrecon, if the present function returns false, calls to 15 | % getSqrtPrecon will still work: they will act as the identity. Note that 16 | % this may be incompatible with the preconditioner if it is given. Thus, 17 | % always check by calling canGetSqrtPrecon first. 18 | % 19 | % See also: canGetPrecon getSqrtPrecon getPrecon 20 | 21 | % This file is part of Manopt: www.manopt.org. 22 | % Original author: Nicolas Boumal, April 3, 2015. 23 | % Contributors: 24 | % Change log: 25 | 26 | candoit = isfield(problem, 'sqrtprecon'); 27 | 28 | end 29 | -------------------------------------------------------------------------------- /manopt/manopt/core/getApproxHessian.m: -------------------------------------------------------------------------------- 1 | function approxhess = getApproxHessian(problem, x, d, storedb, key) 2 | % Computes an approximation of the Hessian of the cost fun. at x along d. 3 | % 4 | % function approxhess = getApproxHessian(problem, x, d) 5 | % function approxhess = getApproxHessian(problem, x, d, storedb) 6 | % function approxhess = getApproxHessian(problem, x, d, storedb, key) 7 | % 8 | % Returns an approximation of the Hessian at x along d of the cost function 9 | % described in the problem structure. 10 | % 11 | % storedb is a StoreDB object, key is the StoreDB key to point x. 12 | % 13 | % If no approximate Hessian was provided, this call is redirected to 14 | % getHessianFD. 15 | % 16 | % See also: getHessianFD canGetApproxHessian 17 | 18 | % This file is part of Manopt: www.manopt.org. 19 | % Original author: Nicolas Boumal, Dec. 30, 2012. 20 | % Contributors: 21 | % Change log: 22 | % 23 | % April 3, 2015 (NB): 24 | % Works with the new StoreDB class system. 25 | 26 | % Allow omission of the key, and even of storedb. 27 | if ~exist('key', 'var') 28 | if ~exist('storedb', 'var') 29 | storedb = StoreDB(); 30 | end 31 | key = storedb.getNewKey(); 32 | end 33 | 34 | 35 | if isfield(problem, 'approxhess') 36 | %% Compute the approximate Hessian using approxhess. 37 | 38 | % Check whether this function wants to deal with storedb or not. 39 | switch nargin(problem.approxhess); 40 | case 2 41 | approxhess = problem.approxhess(x, d); 42 | case 3 43 | % Obtain, pass along, and save the store for x. 44 | store = storedb.getWithShared(key); 45 | [approxhess, store] = problem.approxhess(x, d, store); 46 | storedb.setWithShared(store, key); 47 | case 4 48 | % Pass along the whole storedb (by reference), with key. 49 | approxhess = problem.approxhess(x, d, storedb, key); 50 | otherwise 51 | up = MException('manopt:getApproxHessian:badapproxhess', ... 52 | 'approxhess should accept 2, 3 or 4 inputs.'); 53 | throw(up); 54 | end 55 | 56 | else 57 | %% Try to fall back to a standard FD approximation. 58 | 59 | approxhess = getHessianFD(problem, x, d, storedb, key); 60 | 61 | end 62 | 63 | end 64 | -------------------------------------------------------------------------------- /manopt/manopt/core/getCost.m: -------------------------------------------------------------------------------- 1 | function cost = getCost(problem, x, storedb, key) 2 | % Computes the cost function at x. 3 | % 4 | % function cost = getCost(problem, x) 5 | % function cost = getCost(problem, x, storedb) 6 | % function cost = getCost(problem, x, storedb, key) 7 | % 8 | % Returns the value at x of the cost function described in the problem 9 | % structure. 10 | % 11 | % storedb is a StoreDB object, key is the StoreDB key to point x. 12 | % 13 | % See also: canGetCost 14 | 15 | % This file is part of Manopt: www.manopt.org. 16 | % Original author: Nicolas Boumal, Dec. 30, 2012. 17 | % Contributors: 18 | % Change log: 19 | % 20 | % April 3, 2015 (NB): 21 | % Works with the new StoreDB class system. 22 | 23 | % Allow omission of the key, and even of storedb. 24 | if ~exist('key', 'var') 25 | if ~exist('storedb', 'var') 26 | storedb = StoreDB(); 27 | end 28 | key = storedb.getNewKey(); 29 | end 30 | 31 | 32 | if isfield(problem, 'cost') 33 | %% Compute the cost function using cost. 34 | 35 | % Check whether this function wants to deal with storedb or not. 36 | switch nargin(problem.cost) 37 | case 1 38 | cost = problem.cost(x); 39 | case 2 40 | % Obtain, pass along, and save the store for x. 41 | store = storedb.getWithShared(key); 42 | [cost, store] = problem.cost(x, store); 43 | storedb.setWithShared(store, key); 44 | case 3 45 | % Pass along the whole storedb (by reference), with key. 46 | cost = problem.cost(x, storedb, key); 47 | otherwise 48 | up = MException('manopt:getCost:badcost', ... 49 | 'cost should accept 1, 2 or 3 inputs.'); 50 | throw(up); 51 | end 52 | 53 | elseif isfield(problem, 'costgrad') 54 | %% Compute the cost function using costgrad. 55 | 56 | % Check whether this function wants to deal with storedb or not. 57 | switch nargin(problem.costgrad) 58 | case 1 59 | cost = problem.costgrad(x); 60 | case 2 61 | % Obtain, pass along, and save the store for x. 62 | store = storedb.getWithShared(key); 63 | [cost, grad, store] = problem.costgrad(x, store); %#ok 64 | storedb.setWithShared(store, key); 65 | case 3 66 | % Pass along the whole storedb (by reference), with key. 67 | cost = problem.costgrad(x, storedb, key); 68 | otherwise 69 | up = MException('manopt:getCost:badcostgrad', ... 70 | 'costgrad should accept 1, 2 or 3 inputs.'); 71 | throw(up); 72 | end 73 | 74 | else 75 | %% Abandon computing the cost function. 76 | 77 | up = MException('manopt:getCost:fail', ... 78 | ['The problem description is not explicit enough to ' ... 79 | 'compute the cost.']); 80 | throw(up); 81 | 82 | end 83 | 84 | end 85 | -------------------------------------------------------------------------------- /manopt/manopt/core/getCostGrad.m: -------------------------------------------------------------------------------- 1 | function [cost, grad] = getCostGrad(problem, x, storedb, key) 2 | % Computes the cost function and the gradient at x in one call if possible. 3 | % 4 | % function [cost, grad] = getCostGrad(problem, x) 5 | % function [cost, grad] = getCostGrad(problem, x, storedb) 6 | % function [cost, grad] = getCostGrad(problem, x, storedb, key) 7 | % 8 | % Returns the value at x of the cost function described in the problem 9 | % structure, as well as the gradient at x. 10 | % 11 | % storedb is a StoreDB object, key is the StoreDB key to point x. 12 | % 13 | % See also: canGetCost canGetGradient getCost getGradient 14 | 15 | % This file is part of Manopt: www.manopt.org. 16 | % Original author: Nicolas Boumal, Dec. 30, 2012. 17 | % Contributors: 18 | % Change log: 19 | % 20 | % April 3, 2015 (NB): 21 | % Works with the new StoreDB class system. 22 | 23 | % Allow omission of the key, and even of storedb. 24 | if ~exist('key', 'var') 25 | if ~exist('storedb', 'var') 26 | storedb = StoreDB(); 27 | end 28 | key = storedb.getNewKey(); 29 | end 30 | 31 | 32 | if isfield(problem, 'costgrad') 33 | %% Compute the cost/grad pair using costgrad. 34 | 35 | % Check whether this function wants to deal with storedb or not. 36 | switch nargin(problem.costgrad) 37 | case 1 38 | [cost, grad] = problem.costgrad(x); 39 | case 2 40 | % Obtain, pass along, and save the store for x. 41 | store = storedb.getWithShared(key); 42 | [cost, grad, store] = problem.costgrad(x, store); 43 | storedb.setWithShared(store, key); 44 | case 3 45 | % Pass along the whole storedb (by reference), with key. 46 | [cost, grad] = problem.costgrad(x, storedb, key); 47 | otherwise 48 | up = MException('manopt:getCostGrad:badcostgrad', ... 49 | 'costgrad should accept 1, 2 or 3 inputs.'); 50 | throw(up); 51 | end 52 | 53 | else 54 | %% Revert to calling getCost and getGradient separately 55 | 56 | cost = getCost(problem, x, storedb, key); 57 | grad = getGradient(problem, x, storedb, key); 58 | 59 | end 60 | 61 | end 62 | -------------------------------------------------------------------------------- /manopt/manopt/core/getDirectionalDerivative.m: -------------------------------------------------------------------------------- 1 | function diff = getDirectionalDerivative(problem, x, d, storedb, key) 2 | % Computes the directional derivative of the cost function at x along d. 3 | % 4 | % function diff = getDirectionalDerivative(problem, x, d) 5 | % function diff = getDirectionalDerivative(problem, x, d, storedb) 6 | % function diff = getDirectionalDerivative(problem, x, d, storedb, key) 7 | % 8 | % Returns the derivative at x along d of the cost function described in the 9 | % problem structure. 10 | % 11 | % storedb is a StoreDB object, key is the StoreDB key to point x. 12 | % 13 | % See also: getGradient canGetDirectionalDerivative 14 | 15 | % This file is part of Manopt: www.manopt.org. 16 | % Original author: Nicolas Boumal, Dec. 30, 2012. 17 | % Contributors: 18 | % Change log: 19 | % 20 | % April 3, 2015 (NB): 21 | % Works with the new StoreDB class system. 22 | 23 | % Allow omission of the key, and even of storedb. 24 | if ~exist('key', 'var') 25 | if ~exist('storedb', 'var') 26 | storedb = StoreDB(); 27 | end 28 | key = storedb.getNewKey(); 29 | end 30 | 31 | 32 | if isfield(problem, 'diff') 33 | %% Compute the directional derivative using diff. 34 | 35 | % Check whether this function wants to deal with storedb or not. 36 | switch nargin(problem.diff) 37 | case 2 38 | diff = problem.diff(x, d); 39 | case 3 40 | % Obtain, pass along, and save the store for x. 41 | store = storedb.getWithShared(key); 42 | [diff, store] = problem.diff(x, d, store); 43 | storedb.setWithShared(store, key); 44 | case 4 45 | % Pass along the whole storedb (by reference), with key. 46 | diff = problem.diff(x, d, storedb, key); 47 | otherwise 48 | up = MException('manopt:getDirectionalDerivative:baddiff', ... 49 | 'diff should accept 2, 3 or 4 inputs.'); 50 | throw(up); 51 | end 52 | 53 | elseif canGetGradient(problem) 54 | %% Compute the directional derivative using the gradient. 55 | 56 | % Compute the gradient at x, then compute its inner product with d. 57 | grad = getGradient(problem, x, storedb, key); 58 | diff = problem.M.inner(x, grad, d); 59 | 60 | else 61 | %% Abandon computing the directional derivative. 62 | 63 | up = MException('manopt:getDirectionalDerivative:fail', ... 64 | ['The problem description is not explicit enough to ' ... 65 | 'compute the directional derivatives of f.']); 66 | throw(up); 67 | 68 | end 69 | 70 | end 71 | -------------------------------------------------------------------------------- /manopt/manopt/core/getEuclideanGradient.m: -------------------------------------------------------------------------------- 1 | function egrad = getEuclideanGradient(problem, x, storedb, key) 2 | % Computes the Euclidean gradient of the cost function at x. 3 | % 4 | % function egrad = getEuclideanGradient(problem, x) 5 | % function egrad = getEuclideanGradient(problem, x, storedb) 6 | % function egrad = getEuclideanGradient(problem, x, storedb, key) 7 | % 8 | % Returns the Euclidean gradient at x of the cost function described in the 9 | % problem structure. 10 | % 11 | % storedb is a StoreDB object, key is the StoreDB key to point x. 12 | % 13 | % Because computing the Hessian based on the Euclidean Hessian will require 14 | % the Euclidean gradient every time, to avoid overly redundant 15 | % computations, if the egrad function does not use the store caching 16 | % capabilites, this implements an automatic caching functionality. Writing 17 | % egrad to accept the optional store or storedb parameter will disable 18 | % automatic caching, but allow user controlled caching. 19 | % 20 | % See also: getGradient canGetGradient canGetEuclideanGradient 21 | 22 | % This file is part of Manopt: www.manopt.org. 23 | % Original author: Nicolas Boumal, July 9, 2013. 24 | % Contributors: 25 | % Change log: 26 | % 27 | % April 3, 2015 (NB): 28 | % Works with the new StoreDB class system. 29 | 30 | % Allow omission of the key, and even of storedb. 31 | if ~exist('key', 'var') 32 | if ~exist('storedb', 'var') 33 | storedb = StoreDB(); 34 | end 35 | key = storedb.getNewKey(); 36 | end 37 | 38 | 39 | if isfield(problem, 'egrad') 40 | %% Compute the Euclidean gradient using egrad. 41 | 42 | % Check whether this function wants to deal with storedb or not. 43 | switch nargin(problem.egrad) 44 | case 1 45 | % If it does not want to deal with the store structure, 46 | % then we do some caching of our own. There is a small 47 | % performance hit for this is some cases, but we expect 48 | % that this is most often the preferred choice. 49 | store = storedb.get(key); 50 | if ~isfield(store, 'egrad__') 51 | store.egrad__ = problem.egrad(x); 52 | storedb.set(store, key); 53 | end 54 | egrad = store.egrad__; 55 | case 2 56 | % Obtain, pass along, and save the store for x. 57 | % If the user deals with the store structure, then we don't 58 | % do any automatic caching: the user is in control. 59 | store = storedb.getWithShared(key); 60 | [egrad, store] = problem.egrad(x, store); 61 | storedb.setWithShared(store, key); 62 | case 3 63 | % Pass along the whole storedb (by reference), with key. 64 | % Same here: no automatic caching. 65 | egrad = problem.egrad(x, storedb, key); 66 | otherwise 67 | up = MException('manopt:getEuclideanGradient:badegrad', ... 68 | 'egrad should accept 1, 2 or 3 inputs.'); 69 | throw(up); 70 | end 71 | 72 | else 73 | %% Abandon computing the Euclidean gradient 74 | 75 | up = MException('manopt:getEuclideanGradient:fail', ... 76 | ['The problem description is not explicit enough to ' ... 77 | 'compute the Euclidean gradient of the cost.']); 78 | throw(up); 79 | 80 | end 81 | 82 | end 83 | -------------------------------------------------------------------------------- /manopt/manopt/core/getGlobalDefaults.m: -------------------------------------------------------------------------------- 1 | function opts = getGlobalDefaults() 2 | % Returns a structure with default option values for Manopt. 3 | % 4 | % function opts = getGlobalDefaults() 5 | % 6 | % Returns a structure opts containing the global default options such as 7 | % verbosity level etc. Typically, global defaults are overwritten by solver 8 | % defaults, which are in turn overwritten by user-specified options. 9 | % See the online Manopt documentation for details on options. 10 | % 11 | % See also: mergeOptions 12 | 13 | % This file is part of Manopt: www.manopt.org. 14 | % Original author: Nicolas Boumal, Dec. 30, 2012. 15 | % Contributors: 16 | % Change log: 17 | 18 | 19 | % There should be no reason to modify this file. 20 | % For better compatibility with future Manopt versions, 21 | % use the options structure of solvers. 22 | % 23 | % Really: don't modify it. 24 | 25 | 26 | % Verbosity level: 0 is no output at all. The higher the verbosity, the 27 | % more info is printed / displayed during solver execution. 28 | opts.verbosity = 3; 29 | 30 | % If debug is set to true, additional computations may be performed and 31 | % debugging information is outputed during solver execution. 32 | opts.debug = false; 33 | 34 | % Maximum number of store structures to store. If set to 0, caching 35 | % capabilities are not disabled, but the cache will be emptied at each 36 | % iteration of iterative solvers (more specifically: every time the 37 | % solver calls to purge the storedb). 38 | opts.storedepth = 20; 39 | 40 | % Maximum amount of time a solver may execute, in seconds. 41 | opts.maxtime = inf; 42 | 43 | end 44 | -------------------------------------------------------------------------------- /manopt/manopt/core/getGradient.m: -------------------------------------------------------------------------------- 1 | function grad = getGradient(problem, x, storedb, key) 2 | % Computes the gradient of the cost function at x. 3 | % 4 | % function grad = getGradient(problem, x) 5 | % function grad = getGradient(problem, x, storedb) 6 | % function grad = getGradient(problem, x, storedb, key) 7 | % 8 | % Returns the gradient at x of the cost function described in the problem 9 | % structure. 10 | % 11 | % storedb is a StoreDB object, key is the StoreDB key to point x. 12 | % 13 | % See also: getDirectionalDerivative canGetGradient 14 | 15 | % This file is part of Manopt: www.manopt.org. 16 | % Original author: Nicolas Boumal, Dec. 30, 2012. 17 | % Contributors: 18 | % Change log: 19 | % 20 | % April 3, 2015 (NB): 21 | % Works with the new StoreDB class system. 22 | 23 | % Allow omission of the key, and even of storedb. 24 | if ~exist('key', 'var') 25 | if ~exist('storedb', 'var') 26 | storedb = StoreDB(); 27 | end 28 | key = storedb.getNewKey(); 29 | end 30 | 31 | 32 | if isfield(problem, 'grad') 33 | %% Compute the gradient using grad. 34 | 35 | % Check whether this function wants to deal with storedb or not. 36 | switch nargin(problem.cost) 37 | case 1 38 | grad = problem.grad(x); 39 | case 2 40 | % Obtain, pass along, and save the store for x. 41 | store = storedb.getWithShared(key); 42 | [grad, store] = problem.grad(x, store); 43 | storedb.setWithShared(store, key); 44 | case 3 45 | % Pass along the whole storedb (by reference), with key. 46 | grad = problem.grad(x, storedb, key); 47 | otherwise 48 | up = MException('manopt:getGradient:badgrad', ... 49 | 'grad should accept 1, 2 or 3 inputs.'); 50 | throw(up); 51 | end 52 | 53 | elseif isfield(problem, 'costgrad') 54 | %% Compute the gradient using costgrad. 55 | 56 | % Check whether this function wants to deal with storedb or not. 57 | switch nargin(problem.costgrad) 58 | case 1 59 | [unused, grad] = problem.costgrad(x); %#ok 60 | case 2 61 | % Obtain, pass along, and save the store for x. 62 | store = storedb.getWithShared(key); 63 | [unused, grad, store] = problem.costgrad(x, store); %#ok 64 | storedb.setWithShared(store, key); 65 | case 3 66 | % Pass along the whole storedb (by reference), with key. 67 | [unused, grad] = problem.costgrad(x, storedb, key); %#ok 68 | otherwise 69 | up = MException('manopt:getGradient:badcostgrad', ... 70 | 'costgrad should accept 1, 2 or 3 inputs.'); 71 | throw(up); 72 | end 73 | 74 | elseif canGetEuclideanGradient(problem) 75 | %% Compute the gradient using the Euclidean gradient. 76 | 77 | egrad = getEuclideanGradient(problem, x, storedb, key); 78 | grad = problem.M.egrad2rgrad(x, egrad); 79 | 80 | else 81 | %% Abandon computing the gradient. 82 | 83 | up = MException('manopt:getGradient:fail', ... 84 | ['The problem description is not explicit enough to ' ... 85 | 'compute the gradient of the cost.']); 86 | throw(up); 87 | 88 | end 89 | 90 | end 91 | -------------------------------------------------------------------------------- /manopt/manopt/core/getHessian.m: -------------------------------------------------------------------------------- 1 | function hess = getHessian(problem, x, d, storedb, key) 2 | % Computes the Hessian of the cost function at x along d. 3 | % 4 | % function hess = getHessian(problem, x, d) 5 | % function hess = getHessian(problem, x, d, storedb) 6 | % function hess = getHessian(problem, x, d, storedb, key) 7 | % 8 | % Returns the Hessian at x along d of the cost function described in the 9 | % problem structure. 10 | % 11 | % storedb is a StoreDB object, key is the StoreDB key to point x. 12 | % 13 | % If an exact Hessian is not provided, an approximate Hessian is returned 14 | % if possible, without warning. If not possible, an exception will be 15 | % thrown. To check whether an exact Hessian is available or not (typically 16 | % to issue a warning if not), use canGetHessian. 17 | % 18 | % See also: getPrecon getApproxHessian canGetHessian 19 | 20 | % This file is part of Manopt: www.manopt.org. 21 | % Original author: Nicolas Boumal, Dec. 30, 2012. 22 | % Contributors: 23 | % Change log: 24 | % 25 | % April 3, 2015 (NB): 26 | % Works with the new StoreDB class system. 27 | 28 | % Allow omission of the key, and even of storedb. 29 | if ~exist('key', 'var') 30 | if ~exist('storedb', 'var') 31 | storedb = StoreDB(); 32 | end 33 | key = storedb.getNewKey(); 34 | end 35 | 36 | 37 | if isfield(problem, 'hess') 38 | %% Compute the Hessian using hess. 39 | 40 | % Check whether this function wants to deal with storedb or not. 41 | switch nargin(problem.hess) 42 | case 2 43 | hess = problem.hess(x, d); 44 | case 3 45 | % Obtain, pass along, and save the store for x. 46 | store = storedb.getWithShared(key); 47 | [hess, store] = problem.hess(x, d, store); 48 | storedb.setWithShared(store, key); 49 | case 4 50 | % Pass along the whole storedb (by reference), with key. 51 | hess = problem.hess(x, d, storedb, key); 52 | otherwise 53 | up = MException('manopt:getHessian:badhess', ... 54 | 'hess should accept 2, 3 or 4 inputs.'); 55 | throw(up); 56 | end 57 | 58 | elseif isfield(problem, 'ehess') && canGetEuclideanGradient(problem) 59 | %% Compute the Hessian using ehess. 60 | 61 | % We will need the Euclidean gradient for the conversion from the 62 | % Euclidean Hessian to the Riemannian Hessian. 63 | egrad = getEuclideanGradient(problem, x, storedb, key); 64 | 65 | % Check whether this function wants to deal with storedb or not. 66 | switch nargin(problem.ehess) 67 | case 2 68 | ehess = problem.ehess(x, d); 69 | case 3 70 | % Obtain, pass along, and save the store for x. 71 | store = storedb.getWithShared(key); 72 | [ehess, store] = problem.ehess(x, d, store); 73 | storedb.setWithShared(store, key); 74 | case 4 75 | % Pass along the whole storedb (by reference), with key. 76 | ehess = problem.ehess(x, d, storedb, key); 77 | otherwise 78 | up = MException('manopt:getHessian:badehess', ... 79 | 'ehess should accept 2, 3 or 4 inputs.'); 80 | throw(up); 81 | end 82 | 83 | % Convert to the Riemannian Hessian 84 | hess = problem.M.ehess2rhess(x, egrad, ehess, d); 85 | 86 | else 87 | %% Attempt the computation of an approximation of the Hessian. 88 | 89 | hess = getApproxHessian(problem, x, d, storedb, key); 90 | 91 | end 92 | 93 | end 94 | -------------------------------------------------------------------------------- /manopt/manopt/core/getHessianFD.m: -------------------------------------------------------------------------------- 1 | function hessfd = getHessianFD(problem, x, d, storedb, key) 2 | % Computes an approx. of the Hessian w/ finite differences of the gradient. 3 | % 4 | % function hessfd = getHessianFD(problem, x, d) 5 | % function hessfd = getHessianFD(problem, x, d, storedb) 6 | % function hessfd = getHessianFD(problem, x, d, storedb, key) 7 | % 8 | % Returns a finite difference approximation of the Hessian at x along d of 9 | % the cost function described in the problem structure. The finite 10 | % difference is based on computations of the gradient. 11 | % 12 | % storedb is a StoreDB object, key is the StoreDB key to point x. 13 | % 14 | % If the gradient cannot be computed, an exception is thrown. 15 | % 16 | % See also: approxhessianFD 17 | 18 | % This file is part of Manopt: www.manopt.org. 19 | % Original author: Nicolas Boumal, Dec. 30, 2012. 20 | % Contributors: 21 | % Change log: 22 | % 23 | % Feb. 19, 2015 (NB): 24 | % It is sufficient to ensure positive radial linearity to guarantee 25 | % (together with other assumptions) that this approximation of the 26 | % Hessian will confer global convergence to the trust-regions method. 27 | % Formerly, in-code comments referred to the necessity of having 28 | % complete radial linearity, and that this was harder to achieve. 29 | % This appears not to be necessary after all, which simplifies the 30 | % code. 31 | % 32 | % April 3, 2015 (NB): 33 | % Works with the new StoreDB class system. 34 | 35 | % Allow omission of the key, and even of storedb. 36 | if ~exist('key', 'var') 37 | if ~exist('storedb', 'var') 38 | storedb = StoreDB(); 39 | end 40 | key = storedb.getNewKey(); 41 | end 42 | 43 | 44 | if ~canGetGradient(problem) 45 | up = MException('manopt:getHessianFD:nogradient', ... 46 | 'getHessianFD requires the gradient to be computable.'); 47 | throw(up); 48 | end 49 | 50 | % Step size 51 | norm_d = problem.M.norm(x, d); 52 | 53 | % First, check whether the step d is not too small 54 | if norm_d < eps 55 | hessfd = problem.M.zerovec(x); 56 | return; 57 | end 58 | 59 | % Parameter: how far do we look? 60 | % (Use approxhessianFD explicitly to gain access to this parameter.) 61 | epsilon = 1e-4; 62 | 63 | c = epsilon/norm_d; 64 | 65 | % Compute the gradient at the current point. 66 | grad = getGradient(problem, x, storedb, key); 67 | 68 | % Compute a point a little further along d and the gradient there. 69 | % Since this is a new point, we need a new key for it, for the storedb. 70 | x1 = problem.M.retr(x, d, c); 71 | key1 = storedb.getNewKey(); 72 | grad1 = getGradient(problem, x1, storedb, key1); 73 | 74 | % Transport grad1 back from x1 to x. 75 | grad1 = problem.M.transp(x1, x, grad1); 76 | 77 | % Return the finite difference of them. 78 | hessfd = problem.M.lincomb(x, 1/c, grad1, -1/c, grad); 79 | 80 | end 81 | -------------------------------------------------------------------------------- /manopt/manopt/core/getLinesearch.m: -------------------------------------------------------------------------------- 1 | function t = getLinesearch(problem, x, d, storedb, key) 2 | % Returns a hint for line-search algorithms. 3 | % 4 | % function t = getLinesearch(problem, x, d) 5 | % function t = getLinesearch(problem, x, d, storedb) 6 | % function t = getLinesearch(problem, x, d, storedb, key) 7 | % 8 | % For a line-search problem at x along the tangent direction d, computes 9 | % and returns t such that retracting t*d at x yields a good point around 10 | % where to look for a line-search solution. That is: t is a hint as to 11 | % "how far to look" along the line. 12 | % 13 | % storedb is a StoreDB object, key is the StoreDB key to point x. 14 | % 15 | % See also: canGetLinesearch 16 | 17 | % This file is part of Manopt: www.manopt.org. 18 | % Original author: Nicolas Boumal, July 17, 2014. 19 | % Contributors: 20 | % Change log: 21 | % 22 | % April 3, 2015 (NB): 23 | % Works with the new StoreDB class system. 24 | 25 | % Allow omission of the key, and even of storedb. 26 | if ~exist('key', 'var') 27 | if ~exist('storedb', 'var') 28 | storedb = StoreDB(); 29 | end 30 | key = storedb.getNewKey(); 31 | end 32 | 33 | 34 | if isfield(problem, 'linesearch') 35 | %% Compute the line-search hint function using linesearch. 36 | 37 | % Check whether this function wants to deal with storedb or not. 38 | switch nargin(problem.linesearch) 39 | case 2 40 | t = problem.linesearch(x, d); 41 | case 3 42 | % Obtain, pass along, and save the store for x. 43 | store = storedb.getWithShared(key); 44 | [t, store] = problem.linesearch(x, d, store); 45 | storedb.setWithShared(store, key); 46 | case 4 47 | % Pass along the whole storedb (by reference), with key. 48 | t = problem.linesearch(x, d, storedb, key); 49 | otherwise 50 | up = MException('manopt:getLinesearch:badfun', ... 51 | 'linesearch should accept 2, 3 or 4 inputs.'); 52 | throw(up); 53 | end 54 | 55 | else 56 | %% Abandon computing the line-search function. 57 | 58 | up = MException('manopt:getLinesearch:fail', ... 59 | ['The problem description is not explicit enough to ' ... 60 | 'compute a line-search hint.']); 61 | throw(up); 62 | 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /manopt/manopt/core/getPrecon.m: -------------------------------------------------------------------------------- 1 | function Pd = getPrecon(problem, x, d, storedb, key) 2 | % Applies the preconditioner for the Hessian of the cost at x along d. 3 | % 4 | % function Pd = getPrecon(problem, x, d) 5 | % function Pd = getPrecon(problem, x, d, storedb) 6 | % function Pd = getPrecon(problem, x, d, storedb, key) 7 | % 8 | % Returns as Pd the result of applying the Hessian preconditioner to the 9 | % tangent vector d at point x. The preconditioner is supposed to be a 10 | % symmetric, positive definite approximation of the inverse of the Hessian. 11 | % 12 | % If no preconditioner is available, Pd = d (identity). 13 | % 14 | % storedb is a StoreDB object, key is the StoreDB key to point x. 15 | % 16 | % See also: getHessian 17 | 18 | % This file is part of Manopt: www.manopt.org. 19 | % Original author: Nicolas Boumal, Dec. 30, 2012. 20 | % Contributors: 21 | % Change log: 22 | % 23 | % April 3, 2015 (NB): 24 | % Works with the new StoreDB class system. 25 | 26 | % Allow omission of the key, and even of storedb. 27 | if ~exist('key', 'var') 28 | if ~exist('storedb', 'var') 29 | storedb = StoreDB(); 30 | end 31 | key = storedb.getNewKey(); 32 | end 33 | 34 | 35 | if isfield(problem, 'precon') 36 | %% Precondition using precon. 37 | 38 | % Check whether this function wants to deal with storedb or not. 39 | switch nargin(problem.precon) 40 | case 2 41 | Pd = problem.precon(x, d); 42 | case 3 43 | % Obtain, pass along, and save the store for x. 44 | store = storedb.getWithShared(key); 45 | [Pd, store] = problem.precon(x, d, store); 46 | storedb.setWithShared(store, key); 47 | case 4 48 | % Pass along the whole storedb (by reference), with key. 49 | Pd = problem.precon(x, d, storedb, key); 50 | otherwise 51 | up = MException('manopt:getPrecon:badprecon', ... 52 | 'precon should accept 2, 3 or 4 inputs.'); 53 | throw(up); 54 | end 55 | 56 | elseif canGetSqrtPrecon(problem) 57 | %% Precondition by applying the square root of the preconditioner twice. 58 | 59 | sqrtPd = getSqrtPrecon(problem, x, d, storedb, key); 60 | Pd = getSqrtPrecon(problem, x, sqrtPd, storedb, key); 61 | 62 | else 63 | %% No preconditioner provided, so just use the identity. 64 | 65 | Pd = d; 66 | 67 | end 68 | 69 | end 70 | -------------------------------------------------------------------------------- /manopt/manopt/core/getSqrtPrecon.m: -------------------------------------------------------------------------------- 1 | function sqrtPd = getSqrtPrecon(problem, x, d, storedb, key) 2 | % Applies the square root of the Hessian preconditioner at x along d. 3 | % 4 | % function sqrtPd = getSqrtPrecon(problem, x, d) 5 | % function sqrtPd = getSqrtPrecon(problem, x, d, storedb) 6 | % function sqrtPd = getSqrtPrecon(problem, x, d, storedb, key) 7 | % 8 | % Returns as sqrtPd the result of applying the square root of the Hessian 9 | % preconditioner to the tangent vector d at point x. The preconditioner is 10 | % supposed to be a symmetric, positive definite approximation of the 11 | % inverse of the Hessian. Its square root must thus be symmetric and 12 | % positive definite itself. 13 | % 14 | % If no square root of preconditioner is available, sqrtPd = d (identity). 15 | % Note that this may be incompatible with the preconditioner, if that one 16 | % is supplied in the problem description. Always check with canGetPrecon 17 | % and canGetSqrtPrecon. 18 | % 19 | % storedb is a StoreDB object, key is the StoreDB key to point x. 20 | % 21 | % See also: getPrecon canGetPrecon canGetSqrtPrecon getHessian 22 | 23 | % This file is part of Manopt: www.manopt.org. 24 | % Original author: Nicolas Boumal, April 3, 2015. 25 | % Contributors: 26 | % Change log: 27 | 28 | % Allow omission of the key, and even of storedb. 29 | if ~exist('key', 'var') 30 | if ~exist('storedb', 'var') 31 | storedb = StoreDB(); 32 | end 33 | key = storedb.getNewKey(); 34 | end 35 | 36 | 37 | if isfield(problem, 'sqrtprecon') 38 | %% Apply sqrtprecon for the square root of the preconditioner 39 | 40 | % Check whether this function wants to deal with storedb or not. 41 | switch nargin(problem.sqrtprecon) 42 | case 2 43 | sqrtPd = problem.sqrtprecon(x, d); 44 | case 3 45 | % Obtain, pass along, and save the store for x. 46 | store = storedb.getWithShared(key); 47 | [sqrtPd, store] = problem.sqrtprecon(x, d, store); 48 | storedb.setWithShared(store, key); 49 | case 4 50 | % Pass along the whole storedb (by reference), with key. 51 | sqrtPd = problem.sqrtprecon(x, d, storedb, key); 52 | otherwise 53 | up = MException('manopt:getSqrtPrecon:badsqrtprecon', ... 54 | 'sqrtprecon should accept 2, 3 or 4 inputs.'); 55 | throw(up); 56 | end 57 | 58 | else 59 | %% No preconditioner square root provided, so just use the identity. 60 | 61 | sqrtPd = d; 62 | 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /manopt/manopt/core/getStore.m: -------------------------------------------------------------------------------- 1 | function store = getStore(problem, x, storedb) %#ok 2 | 3 | error('This file was removed from Manopt. Please use the StoreDB class.'); 4 | 5 | end 6 | -------------------------------------------------------------------------------- /manopt/manopt/core/handle_light.m: -------------------------------------------------------------------------------- 1 | classdef handle_light < handle 2 | % Trick class to hide methods inherited from the handle class 3 | % when calling methods(myclass). 4 | % 5 | % Source: 6 | % http://stackoverflow.com/questions/6621850/is-it-possible-to-hide-the-methods-inherited-from-the-handle-class-in-matlab 7 | % Posted by sclarke81 on StackOverflow on Oct. 24, 2012. 8 | 9 | % This file is part of Manopt: www.manopt.org. 10 | % Original author: sclarke81, added April 3, 2013. 11 | % Contributors: 12 | % Change log: 13 | 14 | methods(Hidden) 15 | function lh = addlistener(varargin) 16 | lh = addlistener@handle(varargin{:}); 17 | end 18 | function notify(varargin) 19 | notify@handle(varargin{:}); 20 | end 21 | function delete(varargin) 22 | delete@handle(varargin{:}); 23 | end 24 | function Hmatch = findobj(varargin) 25 | Hmatch = findobj@handle(varargin{:}); 26 | end 27 | function p = findprop(varargin) 28 | p = findprop@handle(varargin{:}); 29 | end 30 | function TF = eq(varargin) 31 | TF = eq@handle(varargin{:}); 32 | end 33 | function TF = ne(varargin) 34 | TF = ne@handle(varargin{:}); 35 | end 36 | function TF = lt(varargin) 37 | TF = lt@handle(varargin{:}); 38 | end 39 | function TF = le(varargin) 40 | TF = le@handle(varargin{:}); 41 | end 42 | function TF = gt(varargin) 43 | TF = gt@handle(varargin{:}); 44 | end 45 | function TF = ge(varargin) 46 | TF = ge@handle(varargin{:}); 47 | end 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /manopt/manopt/core/mergeOptions.m: -------------------------------------------------------------------------------- 1 | function opts = mergeOptions(opts1, opts2) 2 | % Merges two options structures with one having precedence over the other. 3 | % 4 | % function opts = mergeOptions(opts1, opts2) 5 | % 6 | % input: opts1 and opts2 are two structures. 7 | % output: opts is a structure containing all fields of opts1 and opts2. 8 | % Whenever a field is present in both opts1 and opts2, it is the value in 9 | % opts2 that is kept. 10 | % 11 | % The typical usage is to have opts1 contain default options and opts2 12 | % contain user-specified options that overwrite the defaults. 13 | % 14 | % See also: getGlobalDefaults 15 | 16 | % This file is part of Manopt: www.manopt.org. 17 | % Original author: Nicolas Boumal, Dec. 30, 2012. 18 | % Contributors: 19 | % Change log: 20 | 21 | 22 | if isempty(opts1) 23 | opts1 = struct(); 24 | end 25 | if isempty(opts2) 26 | opts2 = struct(); 27 | end 28 | 29 | opts = opts1; 30 | fields = fieldnames(opts2); 31 | for i = 1 : length(fields) 32 | opts.(fields{i}) = opts2.(fields{i}); 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /manopt/manopt/core/purgeStoredb.m: -------------------------------------------------------------------------------- 1 | function storedb = purgeStoredb(storedb, storedepth) %#ok 2 | 3 | error('This file was removed from Manopt. Please use the StoreDB class.'); 4 | 5 | end 6 | -------------------------------------------------------------------------------- /manopt/manopt/core/setStore.m: -------------------------------------------------------------------------------- 1 | function storedb = setStore(problem, x, storedb, store) %#ok 2 | 3 | error('This file was removed from Manopt. Please use the StoreDB class.'); 4 | 5 | end 6 | -------------------------------------------------------------------------------- /manopt/manopt/core/stoppingcriterion.m: -------------------------------------------------------------------------------- 1 | function [stop, reason] = stoppingcriterion(problem, x, options, info, last) 2 | % Checks for standard stopping criteria, as a helper to solvers. 3 | % 4 | % function [stop, reason] = stoppingcriterion(problem, x, options, info, last) 5 | % 6 | % Executes standard stopping criterion checks, based on what is defined in 7 | % the info(last) stats structure and in the options structure. 8 | % 9 | % The returned number 'stop' is 0 if none of the stopping criteria 10 | % triggered, and a (strictly) positive integer otherwise. The integer 11 | % identifies which criterion triggered: 12 | % 0 : Nothing triggered; 13 | % 1 : Cost tolerance reached; 14 | % 2 : Gradient norm tolerance reached; 15 | % 3 : Max time exceeded; 16 | % 4 : Max iteration count reached; 17 | % 5 : Maximum number of cost evaluations reached; 18 | % 6 : User defined stopfun criterion triggered. 19 | % 20 | % The output 'reason' is a string describing the triggered event. 21 | 22 | % This file is part of Manopt: www.manopt.org. 23 | % Original author: Nicolas Boumal, Dec. 30, 2012. 24 | % Contributors: 25 | % Change log: 26 | % 27 | % April 2, 2015 (NB): 28 | % 'reason' now contains the option (name and value) that triggered. 29 | 30 | 31 | stop = 0; 32 | reason = ''; 33 | 34 | stats = info(last); 35 | 36 | % Target cost attained 37 | if isfield(stats, 'cost') && isfield(options, 'tolcost') && ... 38 | stats.cost <= options.tolcost 39 | reason = sprintf('Cost tolerance reached; options.tolcost = %g.', options.tolcost); 40 | stop = 1; 41 | return; 42 | end 43 | 44 | % Target gradient norm attained 45 | if isfield(stats, 'gradnorm') && isfield(options, 'tolgradnorm') && ... 46 | stats.gradnorm < options.tolgradnorm 47 | reason = sprintf('Gradient norm tolerance reached; options.tolgradnorm = %g.', options.tolgradnorm); 48 | stop = 2; 49 | return; 50 | end 51 | 52 | % Allotted time exceeded 53 | if isfield(stats, 'time') && isfield(options, 'maxtime') && ... 54 | stats.time >= options.maxtime 55 | reason = sprintf('Max time exceeded; options.maxtime = %g.', options.maxtime); 56 | stop = 3; 57 | return; 58 | end 59 | 60 | % Allotted iteration count exceeded 61 | if isfield(stats, 'iter') && isfield(options, 'maxiter') && ... 62 | stats.iter >= options.maxiter 63 | reason = sprintf('Max iteration count reached; options.maxiter = %g.', options.maxiter); 64 | stop = 4; 65 | return; 66 | end 67 | 68 | % Allotted function evaluation count exceeded 69 | if isfield(stats, 'costevals') && isfield(options, 'maxcostevals') && ... 70 | stats.costevals >= options.maxcostevals 71 | reason = sprintf('Maximum number of cost evaluations reached; options.maxcostevals = %g.', options.maxcostevals); 72 | stop = 5; 73 | end 74 | 75 | % Check whether the possibly user defined stopping criterion 76 | % triggers or not. 77 | if isfield(options, 'stopfun') 78 | userstop = options.stopfun(problem, x, info, last); 79 | if userstop 80 | reason = 'User defined stopfun criterion triggered; see options.stopfun.'; 81 | stop = 6; 82 | return; 83 | end 84 | end 85 | 86 | end 87 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/essential_costE2cost.m: -------------------------------------------------------------------------------- 1 | function val = essential_costE2cost(X, costE) 2 | % Cost evaluation at X given function handle in the Essential matrix E. 3 | % 4 | % function val = essential_costE2cost(X, costE) 5 | % 6 | % costE is the function handle for the cost function in E. 7 | % 8 | % See also: essential_egradE2egrad essential_ehessE2ehess 9 | 10 | % This file is part of Manopt: www.manopt.org. 11 | % Original author: Roberto Tron, Aug. 8, 2014 12 | % Contributors: Bamdev Mishra, May 22, 2015. 13 | 14 | e3hat = [0 -1 0; 1 0 0; 0 0 0]; 15 | 16 | RA = X(:,1:3,:); 17 | RB = X(:,4:6,:); 18 | E = multiprod(multiprod(multitransp(RA), e3hat), RB); 19 | 20 | val = costE(E); 21 | end 22 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/essential_egradE2egrad.m: -------------------------------------------------------------------------------- 1 | function egrad = essential_egradE2egrad(X, egradE) 2 | % Converts the gradient in essential matrix E to the gradient in X. 3 | % 4 | % function egrad = essential_egradE2egrad(X, egradE) 5 | % 6 | % egradE is the function handle for the gradient in E. 7 | % 8 | % The output is a matrix in the space of X. 9 | % 10 | % See also: essential_costE2cost essential_ehessE2ehess 11 | 12 | 13 | % This file is part of Manopt: www.manopt.org. 14 | % Original author: Roberto Tron, Aug. 8, 2014 15 | % Contributors: Bamdev Mishra, May 22, 2015. 16 | 17 | e3hat = [0 -1 0; 1 0 0; 0 0 0]; 18 | RA = X(:,1:3,:); 19 | RB = X(:,4:6,:); 20 | E = multiprod(multiprod(multitransp(RA), e3hat), RB); 21 | G = egradE(E); 22 | 23 | %The following is the vectorized version of egrad = e3hat*[RB*G' -RA*G]; 24 | egrad = multiprod(e3hat, cat(2,... 25 | multiprod(RB, multitransp(G)),... 26 | -multiprod(RA, G))); 27 | end 28 | 29 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/essential_ehessE2ehess.m: -------------------------------------------------------------------------------- 1 | function ehess = essential_ehessE2ehess(X, egradE, ehessE, S) 2 | % Converts the Hessian in essential matrix E to the Hessian in X. 3 | % 4 | % function ehess = essential_ehessE2ehess(X, egradE, ehessE, S) 5 | % 6 | % egradE is the function handle for the gradient in E. 7 | % ehessE is the function handle for the Hessian in E. 8 | % S is the search direction in the space of X. 9 | % 10 | % The output is a matrix in the space of X. 11 | % 12 | % See also: essential_costE2cost essential_egradE2egrad 13 | 14 | 15 | % This file is part of Manopt: www.manopt.org. 16 | % Original author: Roberto Tron, Aug. 8, 2014 17 | % Contributors: Bamdev Mishra, May 22, 2015. 18 | 19 | e3hat = [0 -1 0; 1 0 0; 0 0 0]; 20 | 21 | RA = X(:,1:3,:); 22 | RB = X(:,4:6,:); 23 | E = multiprod(multiprod(multitransp(RA), e3hat), RB); % M.E(X); 24 | G = egradE(E); 25 | 26 | V = essential_sharp(multiprod(essential_flat(X), essential_flat(S))); 27 | VA = V(:,1:3,:); 28 | VB = V(:,4:6,:); 29 | 30 | dE = multiprod(multiprod(multitransp(RA), e3hat), VB)... 31 | + multiprod(multiprod(multitransp(VA), e3hat), RB); 32 | dG = ehessE(E, dE); 33 | 34 | %The following is the vectorized version of ehess = e3hat*[(VB*G'+RB*H') -(VA*G+RA*H)] 35 | ehess = multiprod(e3hat,cat(2,... 36 | multiprod(VB, multitransp(G)) + multiprod(RB, multitransp(dG)),... 37 | -multiprod(VA, G) - multiprod(RA, dG))); 38 | 39 | end -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/essential_flat.m: -------------------------------------------------------------------------------- 1 | function Hp = essential_flat(H) 2 | %Reshape a [3x6xk] matrix to a [3x3x2k] matrix 3 | Hp = reshape(H,3,3,[]); 4 | end 5 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/essential_hat3.m: -------------------------------------------------------------------------------- 1 | %Compute the matrix representation of the cross product 2 | %function [V,vShift] = essential_hat3(v) 3 | %V is a [3x3xN] array of skew-symmetric matrices where each [3x3] block is 4 | %the matrix representation of the cross product of one of the columns of v 5 | %vShift is equal to permute(v,[1 3 2]). 6 | function [V, vShift] = essential_hat3(v) 7 | N = size(v,2); 8 | V = zeros(3,3,N); 9 | vShift = permute(v,[1 3 2]); 10 | V(1,2,:) = -vShift(3,:,:); 11 | V(2,1,:) = vShift(3,:,:); 12 | V(1,3,:) = vShift(2,:,:); 13 | V(3,1,:) = -vShift(2,:,:); 14 | V(2,3,:) = -vShift(1,:,:); 15 | V(3,2,:) = vShift(1,:,:); 16 | end -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/essential_sharp.m: -------------------------------------------------------------------------------- 1 | function H = essential_sharp(Hp) 2 | %Reshape a [3x3x2k] matrix to a [3x6xk] matrix 3 | H = reshape(Hp,3,6,[]); 4 | end 5 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/privateessential/essential_closestRepresentative.m: -------------------------------------------------------------------------------- 1 | function Q2r=essential_closestRepresentative(Q1,Q2,varargin) 2 | [tMin,~,Q2]=essential_distMinAngle(Q1,Q2,varargin{:}); 3 | NQ1=size(Q1,3); 4 | NQ2=size(Q2,3); 5 | 6 | if NQ1>1 && NQ2==1 7 | Q2=repmat(Q2,[1 1 NQ1]); 8 | end 9 | NQ=max(NQ1,NQ2); 10 | 11 | Q2r=zeros(size(Q2)); 12 | for iQ=1:NQ 13 | t=tMin(iQ); 14 | Rz=[cos(t) -sin(t) 0; sin(t) cos(t) 0; 0 0 1]; 15 | Q2r(1:3,1:3,iQ)=Rz*Q2(1:3,1:3,iQ); 16 | Q2r(4:6,1:3,iQ)=Rz*Q2(4:6,1:3,iQ); 17 | end 18 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/privateessential/essential_distMinAngle.m: -------------------------------------------------------------------------------- 1 | function [tMin,fMin,Q2Flip,output]=essential_distMinAngle(Q1,Q2,varargin) 2 | NQ1=size(Q1,3); 3 | NQ2=size(Q2,3); 4 | 5 | if NQ1==1 && NQ2>1 6 | Q1=repmat(Q1,[1 1 NQ2]); 7 | NQ1=NQ2; 8 | end 9 | if NQ1>1 && NQ2==1 10 | Q2=repmat(Q2,[1 1 NQ1]); 11 | end 12 | 13 | if NQ1>1 14 | tMin=zeros(NQ1,1); 15 | fMin=zeros(NQ1,1); 16 | Q2Flip=zeros(6,3,NQ1); 17 | if nargout>3 18 | output=repmat(struct('tMin',[],'fMin',[],'tBreak1',[],'tBreak2',[]),NQ1,1); 19 | end 20 | for iQ=1:NQ1 21 | if nargout>3 22 | [tMin(iQ),fMin(iQ),Q2Flip(:,:,iQ),output(iQ)]=... 23 | essential_distMinAngle(Q1(:,:,iQ),Q2(:,:,iQ),varargin{:}); 24 | else 25 | [tMin(iQ),fMin(iQ),Q2Flip(:,:,iQ)]=... 26 | essential_distMinAngle(Q1(:,:,iQ),Q2(:,:,iQ),varargin{:}); 27 | end 28 | end 29 | else 30 | flagModTMin=false; 31 | flagSigned=false; 32 | 33 | %optional parameters 34 | ivarargin=1; 35 | while(ivarargin<=length(varargin)) 36 | switch(lower(varargin{ivarargin})) 37 | case 'flagmodtmin' 38 | ivarargin=ivarargin+1; 39 | flagModTMin=varargin{ivarargin}; 40 | case 'signed' 41 | flagSigned=true; 42 | case 'flagsigned' 43 | ivarargin=ivarargin+1; 44 | flagSigned=varargin{ivarargin}; 45 | otherwise 46 | error(['Argument ' varargin{ivarargin} ' not valid!']) 47 | end 48 | ivarargin=ivarargin+1; 49 | end 50 | 51 | tMin=zeros(4,1); 52 | fMin=zeros(4,1); 53 | tBreak1=zeros(4,1); 54 | tBreak2=zeros(4,1); 55 | Q2Flip=zeros(6,3,4); 56 | if ~flagSigned 57 | for k=1:4 58 | [tMin(k),fMin(k),tBreak1(k),tBreak2(k),Q2Flip(:,:,k)]=... 59 | essential_distMinAnglePair(Q1,Q2,k); 60 | end 61 | else 62 | [tMin,fMin,tBreak1,tBreak2,Q2Flip]=... 63 | essential_distMinAnglePair(Q1,Q2,1); 64 | end 65 | 66 | if flagModTMin 67 | tMin=modAngle(tMin); 68 | end 69 | 70 | if nargout>3 71 | output.tMin=tMin; 72 | output.fMin=fMin; 73 | output.tBreak1=tBreak1; 74 | output.tBreak2=tBreak2; 75 | end 76 | 77 | if ~flagSigned 78 | [fMin,idxMin]=min(fMin); 79 | fMin=max(fMin,0); 80 | tMin=tMin(idxMin); 81 | Q2Flip=Q2Flip(:,:,idxMin); 82 | if nargout>3 83 | output.idxMin=idxMin; 84 | end 85 | end 86 | end -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/privateessential/essential_distMinAnglePair.m: -------------------------------------------------------------------------------- 1 | function [tMin,fMin,tBreak1,tBreak2,Q2,tMinAll]=essential_distMinAnglePair(Q1,Q2,kFlip) 2 | 3 | switch kFlip 4 | case 1 5 | %nothing to do 6 | case 2 7 | Q2([2 3 4 6],:)=-Q2([2 3 4 6],:); 8 | case 3 9 | Q2([4 5],:)=-Q2([4 5],:); 10 | case 4 11 | Q2([2 3 5 6],:)=-Q2([2 3 5 6],:); 12 | otherwise 13 | error('Value of kFlip invalid') 14 | end 15 | 16 | Q11=Q1(1:3,:); 17 | Q12=Q1(4:6,:); 18 | Q21=Q2(1:3,:); 19 | Q22=Q2(4:6,:); 20 | 21 | Q211=Q21*Q11'; 22 | Q212=Q22*Q12'; 23 | [tMin,fMin,tBreak1,tBreak2,tMinAll]=essential_distMinAnglePair_base(Q211,Q212); 24 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/privateessential/essential_distMinAnglePair_computeDfBreak.m: -------------------------------------------------------------------------------- 1 | function dfBreak=essential_distMinAnglePair_computeDfBreak(tBreak,Q21) 2 | c=cos(tBreak); 3 | s=sin(tBreak); 4 | 5 | % The code below is an optimization exploiting the structure of RBreak to 6 | % substitute the following code 7 | % RBreak=Q1'*[c -s 0; s c 0; 0 0 1]*Q2; 8 | % 9 | % %compute v0 such that RBreak=rot(pi*v0) 10 | % [U,~,~]=svd(RBreak+eye(3)); 11 | % v0=U(:,1); 12 | % 13 | % dfBreak=pi*abs(Q1(3,:)*v0); 14 | 15 | Q1RBreakQ1=[c -s 0; s c 0; 0 0 1]*Q21; 16 | [U,~,~]=svd(Q1RBreakQ1+eye(3)); 17 | dfBreak=pi*abs(U(3,1)); 18 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/essential/privateessential/essential_distMinAnglePair_dfNewton.m: -------------------------------------------------------------------------------- 1 | %Support function for essential_distMinAnglePair implementing Newton's search 2 | function [tMin,fMin]=essential_distMinAnglePair_dfNewton(m1,p1,c1,m2,p2,c2,tMin,tLow,tHigh) 3 | tolDist=1e-8; 4 | for i=1:100 5 | % d=dfi(m1,p1,c1,tMin)+dfi(m2,p2,c2,tMin); 6 | % dd=ddfi(m1,p1,c1,tMin)+ddfi(m2,p2,c2,tMin); 7 | %The code below unrolls the following calls 8 | % f1=fi(m1,p1,c1,tMin); 9 | % f2=fi(m2,p2,c2,tMin); 10 | % d=dfi2(m1,p1,f1,tMin)+dfi2(m2,p2,f2,tMin); 11 | % dd=ddfi2(m1,p1,f1,tMin)+ddfi2(m2,p2,f2,tMin); 12 | mc1=m1*cos(tMin+p1); 13 | mc2=m2*cos(tMin+p2); 14 | f1=acos(clip((m1*sin(tMin+p1)+c1-1)/2)); 15 | f2=acos(clip((m2*sin(tMin+p2)+c2-1)/2)); 16 | sf1=2*sin(f1); 17 | sf2=2*sin(f2); 18 | d1=-f1*mc1/sf1; 19 | d2=-f2*mc2/sf2; 20 | d=d1+d2; 21 | eztuSq1=(mc1/sf1)^2; 22 | dd1=eztuSq1+f1/2*cot(f1/2)*(1-eztuSq1); 23 | eztuSq2=(mc2/sf2)^2; 24 | dd2=eztuSq2+f2/2*cot(f2/2)*(1-eztuSq2); 25 | dd=dd1+dd2; 26 | 27 | 28 | tOld=tMin; 29 | tMin=max(tLow+tolDist,min(tHigh-tolDist,tOld-d/dd)); 30 | if abs(tMin-tOld) 66 | u = randn(m, n) + 1i*randn(m, n); 67 | u = u / norm(u, 'fro'); 68 | end 69 | 70 | M.lincomb = @matrixlincomb; 71 | 72 | M.zerovec = @(x) zeros(m, n); 73 | 74 | M.transp = @(x1, x2, d) d; 75 | 76 | M.pairmean = @(x1, x2) .5*(x1+x2); 77 | 78 | mn = m*n; 79 | M.vec = @(x, u_mat) [real(u_mat(:)) ; imag(u_mat(:))]; 80 | M.mat = @(x, u_vec) reshape(u_vec(1:mn), [m, n]) + 1i*reshape(u_vec((mn+1):end), [m, n]); 81 | M.vecmatareisometries = @() true; 82 | 83 | end 84 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/euclidean/euclideanfactory.m: -------------------------------------------------------------------------------- 1 | function M = euclideanfactory(m, n) 2 | % Returns a manifold struct to optimize over m-by-n matrices. 3 | % 4 | % function M = euclideanfactory(m, n) 5 | % 6 | % Returns M, a structure describing the Euclidean space of m-by-n matrices, 7 | % equipped with the standard Frobenius distance and associated trace inner 8 | % product, as a manifold for Manopt. 9 | % 10 | % m and n in general can be vectors to handle multidimensional arrays. 11 | % If either of m or n is a vector, they are concatenated as [m, n]. 12 | % 13 | % Using this simple linear manifold, Manopt can be used to solve standard 14 | % unconstrained optimization problems, for example in replacement of 15 | % Matlab's fminunc. 16 | % 17 | % See also: euclideancomplexfactory 18 | 19 | % This file is part of Manopt: www.manopt.org. 20 | % Original author: Nicolas Boumal, Dec. 30, 2012. 21 | % Contributors: Bamdev Mishra, May 4, 2015. 22 | % Change log: 23 | % 24 | % July 5, 2013 (NB): 25 | % Added egred2rgrad, ehess2rhess, mat, vec, tangent. 26 | % May 4, 2015 (BM): 27 | % Added functionality to handle multidimensional arrays. 28 | 29 | 30 | % The size can be defined using both m and n, or simply with m. 31 | % If m is a scalar, then n is implicitly 1. 32 | % This mimicks the use of built-in Matlab functions such as zeros(...). 33 | if ~exist('n', 'var') || isempty(n) 34 | if numel(m) == 1 35 | n = 1; 36 | else 37 | n = []; 38 | end 39 | end 40 | 41 | dimensions_vec = [m(:)', n(:)']; % We have a row vector. 42 | 43 | 44 | M.name = @() sprintf('Euclidean space R^(%s)', num2str(dimensions_vec)); % BM: okay. 45 | 46 | M.dim = @() prod(dimensions_vec);% BM: replacing m*n; 47 | 48 | M.inner = @(x, d1, d2) d1(:).'*d2(:); % BM: okay. 49 | 50 | M.norm = @(x, d) norm(d(:), 'fro');% BM: replacing norm(d, 'fro'); 51 | 52 | M.dist = @(x, y) norm(x(:) - y(:), 'fro');% BM: replacing norm(x-y, 'fro'); 53 | 54 | M.typicaldist = @() sqrt(prod(dimensions_vec));% BM: replacing sqrt(m*n); 55 | 56 | M.proj = @(x, d) d; % BM: okay. 57 | 58 | M.egrad2rgrad = @(x, g) g; % BM: okay. 59 | 60 | M.ehess2rhess = @(x, eg, eh, d) eh; % BM: okay. 61 | 62 | M.tangent = M.proj; 63 | 64 | M.exp = @exp; 65 | function y = exp(x, d, t) 66 | if nargin == 3 67 | y = x + t*d; % BM: okay. 68 | else 69 | y = x + d; % BM: okay. 70 | end 71 | end 72 | 73 | M.retr = M.exp; 74 | 75 | M.log = @(x, y) y-x; % BM: okay. 76 | 77 | M.hash = @(x) ['z' hashmd5(x(:))]; % BM: okay. 78 | 79 | M.rand = @() randn(dimensions_vec);% BM: replacing randn(m, n); 80 | 81 | M.randvec = @randvec; 82 | function u = randvec(x) %#ok 83 | u = randn(dimensions_vec);% BM: replacing randn(m, n); 84 | u = u / norm(u(:), 'fro');% BM: replacing u / norm(u, 'fro'); 85 | end 86 | 87 | M.lincomb = @matrixlincomb; 88 | 89 | M.zerovec = @(x) zeros(dimensions_vec);% BM: replacing zeros(m, n); 90 | 91 | M.transp = @(x1, x2, d) d; 92 | 93 | M.pairmean = @(x1, x2) .5*(x1+x2); % BM: okay. 94 | 95 | M.vec = @(x, u_mat) u_mat(:); % BM: okay. 96 | M.mat = @(x, u_vec) reshape(u_vec, dimensions_vec);% BM: replacing reshape(u_vec, [m, n]); 97 | M.vecmatareisometries = @() true; 98 | 99 | end 100 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/euclidean/shapefitfactory.m: -------------------------------------------------------------------------------- 1 | function M = shapefitfactory(VJt) 2 | % Linear manifold structure for optimization over the ShapeFit search space 3 | % 4 | % function M = shapefitfactory(VJt) 5 | % 6 | % Input: VJt is a matrix of size dxn, such that VJt * ones(n, 1) = 0. 7 | % 8 | % Returns M, a structure describing the Euclidean space of d-by-n matrices 9 | % equipped with the standard Frobenius distance and associated trace inner 10 | % product, as a manifold for Manopt. Matrices on M, denoted by T, have size 11 | % dxn and obey T*ones(n, 1) = 0 (centered columns) and = 1, where 12 | % = Trace(A' * B). 13 | % 14 | % See this paper: http://arxiv.org/abs/1506.01437 15 | % ShapeFit: Exact location recovery from corrupted pairwise directions, 2015 16 | % Paul Hand, Choongbum Lee, Vladislav Voroninski 17 | % 18 | % See also: shapefit_smoothed 19 | 20 | % This file is part of Manopt: www.manopt.org. 21 | % Original author: Nicolas Boumal, June 18, 2015. 22 | % Contributors: 23 | % Change log: 24 | 25 | [d, n] = size(VJt); 26 | 27 | M.name = @() sprintf('ShapeFit space of size %d x %d', d, n); 28 | 29 | M.dim = @() d*n - d - 1; 30 | 31 | M.inner = @(x, d1, d2) d1(:).'*d2(:); 32 | 33 | M.norm = @(x, d) norm(d, 'fro'); 34 | 35 | M.dist = @(x, y) norm(x-y, 'fro'); 36 | 37 | M.typicaldist = @() sqrt(d*n); 38 | 39 | M.proj = @(T, U) projection(U); 40 | VJt_normed = VJt / norm(VJt, 'fro'); 41 | function PU = projection(U) 42 | % Center the columns 43 | PU = bsxfun(@minus, U, mean(U, 2)); 44 | % Remove component along VJt 45 | % Note: these two actions can be executed separately, without 46 | % interference, owing to VJt having centered columns itself. 47 | PU = PU - (VJt_normed(:)'*U(:))*VJt_normed; 48 | end 49 | 50 | M.egrad2rgrad = M.proj; 51 | 52 | M.ehess2rhess = @(x, eg, eh, d) projection(eh); 53 | 54 | M.tangent = @(x, d) d; 55 | 56 | M.exp = @exp; 57 | function y = exp(x, d, t) 58 | if nargin == 3 59 | y = x + t*d; 60 | else 61 | y = x + d; 62 | end 63 | end 64 | 65 | M.retr = M.exp; 66 | 67 | M.log = @(x, y) y-x; 68 | 69 | M.hash = @(x) ['z' hashmd5(x(:))]; 70 | 71 | M.randvec = @(x) randvec(); 72 | function u = randvec() 73 | u = projection(randn(d, n)); 74 | u = u / norm(u, 'fro'); 75 | end 76 | 77 | % We exploit the fact that VJt_normed belongs to the manifold 78 | M.rand = @() VJt_normed + randn(1) * randvec(); 79 | 80 | M.lincomb = @matrixlincomb; 81 | 82 | M.zerovec = @(x) zeros(d, n); 83 | 84 | M.transp = @(x1, x2, d) d; 85 | 86 | M.pairmean = @(x1, x2) .5*(x1+x2); 87 | 88 | M.vec = @(x, u_mat) u_mat(:); 89 | M.mat = @(x, u_vec) reshape(u_vec, [d, n]); 90 | M.vecmatareisometries = @() true; 91 | 92 | end 93 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/fixedranktensors/tucker2multiarray.m: -------------------------------------------------------------------------------- 1 | function Xtensor = tucker2multiarray(X) 2 | % Converts a 3d Tucker form tensor to a multiarray. 3 | % 4 | % function Xtensor = tucker2multiarray(X) 5 | % 6 | % X has fields U1, U2, U3, and G. 7 | % 8 | % The matrices U1 (n1-by-r1), U2 (n2-by-r2) and U3 (n3-by-r3) are 9 | % orthogonal matrices. 10 | % G (r1-by-r2-by-r3) is a multidimensional array. 11 | % 12 | % See also: fixedrankfactory_tucker_preconditioned 13 | 14 | % This file is part of Manopt: www.manopt.org. 15 | % Original authors: Hiroyuki Kasai and Bamdev Mishra, June 05, 2015. 16 | % Contributors: 17 | % Change log: 18 | 19 | U1 = X.U1; 20 | U2 = X.U2; 21 | U3 = X.U3; 22 | G = X.G; 23 | 24 | % Tensor size 25 | n1 = size(U1, 1); 26 | n2 = size(U2, 1); 27 | n3 = size(U3, 1); 28 | 29 | % Core size 30 | [r1, r2, r3] = size(G); 31 | 32 | % Multplication by U1 33 | G1 = reshape(G, r1, r2*r3); 34 | GU1 = reshape(U1*G1, n1, r2, r3); 35 | 36 | % Further multplication by U2 37 | G2 = reshape(permute(GU1, [2 1 3]), r2, n1*r3); 38 | GU1U2 = permute(reshape(U2*G2, n2, n1, r3), [2 1 3]); 39 | 40 | % Further multplication by U3 41 | G3 = reshape(permute(GU1U2, [3 1 2]), r3, n1*n2); 42 | GU1U2U3 = permute(reshape(U3*G3, n3, n1, n2), [2 3 1]); 43 | 44 | Xtensor = GU1U2U3;% Full tensor 45 | 46 | end 47 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/rotations/randrot.m: -------------------------------------------------------------------------------- 1 | function R = randrot(n, N) 2 | % Generates uniformly random rotation matrices. 3 | % 4 | % function R = randrot(n, N) 5 | % 6 | % R is a n-by-n-by-N matrix such that each slice R(:, :, i) is an 7 | % orthogonal matrix of size n of determinant +1 (i.e., a matrix in SO(n)). 8 | % By default, N = 1. 9 | % Complexity: N times O(n^3). 10 | % Theory in Diaconis and Shahshahani 1987 for the uniformity on O(n); 11 | % With details in Mezzadri 2007, 12 | % "How to generate random matrices from the classical compact groups." 13 | % To ensure matrices in SO(n), we permute the two first columns when 14 | % the determinant is -1. 15 | % 16 | % See also: randskew 17 | 18 | % This file is part of Manopt: www.manopt.org. 19 | % Original author: Nicolas Boumal, Sept. 25, 2012. 20 | % Contributors: 21 | % Change log: 22 | 23 | if nargin < 2 24 | N = 1; 25 | end 26 | 27 | if n == 1 28 | R = ones(1, 1, N); 29 | return; 30 | end 31 | 32 | R = zeros(n, n, N); 33 | 34 | for i = 1 : N 35 | 36 | % Generated as such, Q is uniformly distributed over O(n), the set 37 | % of orthogonal matrices. 38 | A = randn(n); 39 | [Q, RR] = qr(A); 40 | Q = Q * diag(sign(diag(RR))); %% Mezzadri 2007 41 | 42 | % If Q is in O(n) but not in SO(n), we permute the two first 43 | % columns of Q such that det(new Q) = -det(Q), hence the new Q will 44 | % be in SO(n), uniformly distributed. 45 | if det(Q) < 0 46 | Q(:, [1 2]) = Q(:, [2 1]); 47 | end 48 | 49 | R(:, :, i) = Q; 50 | 51 | end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/rotations/randskew.m: -------------------------------------------------------------------------------- 1 | function S = randskew(n, N) 2 | % Generates random skew symmetric matrices with normal entries. 3 | % 4 | % function S = randskew(n, N) 5 | % 6 | % S is an n-by-n-by-N matrix where each slice S(:, :, i) for i = 1..N is a 7 | % random skew-symmetric matrix with upper triangular entries distributed 8 | % independently following a normal distribution (Gaussian, zero mean, unit 9 | % variance). 10 | % 11 | % See also: randrot 12 | 13 | % This file is part of Manopt: www.manopt.org. 14 | % Original author: Nicolas Boumal, Sept. 25, 2012. 15 | % Contributors: 16 | % Change log: 17 | 18 | 19 | if nargin < 2 20 | N = 1; 21 | end 22 | 23 | % Subindices of the (strictly) upper triangular entries of an n-by-n 24 | % matrix 25 | [I J] = find(triu(ones(n), 1)); 26 | 27 | K = repmat(1:N, n*(n-1)/2, 1); 28 | 29 | % Indices of the strictly upper triangular entries of all N slices of 30 | % an n-by-n-by-N matrix 31 | L = sub2ind([n n N], repmat(I, N, 1), repmat(J, N, 1), K(:)); 32 | 33 | % Allocate memory for N random skew matrices of size n-by-n and 34 | % populate each upper triangular entry with a random number following a 35 | % normal distribution and copy them with opposite sign on the 36 | % corresponding lower triangular side. 37 | S = zeros(n, n, N); 38 | S(L) = randn(size(L)); 39 | S = S-multitransp(S); 40 | 41 | end 42 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/specialeuclidean/specialeuclideanfactory.m: -------------------------------------------------------------------------------- 1 | function M = specialeuclideanfactory(n, k) 2 | % Returns a manifold structure to optimize over the special Euclidean group 3 | % 4 | % function M = specialeuclideanfactory(n) 5 | % function M = specialeuclideanfactory(n, k) 6 | % 7 | % The special Euclidean group (the manifold of rigid transformations): 8 | % This is a product manifold of the rotations group SO(n) and the 9 | % translation group R^n, copied k times. 10 | % 11 | % Points on the manifold are represented as structures X with two fields. 12 | % X.R is a 3D array of size nxnxk such that each slice X.R(:, :, i) 13 | % corresponds to a rotation matrix (orthogonal with determinant 1). 14 | % X.t is a matrix of size nxk such that each column X.t(:, i) corresponds 15 | % to a translation vector. 16 | % 17 | % Tangent vectors are represented as structures with the same fields. Note 18 | % that rotational components of the tangent vectors are represented in the 19 | % Lie algebra, i.e., each slice Xdot.R(:, :, i) is a skew-symmetric matrix. 20 | % Use M.tangent2ambient(X, Xdot) to obtain a representation in the ambient 21 | % space. 22 | % 23 | % This is a description of SE(n)^k with the induced metric from the 24 | % embedding space (R^nxn)^k x (R^n)^k, i.e., this manifold is a Riemannian 25 | % submanifold of the embedding Euclidean space with the usual inner 26 | % product. 27 | % 28 | % By default, k = 1. 29 | % 30 | % This is a test geometry: it may not be the "appropriate" geometry to give 31 | % to SE(n). 32 | % 33 | % See rotationsfactory and euclideanfactory for details. 34 | % 35 | % See also: rotationsfactory euclideanfactory 36 | 37 | % This file is part of Manopt: www.manopt.org. 38 | % Original author: Nicolas Boumal, Sep. 23, 2014. 39 | % Contributors: 40 | % Change log: 41 | 42 | 43 | if ~exist('k', 'var') || isempty(k) 44 | k = 1; 45 | end 46 | 47 | elements = struct(); 48 | elements.R = rotationsfactory(n, k); 49 | elements.t = euclideanfactory(n, k); 50 | 51 | M = productmanifold(elements); 52 | 53 | end 54 | -------------------------------------------------------------------------------- /manopt/manopt/manifolds/sphere/spherefactory.m: -------------------------------------------------------------------------------- 1 | function M = spherefactory(n, m) 2 | % Returns a manifold struct to optimize over unit-norm vectors or matrices. 3 | % 4 | % function M = spherefactory(n) 5 | % function M = spherefactory(n, m) 6 | % 7 | % Manifold of n-by-m real matrices of unit Frobenius norm. 8 | % By default, m = 1, which corresponds to the unit sphere in R^n. The 9 | % metric is such that the sphere is a Riemannian submanifold of the space 10 | % of nxm matrices with the usual trace inner product, i.e., the usual 11 | % metric. 12 | % 13 | % See also: obliquefactory spherecomplexfactory 14 | 15 | % This file is part of Manopt: www.manopt.org. 16 | % Original author: Nicolas Boumal, Dec. 30, 2012. 17 | % Contributors: 18 | % Change log: 19 | 20 | 21 | if ~exist('m', 'var') 22 | m = 1; 23 | end 24 | 25 | if m == 1 26 | M.name = @() sprintf('Sphere S^%d', n-1); 27 | else 28 | M.name = @() sprintf('Unit F-norm %dx%d matrices', n, m); 29 | end 30 | 31 | M.dim = @() n*m-1; 32 | 33 | M.inner = @(x, d1, d2) d1(:).'*d2(:); 34 | 35 | M.norm = @(x, d) norm(d, 'fro'); 36 | 37 | M.dist = @(x, y) real(acos(x(:).'*y(:))); 38 | 39 | M.typicaldist = @() pi; 40 | 41 | M.proj = @(x, d) d - x*(x(:).'*d(:)); 42 | 43 | M.tangent = M.proj; 44 | 45 | % For Riemannian submanifolds, converting a Euclidean gradient into a 46 | % Riemannian gradient amounts to an orthogonal projection. 47 | M.egrad2rgrad = M.proj; 48 | 49 | M.ehess2rhess = @ehess2rhess; 50 | function rhess = ehess2rhess(x, egrad, ehess, u) 51 | rhess = M.proj(x, ehess) - (x(:)'*egrad(:))*u; 52 | end 53 | 54 | M.exp = @exponential; 55 | 56 | M.retr = @retraction; 57 | 58 | M.log = @logarithm; 59 | function v = logarithm(x1, x2) 60 | v = M.proj(x1, x2 - x1); 61 | di = M.dist(x1, x2); 62 | % If the two points are "far apart", correct the norm. 63 | if di > 1e-6 64 | nv = norm(v, 'fro'); 65 | v = v * (di / nv); 66 | end 67 | end 68 | 69 | M.hash = @(x) ['z' hashmd5(x(:))]; 70 | 71 | M.rand = @() random(n, m); 72 | 73 | M.randvec = @(x) randomvec(n, m, x); 74 | 75 | M.lincomb = @matrixlincomb; 76 | 77 | M.zerovec = @(x) zeros(n, m); 78 | 79 | M.transp = @(x1, x2, d) M.proj(x2, d); 80 | 81 | M.pairmean = @pairmean; 82 | function y = pairmean(x1, x2) 83 | y = x1+x2; 84 | y = y / norm(y, 'fro'); 85 | end 86 | 87 | M.vec = @(x, u_mat) u_mat(:); 88 | M.mat = @(x, u_vec) reshape(u_vec, [n, m]); 89 | M.vecmatareisometries = @() true; 90 | 91 | end 92 | 93 | % Exponential on the sphere 94 | function y = exponential(x, d, t) 95 | 96 | if nargin == 2 97 | t = 1; 98 | end 99 | 100 | td = t*d; 101 | 102 | nrm_td = norm(td, 'fro'); 103 | 104 | if nrm_td > 4.5e-8 105 | y = x*cos(nrm_td) + td*(sin(nrm_td)/nrm_td); 106 | else 107 | % If the step is too small to accurately evaluate sin(x)/x, 108 | % then sin(x)/x is almost indistinguishable from 1. 109 | y = x + td; 110 | y = y / norm(y, 'fro'); 111 | end 112 | 113 | end 114 | 115 | % Retraction on the sphere 116 | function y = retraction(x, d, t) 117 | 118 | if nargin == 2 119 | t = 1; 120 | end 121 | 122 | y = x + t*d; 123 | y = y / norm(y, 'fro'); 124 | 125 | end 126 | 127 | % Uniform random sampling on the sphere. 128 | function x = random(n, m) 129 | 130 | x = randn(n, m); 131 | x = x/norm(x, 'fro'); 132 | 133 | end 134 | 135 | % Random normalized tangent vector at x. 136 | function d = randomvec(n, m, x) 137 | 138 | d = randn(n, m); 139 | d = d - x*(x(:).'*d(:)); 140 | d = d / norm(d, 'fro'); 141 | 142 | end 143 | -------------------------------------------------------------------------------- /manopt/manopt/solvers/neldermead/centroid.m: -------------------------------------------------------------------------------- 1 | function y = centroid(M, x) 2 | % Attempts the computation of a centroid of a set of points on a manifold. 3 | % 4 | % function y = centroid(M, x) 5 | % 6 | % M is a structure representing a manifold. 7 | % x is a cell of points on that manifold. 8 | 9 | % This file is part of Manopt: www.manopt.org. 10 | % Original author: Nicolas Boumal, Dec. 30, 2012. 11 | % Contributors: 12 | % Change log: 13 | 14 | 15 | % For now, just apply a few steps of gradient descent for Karcher means 16 | 17 | n = numel(x); 18 | 19 | problem.M = M; 20 | 21 | problem.cost = @cost; 22 | function val = cost(y) 23 | val = 0; 24 | for i = 1 : n 25 | val = val + M.dist(y, x{i})^2; 26 | end 27 | val = val/2; 28 | end 29 | 30 | problem.grad = @grad; 31 | function g = grad(y) 32 | g = M.zerovec(y); 33 | for i = 1 : n 34 | g = M.lincomb(y, 1, g, -1, M.log(y, x{i})); 35 | end 36 | end 37 | 38 | % This line can be uncommented to check that the gradient is indeed 39 | % correct. This should always be the case if the dist and the log 40 | % functions in the manifold are correct. 41 | % checkgradient(problem); pause; 42 | 43 | query = warning('query', 'manopt:getHessian:approx'); 44 | warning('off', 'manopt:getHessian:approx'); 45 | options.verbosity = 0; 46 | options.maxiter = 15; 47 | y = trustregions(problem, x{randi(n)}, options); 48 | warning(query.state, 'manopt:getHessian:approx'); 49 | 50 | end 51 | -------------------------------------------------------------------------------- /manopt/manopt/solvers/trustregions/license for original GenRTR code.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007,2012 Christopher G. Baker, Pierre-Antoine Absil, Kyle A. Gallivan 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the names of the contributors nor of their affiliated 12 | institutions may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | For questions, please contact Chris Baker (chris@cgbaker.net) 27 | -------------------------------------------------------------------------------- /manopt/manopt/tools/checkdiff.m: -------------------------------------------------------------------------------- 1 | function checkdiff(problem, x, d) 2 | % Checks the consistency of the cost function and directional derivatives. 3 | % 4 | % function checkdiff(problem) 5 | % function checkdiff(problem, x) 6 | % function checkdiff(problem, x, d) 7 | % 8 | % checkdiff performs a numerical test to check that the directional 9 | % derivatives defined in the problem structure agree up to first order with 10 | % the cost function at some point x, along some direction d. The test is 11 | % based on a truncated Taylor series (see online Manopt documentation). 12 | % 13 | % Both x and d are optional and will be sampled at random if omitted. 14 | % 15 | % See also: checkgradient checkhessian 16 | 17 | % This file is part of Manopt: www.manopt.org. 18 | % Original author: Nicolas Boumal, Dec. 30, 2012. 19 | % Contributors: 20 | % Change log: 21 | % 22 | % April 3, 2015 (NB): 23 | % Works with the new StoreDB class system. 24 | 25 | 26 | % Verify that the problem description is sufficient. 27 | if ~canGetCost(problem) 28 | error('It seems no cost was provided.'); 29 | end 30 | if ~canGetDirectionalDerivative(problem) 31 | error('It seems no directional derivatives were provided.'); 32 | end 33 | 34 | x_isprovided = exist('x', 'var') && ~isempty(x); 35 | d_isprovided = exist('d', 'var') && ~isempty(d); 36 | 37 | if ~x_isprovided && d_isprovided 38 | error('If d is provided, x must be too, since d is tangent at x.'); 39 | end 40 | 41 | % If x and / or d are not specified, pick them at random. 42 | if ~x_isprovided 43 | x = problem.M.rand(); 44 | end 45 | if ~d_isprovided 46 | d = problem.M.randvec(x); 47 | end 48 | 49 | % Compute the value f0 at f and directional derivative at x along d. 50 | storedb = StoreDB(); 51 | xkey = storedb.getNewKey(); 52 | f0 = getCost(problem, x, storedb, xkey); 53 | df0 = getDirectionalDerivative(problem, x, d, storedb, xkey); 54 | 55 | % Compute the value of f at points on the geodesic (or approximation 56 | % of it) originating from x, along direction d, for stepsizes in a 57 | % large range given by h. 58 | h = logspace(-8, 0, 51); 59 | value = zeros(size(h)); 60 | for i = 1 : length(h) 61 | y = problem.M.exp(x, d, h(i)); 62 | ykey = storedb.getNewKey(); 63 | value(i) = getCost(problem, y, storedb, ykey); 64 | end 65 | 66 | % Compute the linear approximation of the cost function using f0 and 67 | % df0 at the same points. 68 | model = polyval([df0 f0], h); 69 | 70 | % Compute the approximation error 71 | err = abs(model - value); 72 | 73 | % And plot it. 74 | loglog(h, err); 75 | title(sprintf(['Directional derivative check.\nThe slope of the '... 76 | 'continuous line should match that of the dashed '... 77 | '(reference) line\nover at least a few orders of '... 78 | 'magnitude for h.'])); 79 | xlabel('h'); 80 | ylabel('Approximation error'); 81 | 82 | line('xdata', [1e-8 1e0], 'ydata', [1e-8 1e8], ... 83 | 'color', 'k', 'LineStyle', '--', ... 84 | 'YLimInclude', 'off', 'XLimInclude', 'off'); 85 | 86 | 87 | % In a numerically reasonable neighborhood, the error should decrease 88 | % as the square of the stepsize, i.e., in loglog scale, the error 89 | % should have a slope of 2. 90 | window_len = 10; 91 | [range, poly] = identify_linear_piece(log10(h), log10(err), window_len); 92 | hold on; 93 | loglog(h(range), 10.^polyval(poly, log10(h(range))), ... 94 | 'r-', 'LineWidth', 3); 95 | hold off; 96 | 97 | fprintf('The slope should be 2. It appears to be: %g.\n', poly(1)); 98 | fprintf(['If it is far from 2, then directional derivatives ' ... 99 | 'might be erroneous.\n']); 100 | 101 | end 102 | -------------------------------------------------------------------------------- /manopt/manopt/tools/checkgradient.m: -------------------------------------------------------------------------------- 1 | function checkgradient(problem, x, d) 2 | % Checks the consistency of the cost function and the gradient. 3 | % 4 | % function checkgradient(problem) 5 | % function checkgradient(problem, x) 6 | % function checkgradient(problem, x, d) 7 | % 8 | % checkgradient performs a numerical test to check that the gradient 9 | % defined in the problem structure agrees up to first order with the cost 10 | % function at some point x, along some direction d. The test is based on a 11 | % truncated Taylor series (see online Manopt documentation). 12 | % 13 | % It is also tested that the gradient is indeed a tangent vector. 14 | % 15 | % Both x and d are optional and will be sampled at random if omitted. 16 | % 17 | % See also: checkdiff checkhessian 18 | 19 | % This file is part of Manopt: www.manopt.org. 20 | % Original author: Nicolas Boumal, Dec. 30, 2012. 21 | % Contributors: 22 | % Change log: 23 | % 24 | % April 3, 2015 (NB): 25 | % Works with the new StoreDB class system. 26 | 27 | 28 | % Verify that the problem description is sufficient. 29 | if ~canGetCost(problem) 30 | error('It seems no cost was provided.'); 31 | end 32 | if ~canGetGradient(problem) 33 | error('It seems no gradient provided.'); 34 | end 35 | 36 | x_isprovided = exist('x', 'var') && ~isempty(x); 37 | d_isprovided = exist('d', 'var') && ~isempty(d); 38 | 39 | if ~x_isprovided && d_isprovided 40 | error('If d is provided, x must be too, since d is tangent at x.'); 41 | end 42 | 43 | % If x and / or d are not specified, pick them at random. 44 | if ~x_isprovided 45 | x = problem.M.rand(); 46 | end 47 | if ~d_isprovided 48 | d = problem.M.randvec(x); 49 | end 50 | 51 | %% Check that the gradient yields a first order model of the cost. 52 | 53 | % By removing the 'directional derivative' function, it should be so 54 | % (?) that the checkdiff function will use the gradient to compute 55 | % directional derivatives. 56 | if isfield(problem, 'diff') 57 | problem = rmfield(problem, 'diff'); 58 | end 59 | checkdiff(problem, x, d); 60 | title(sprintf(['Gradient check.\nThe slope of the continuous line ' ... 61 | 'should match that of the dashed (reference) line\n' ... 62 | 'over at least a few orders of magnitude for h.'])); 63 | xlabel('h'); 64 | ylabel('Approximation error'); 65 | 66 | %% Try to check that the gradient is a tangent vector. 67 | if isfield(problem.M, 'tangent') 68 | storedb = StoreDB(); 69 | key = storedb.getNewKey(); 70 | grad = getGradient(problem, x, storedb, key); 71 | pgrad = problem.M.tangent(x, grad); 72 | residual = problem.M.lincomb(x, 1, grad, -1, pgrad); 73 | err = problem.M.norm(x, residual); 74 | fprintf('The residual should be 0, or very close. Residual: %g.\n', err); 75 | fprintf('If it is far from 0, then the gradient is not in the tangent space.\n'); 76 | else 77 | fprintf(['Unfortunately, Manopt was unable to verify that the '... 78 | 'gradient is indeed a tangent vector.\nPlease verify ' ... 79 | 'this manually or implement the ''tangent'' function ' ... 80 | 'in your manifold structure.']); 81 | end 82 | 83 | end 84 | -------------------------------------------------------------------------------- /manopt/manopt/tools/dexpm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/dexpm.m -------------------------------------------------------------------------------- /manopt/manopt/tools/dfunm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/dfunm.m -------------------------------------------------------------------------------- /manopt/manopt/tools/diagsum.m: -------------------------------------------------------------------------------- 1 | function [tracedtensor] = diagsum(tensor1, d1, d2) 2 | % C = DIAGSUM(A, d1, d2) Performs the trace 3 | % C(i[1],...,i[d1-1],i[d1+1],...,i[d2-1],i[d2+1],...i[n]) = 4 | % A(i[1],...,i[d1-1],k,i[d1+1],...,i[d2-1],k,i[d2+1],...,i[n]) 5 | % (Sum on k). 6 | % 7 | % C = DIAGSUM(A, d1, d2) traces A along the diagonal formed by dimensions d1 8 | % and d2. If the lengths of these dimensions are not equal, DIAGSUM traces 9 | % until the end of the shortest of dimensions d1 and d2 is reached. This is 10 | % an analogue of the built in TRACE function. 11 | % 12 | % Wynton Moore, January 2006 13 | 14 | 15 | dim1=size(tensor1); 16 | numdims=length(dim1); 17 | 18 | 19 | %check inputs 20 | if d1==d2 21 | tracedtensor=squeeze(sum(tensor1,d1)); 22 | elseif numdims==2 23 | tracedtensor=trace(tensor1); 24 | elseif dim1(d1)==1 && dim1(d2)==1 25 | tracedtensor=squeeze(tensor1); 26 | else 27 | 28 | 29 | %determine correct permutation 30 | swapd1=d1;swapd2=d2; 31 | 32 | if d1~=numdims-1 && d1~=numdims && d2~=numdims-1 33 | swapd1=numdims-1; 34 | elseif d1~=numdims-1 && d1~=numdims && d2~=numdims 35 | swapd1=numdims; 36 | end 37 | if d2~=numdims-1 && d2~=numdims && swapd1~=numdims-1 38 | swapd2=numdims-1; 39 | elseif d2~=numdims-1 && d2~=numdims && swapd1~=numdims 40 | swapd2=numdims; 41 | end 42 | 43 | 44 | %prepare for construction of selector tensor 45 | temp1=eye(numdims); 46 | permmatrix=temp1; 47 | permmatrix(:,d1)=temp1(:,swapd1); 48 | permmatrix(:,swapd1)=temp1(:,d1); 49 | permmatrix(:,d2)=temp1(:,swapd2); 50 | permmatrix(:,swapd2)=temp1(:,d2); 51 | 52 | selectordim=dim1*permmatrix; 53 | permvector=(1:numdims)*permmatrix; 54 | 55 | 56 | %construct selector tensor 57 | if numdims>3 58 | selector = ipermute(outer(ones(selectordim(1:numdims-2)), ... 59 | eye(selectordim(numdims-1), ... 60 | selectordim(numdims)), ... 61 | 0), ... 62 | permvector); 63 | else 64 | %when numdims=3, the above line gives ndims(selector)=4. This 65 | %routine avoids that error. When used with GMDMP, numdims will be 66 | %at least 4, so this routine will be unnecessary. 67 | selector2=eye(selectordim(numdims-1), selectordim(numdims)); 68 | selector=zeros(selectordim); 69 | for j=1:selectordim(1) 70 | selector(j, :, :)=selector2; 71 | end 72 | selector=ipermute(selector, permvector); 73 | end 74 | 75 | 76 | %perform trace, discard resulting singleton dimensions 77 | tracedtensor=sum(sum(tensor1.*selector, d1), d2); 78 | tracedtensor=squeeze(tracedtensor); 79 | 80 | 81 | end 82 | 83 | 84 | %correction for abberation in squeeze function: 85 | %size(squeeze(rand(1,1,2)))=[2 1] 86 | nontracedimensions=dim1; 87 | nontracedimensions(d1)=[]; 88 | if d2>d1 89 | nontracedimensions(d2-1)=[]; 90 | else 91 | nontracedimensions(d2)=[]; 92 | end 93 | tracedsize=size(tracedtensor); 94 | % Next line modified, Nicolas Boumal, April 30, 2012, such that 95 | % diagsum(A, 1, 2) would compute the trace of A, a 2D matrix. 96 | if length(tracedsize)==2 && tracedsize(2)==1 && ... 97 | (isempty(nontracedimensions) || tracedsize(1)~=nontracedimensions(1)) 98 | 99 | tracedtensor=tracedtensor.'; 100 | 101 | end 102 | -------------------------------------------------------------------------------- /manopt/manopt/tools/dlogm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/dlogm.m -------------------------------------------------------------------------------- /manopt/manopt/tools/dsqrtm.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/dsqrtm.m -------------------------------------------------------------------------------- /manopt/manopt/tools/hashmd5.m: -------------------------------------------------------------------------------- 1 | function h = hashmd5(inp) 2 | % Computes the MD5 hash of input data. 3 | % 4 | % function h = hashmd5(inp) 5 | % 6 | % Returns a string containing the MD5 hash of the input variable. The input 7 | % variable may be of any class that can be typecast to uint8 format, which 8 | % is fairly non-restrictive. 9 | 10 | % This file is part of Manopt: www.manopt.org. 11 | % This code is a stripped version of more general hashing code by 12 | % Michael Kleder, Nov 2005. 13 | % Change log: 14 | % 15 | % Aug. 8, 2013 (NB): 16 | % Made x a static (persistent) variable, in the hope it will speed 17 | % it up. Furthermore, the function is now Octave compatible. 18 | 19 | is_octave = exist('OCTAVE_VERSION', 'builtin'); 20 | 21 | persistent x; 22 | if isempty(x) && ~is_octave 23 | x = java.security.MessageDigest.getInstance('MD5'); 24 | end 25 | 26 | inp=inp(:); 27 | % Convert strings and logicals into uint8 format 28 | if ischar(inp) || islogical(inp) 29 | inp=uint8(inp); 30 | else % Convert everything else into uint8 format without loss of data 31 | inp=typecast(inp,'uint8'); 32 | end 33 | 34 | % Create hash 35 | if ~is_octave 36 | x.update(inp); 37 | h = typecast(x.digest, 'uint8'); 38 | h = dec2hex(h)'; 39 | % Remote possibility: all hash bytes < 128, so pad: 40 | if(size(h,1))==1 41 | h = [repmat('0',[1 size(h,2)]);h]; 42 | end 43 | h = lower(h(:)'); 44 | else 45 | h = md5sum(char(inp'), true); 46 | end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /manopt/manopt/tools/identify_linear_piece.m: -------------------------------------------------------------------------------- 1 | function [range, poly] = identify_linear_piece(x, y, window_length) 2 | % Identify a segment of the curve (x, y) that appears to be linear. 3 | % 4 | % function [range poly] = identify_linear_piece(x, y, window_length) 5 | % 6 | % This function attempts to identify a contiguous segment of the curve 7 | % defined by the vectors x and y that appears to be linear. A line is fit 8 | % through the data over all windows of length window_length and the best 9 | % fit is retained. The output specifies the range of indices such that 10 | % x(range) is the portion over which (x, y) is the most linear and the 11 | % output poly specifies a first order polynomial that best fits (x, y) over 12 | % that range, following the usual matlab convention for polynomials 13 | % (highest degree coefficients first). 14 | % 15 | % See also: checkdiff checkgradient checkhessian 16 | 17 | % This file is part of Manopt: www.manopt.org. 18 | % Original author: Nicolas Boumal, July 8, 2013. 19 | % Contributors: 20 | % Change log: 21 | 22 | residues = zeros(length(x)-window_length, 1); 23 | polys = zeros(2, length(residues)); 24 | for i = 1 : length(residues) 25 | range = i:(i+window_length); 26 | [poly, meta] = polyfit(x(range), y(range), 1); 27 | residues(i) = meta.normr; 28 | polys(:, i) = poly'; 29 | end 30 | [unused, best] = min(residues); %#ok 31 | range = best:(best+window_length); 32 | poly = polys(:, best)'; 33 | 34 | end 35 | -------------------------------------------------------------------------------- /manopt/manopt/tools/manoptsolve.m: -------------------------------------------------------------------------------- 1 | function [x, cost, info, options] = manoptsolve(problem, x0, options) 2 | % Gateway helper function to call a Manopt solver, chosen in the options. 3 | % 4 | % function [x, cost, info, options] = manoptsolve(problem) 5 | % function [x, cost, info, options] = manoptsolve(problem, x0) 6 | % function [x, cost, info, options] = manoptsolve(problem, x0, options) 7 | % function [x, cost, info, options] = manoptsolve(problem, [], options) 8 | % 9 | % Depending on what is available in the Manopt problem structure, one of 10 | % the Manopt solvers will be called and the outputs passed along. It is 11 | % also possible to force the choice of a solver by specifying it in the 12 | % options structure. For example: 13 | % 14 | % options.solver = @trustregions; 15 | % 16 | % Simply specify a function handle to a Manopt solver. 17 | % 18 | % See also: trustregions conjugategradient steepestdescent 19 | 20 | % This file is part of Manopt: www.manopt.org. 21 | % Original author: Nicolas Boumal, Aug. 13, 2014. 22 | % Contributors: 23 | % Change log: 24 | 25 | % At the very least, we need a cost function. 26 | if ~canGetCost(problem) 27 | error('The problem structure must specify a cost function.'); 28 | end 29 | 30 | % Depending on the number of differentials available, pick a different 31 | % default solver. 32 | if ~canGetGradient(problem) 33 | localdefaults.solver = @neldermead; 34 | elseif ~canGetHessian(problem) 35 | localdefaults.solver = @conjugategradient; 36 | else 37 | localdefaults.solver = @trustregions; 38 | end 39 | 40 | % Merge local defaults with user options, if any. 41 | if ~exist('options', 'var') || isempty(options) 42 | options = struct(); 43 | end 44 | options = mergeOptions(localdefaults, options); 45 | 46 | % If no initial guess was specified, prepare the empty one. 47 | if ~exist('x0', 'var') 48 | x0 = []; 49 | end 50 | 51 | % Issue the actual call. 52 | [x, cost, info, options] = options.solver(problem, x0, options); 53 | 54 | end 55 | -------------------------------------------------------------------------------- /manopt/manopt/tools/matrixlincomb.m: -------------------------------------------------------------------------------- 1 | function v = matrixlincomb(x, a1, d1, a2, d2) %#ok 2 | % Linear combination function for tangent vectors represented as matrices. 3 | % 4 | % function v = lincomb(x, a1, d1) 5 | % function v = lincomb(x, a1, d1, a2, d2) 6 | % 7 | % Given a point x, two tangent vectors d1 and d2 at x, and two real 8 | % coefficients a1 and a2, returns a tangent vector at x representing 9 | % a1*d1 + a2*d2, if d1 and d2 are represented as matrices (or more 10 | % generally as arrays in Matlab). 11 | % 12 | % If a2 and d2 are omitted, the returned tangent vector is a1*d1. 13 | % 14 | % The input x is actually unused. 15 | % 16 | % This function is a helper to define manifolds in Manopt. 17 | 18 | % This file is part of Manopt: www.manopt.org. 19 | % Original author: Nicolas Boumal, July 2, 2015. 20 | % Contributors: 21 | % Change log: 22 | 23 | if nargin == 3 24 | v = a1*d1; 25 | elseif nargin == 5 26 | v = a1*d1 + a2*d2; 27 | else 28 | error('matrixlincomb takes either 3 or 5 inputs.'); 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multihconj.m: -------------------------------------------------------------------------------- 1 | function b = multihconj(a, dim) 2 | %MULTIHCONJ Hermitian conjugating arrays of matrices. 3 | % B = MULTIHCONJ(A) is equivalent to B = MULTIHCONJ(A, DIM), where 4 | % DIM = 1. 5 | % 6 | % B = MULTIHCONJ(A, DIM) is equivalent to 7 | % B = PERMUTE(A, [1:DIM-1, DIM+1, DIM, DIM+2:NDIMS(A)]), where A is an 8 | % array containing N P-by-Q matrices along its dimensions DIM and DIM+1, 9 | % and B is an array containing the Q-by-P Hermitian conjugate (') of 10 | % those N matrices along the same dimensions. N = NUMEL(A) / (P*Q), i.e. 11 | % N is equal to the number of elements in A divided by the number of 12 | % elements in each matrix. 13 | % 14 | % 15 | % Example: 16 | % A 5-by-9-by-3-by-2 array may be considered to be a block array 17 | % containing ten 9-by-3 matrices along dimensions 2 and 3. In this 18 | % case, its size is so indicated: 5-by-(9-by-3)-by-2 or 5x(9x3)x2. 19 | % If A is ................ a 5x(9x3)x2 array of 9x3 matrices, 20 | % C = MULTIHCONJ(A, 2) is a 5x(3x9)x2 array of 3x9 matrices. 21 | % 22 | % See also MULTITRANSP MULTIHERM. 23 | 24 | % This file is part of Manopt: www.manopt.org. 25 | % Original author: Hiroyuki Sato, April 27, 2015. 26 | % Contributors: 27 | % Change log: 28 | 29 | % Setting DIM if not supplied. 30 | if nargin == 1, dim = 1; end 31 | 32 | % Transposing 33 | b = multitransp(a, dim); 34 | 35 | %Conjugating 36 | b = conj(b); 37 | 38 | end 39 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multiherm.m: -------------------------------------------------------------------------------- 1 | function Y = multiherm(X) 2 | % Returns the Hermitian parts of the matrices in the 3D matrix X 3 | % 4 | % function Y = multiherm(X) 5 | % 6 | % Y is a 3D matrix the same size as X. Each slice Y(:, :, i) is the 7 | % Hermitian part of the slice X(:, :, i). 8 | % 9 | % See also: multiprod multitransp multihconj multiscale multiskew 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Hiroyuki Sato, April 27, 2015. 13 | % Contributors: 14 | % Change log: 15 | 16 | Y = .5*(X + multihconj(X)); 17 | 18 | end 19 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multiprod.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/manopt/manopt/tools/multiprod.m -------------------------------------------------------------------------------- /manopt/manopt/tools/multiprodmultitransp_license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009, Paolo de Leva 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multiscale.m: -------------------------------------------------------------------------------- 1 | function A = multiscale(scale, A) 2 | % Multiplies the 2D slices in a 3D matrix by individual scalars. 3 | % 4 | % function A = multiscale(scale, A) 5 | % 6 | % Given a vector scale of length N and a 3-dimensional matrix A of size 7 | % n-by-m-by-N, returns a matrix A of same size such that 8 | % A(:, :, k) := scale(k) * A(:, :, k); 9 | % 10 | % See also: multiprod multitransp multitrace 11 | 12 | % This file is part of Manopt: www.manopt.org. 13 | % Original author: Nicolas Boumal, Dec. 30, 2012. 14 | % Contributors: 15 | % Change log: 16 | 17 | 18 | assert(ndims(A) <= 3, ... 19 | ['multiscale is only well defined for matrix arrays of 3 ' ... 20 | 'or less dimensions.']); 21 | [n, m, N] = size(A); 22 | assert(numel(scale) == N, ... 23 | ['scale must be a vector whose length equals the third ' ... 24 | 'dimension of A, that is, the number of 2D matrix slices ' ... 25 | 'in the 3D matrix A.']); 26 | 27 | scale = scale(:); 28 | A = reshape(bsxfun(@times, reshape(A, n*m, N), scale'), n, m, N); 29 | 30 | end 31 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multiskew.m: -------------------------------------------------------------------------------- 1 | function Y = multiskew(X) 2 | % Returns the skew-symmetric parts of the matrices in the 3D matrix X. 3 | % 4 | % function Y = multiskew(X) 5 | % 6 | % Y is a 3D matrix the same size as X. Each slice Y(:, :, i) is the 7 | % skew-symmetric part of the slice X(:, :, i). 8 | % 9 | % See also: multiprod multitransp multiscale multisym 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, Jan. 31, 2013. 13 | % Contributors: 14 | % Change log: 15 | 16 | Y = .5*(X - multitransp(X)); 17 | 18 | end 19 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multisqnorm.m: -------------------------------------------------------------------------------- 1 | function sqnorm = multisqnorm(A) 2 | % Returns the squared Frobenius norms of the slices of a 3D matrix. 3 | % 4 | % function sqnorm = multisqnorm(A) 5 | % 6 | % Given a 3-dimensional matrix A of size n-by-m-by-N, returns a column 7 | % vector of length N such that sqnorm(i) = norm(A(:, :, i), 'fro')^2. 8 | % 9 | % See also: multiprod multitransp multitrace norms 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, June 17, 2015. 13 | % Contributors: 14 | % Change log: 15 | 16 | 17 | assert(ndims(A) <= 3, ... 18 | ['multisqnorm is only well defined for matrix arrays of 3 ' ... 19 | 'or less dimensions.']); 20 | [n, m, N] = size(A); 21 | 22 | % This is equivalent to squeeze(sum(norms(A, 2, 1).^2)), but faster. 23 | sqnorm = sum(reshape(A, n*m, N).^2, 1)'; 24 | 25 | end 26 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multisym.m: -------------------------------------------------------------------------------- 1 | function Y = multisym(X) 2 | % Returns the symmetric parts of the matrices in the 3D matrix X 3 | % 4 | % function Y = multisym(X) 5 | % 6 | % Y is a 3D matrix the same size as X. Each slice Y(:, :, i) is the 7 | % symmetric part of the slice X(:, :, i). 8 | % 9 | % See also: multiprod multitransp multiscale multiskew 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, Jan. 31, 2013. 13 | % Contributors: 14 | % Change log: 15 | 16 | Y = .5*(X + multitransp(X)); 17 | 18 | end 19 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multitrace.m: -------------------------------------------------------------------------------- 1 | function tr = multitrace(A) 2 | % Computes the traces of the 2D slices in a 3D matrix. 3 | % 4 | % function tr = multitrace(A) 5 | % 6 | % For a 3-dimensional matrix A of size n-by-n-by-N, returns a column vector 7 | % tr of length N such that tr(k) = trace(A(:, :, k)); 8 | % 9 | % See also: multiprod multitransp multiscale 10 | 11 | % This file is part of Manopt: www.manopt.org. 12 | % Original author: Nicolas Boumal, Dec. 30, 2012. 13 | % Contributors: 14 | % Change log: 15 | 16 | 17 | assert(ndims(A) <= 3, ... 18 | ['multitrace is only well defined for matrix arrays of 3 ' ... 19 | 'or less dimensions.']); 20 | 21 | tr = diagsum(A, 1, 2); 22 | 23 | end 24 | -------------------------------------------------------------------------------- /manopt/manopt/tools/multitransp.m: -------------------------------------------------------------------------------- 1 | function b = multitransp(a, dim) 2 | % Transposing arrays of matrices. 3 | % 4 | % B = MULTITRANSP(A) is equivalent to B = MULTITRANSP(A, DIM), where 5 | % DIM = 1. 6 | % 7 | % B = MULTITRANSP(A, DIM) is equivalent to 8 | % B = PERMUTE(A, [1:DIM-1, DIM+1, DIM, DIM+2:NDIMS(A)]), where A is an 9 | % array containing N P-by-Q matrices along its dimensions DIM and DIM+1, 10 | % and B is an array containing the Q-by-P transpose (.') of those N 11 | % matrices along the same dimensions. N = NUMEL(A) / (P*Q), i.e. N is 12 | % equal to the number of elements in A divided by the number of elements 13 | % in each matrix. 14 | % 15 | % MULTITRANSP, PERMUTE and IPERMUTE are a generalization of TRANSPOSE 16 | % (.') for N-D arrays. 17 | % 18 | % Example: 19 | % A 5-by-9-by-3-by-2 array may be considered to be a block array 20 | % containing ten 9-by-3 matrices along dimensions 2 and 3. In this 21 | % case, its size is so indicated: 5-by-(9-by-3)-by-2 or 5x(9x3)x2. 22 | % If A is ................ a 5x(9x3)x2 array of 9x3 matrices, 23 | % C = MULTITRANSP(A, 2) is a 5x(3x9)x2 array of 3x9 matrices. 24 | % 25 | % See also PERMUTE, IPERMUTE, MULTIPROD, MULTITRACE, MULTISCALE. 26 | 27 | % $ Version: 1.0 $ 28 | % CODE by: Paolo de Leva (IUSM, Rome, IT) 2005 Sep 9 29 | % COMMENTS by: Code author 2006 Nov 21 30 | % OUTPUT tested by: Code author 2005 Sep 13 31 | % ------------------------------------------------------------------------- 32 | 33 | % Setting DIM if not supplied. 34 | if nargin == 1, dim = 1; end 35 | 36 | % Transposing 37 | order = [1:dim-1, dim+1, dim, dim+2:ndims(a)]; 38 | b = permute(a, order); 39 | 40 | end 41 | -------------------------------------------------------------------------------- /manopt/manopt/tools/plotprofile.m: -------------------------------------------------------------------------------- 1 | function cost = plotprofile(problem, x, d, t) 2 | % Plot the cost function along a geodesic or a retraction path. 3 | % 4 | % function plotprofile(problem, x, d, t) 5 | % function costs = plotprofile(problem, x, d, t) 6 | % 7 | % Plot profile evaluates the cost function along a geodesic gamma(t) such 8 | % that gamma(0) = x and the derivative of gamma at 0 is the direction d. 9 | % The input t is a vector specifying for which values of t we must evaluate 10 | % f(gamma(t)) (it may include negative values). 11 | % 12 | % If the function is called with an output, the plot is not drawn and the 13 | % values of the cost are returned for the instants t. 14 | 15 | % This file is part of Manopt: www.manopt.org. 16 | % Original author: Nicolas Boumal, Jan. 9, 2013. 17 | % Contributors: 18 | % Change log: 19 | % 20 | % April 3, 2015 (NB): 21 | % Works with the new StoreDB class system. 22 | 23 | % Verify that the problem description is sufficient. 24 | if ~canGetCost(problem) 25 | error('It seems no cost was provided.'); 26 | end 27 | 28 | if isfield(problem.M, 'exp') 29 | expo = problem.M.exp; 30 | str = 'Exp'; 31 | else 32 | expo = problem.M.retr; 33 | str = 'Retr'; 34 | end 35 | 36 | storedb = StoreDB(); 37 | linesearch_fun = @(t) getCost(problem, expo(x, d, t), storedb); 38 | 39 | cost = zeros(size(t)); 40 | for i = 1 : numel(t) 41 | cost(i) = linesearch_fun(t(i)); 42 | end 43 | 44 | if nargout == 0 45 | plot(t, cost); 46 | xlabel('t'); 47 | ylabel(['f(' str '_x(t*d))']); 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /manopt/manopt/tools/statsfunhelper.m: -------------------------------------------------------------------------------- 1 | function statsfun = statsfunhelper(inp1, inp2) 2 | % Helper tool to create a statsfun for the options structure of solvers. 3 | % 4 | % function statsfun = statsfunhelper(name, fun) 5 | % function statsfun = statsfunhelper(S) 6 | % 7 | % Usage with (name, fun): 8 | % 9 | % Input 1: name is a string which is a valid field name (no spaces, starts 10 | % with a letter or an underscore, only alphanumeric characters and 11 | % underscores). 12 | % 13 | % Input2: fun is a function handle with one output and 1 to 4 inputs, as 14 | % follows (your choice): 15 | % 16 | % fun(x) or fun(problem, x) or 17 | % fun(problem, x, stats) or fun(problem, x, stats, store) 18 | % 19 | % where the inputs are the ones that would be given to options.statsfun, as 20 | % described in the help of the solver used. Typically, x is the point on 21 | % the manifold at the current iterate, problem is the Manopt problem 22 | % structure, stats is all the current statistics recorded for that iterate 23 | % and store is the cache structure at the current iterate. 24 | % 25 | % When calling a Manopt solver with the options structure, such as for 26 | % example with: 27 | % 28 | % [x, xcost, info] = steepestdescent(problem, [], options); 29 | % 30 | % you may set a field of the options structure as follows: 31 | % 32 | % options.statsfun = statsfunhelper('nameofthefield', fun); 33 | % 34 | % As a result, at each iteration, the stats structure will contain a field 35 | % stats.nameofthefield with the value returned by the call to fun at that 36 | % iterate. The stats structures are stored in the struct-array info. 37 | % As an example, if the value returned by fun is a scalar, then 38 | % [info.nameofthefield] is a vector containing all returned values. 39 | % 40 | % 41 | % Usage with S: 42 | % 43 | % The input S is a structure. For each field of S, say S.field, the stats 44 | % structure will be augmented with stats.field = fun(..), where fun is the 45 | % function handle stored in S.field, and with the same conventions as 46 | % above. This version allows to record more than one bit of information at 47 | % each iteration. Example: 48 | % 49 | % metrics.nameofthefield = fun; 50 | % metrics.othername = otherfun; 51 | % options.statsfun = statsfunhelper(metrics); 52 | % 53 | % The different function handles (here, fun and otherfun) can take 1 to 4 54 | % inputs too, and they do not have to take the same number of inputs. 55 | 56 | % This file is part of Manopt: www.manopt.org. 57 | % Original author: Nicolas Boumal, Dec. 17, 2014. 58 | % Contributors: 59 | % Change log: 60 | 61 | if (nargin == 1) && isstruct(inp1) 62 | S = inp1; 63 | elseif (nargin == 2) 64 | S = struct(inp1, inp2); 65 | else 66 | error('statsfunhelper takes 1 or 2 inputs. If 1 input, it must be a structure.'); 67 | end 68 | 69 | 70 | function stats = thestatsfun(problem, x, stats, store) 71 | names = fieldnames(S); 72 | for it = 1 : length(names) 73 | name = names{it}; 74 | fun = S.(name); 75 | switch nargin(fun) 76 | case 1 77 | stats.(name) = fun(x); 78 | case 2 79 | stats.(name) = fun(problem, x); 80 | case 3 81 | stats.(name) = fun(problem, x, stats); 82 | case 4 83 | stats.(name) = fun(problem, x, stats, store); 84 | otherwise 85 | error('The functions passed to statsfunhelper must take 1 to 4 inputs.'); 86 | end 87 | end 88 | end 89 | 90 | statsfun = @thestatsfun; 91 | 92 | end 93 | -------------------------------------------------------------------------------- /manopt/manopt/tools/surfprofile.m: -------------------------------------------------------------------------------- 1 | function costs = surfprofile(problem, x, d1, d2, t1, t2) 2 | % Plot the cost function as a surface over a 2-dimensional subspace. 3 | % 4 | % function surfprofile(problem, x, d1, d2, t1, t2) 5 | % function costs = surfprofile(problem, x, d1, d2, t1, t2) 6 | % 7 | % Evaluates the cost function at points 8 | % 9 | % gamma(t1, t2) = exponential_x(t1*d1 + t2*d2) 10 | % 11 | % where the exponential map at x is specified by problem.M.exp (retr is 12 | % used instead if needed). d1 and d2 are two tangent vectors to problem.M 13 | % at the point x. The values assigned to t1 and t2 are as specified in the 14 | % two input vectors t1 and t2. 15 | % 16 | % If the function is called with an output, the plot is not drawn and the 17 | % values of the cost are returned in a matrix of size 18 | % length(t1)*length(t2). To plot a surf, call surf(t1, t2, costs.') (notice 19 | % the transpose). 20 | 21 | % This file is part of Manopt: www.manopt.org. 22 | % Original author: Nicolas Boumal, Sep. 1, 2014. 23 | % Contributors: 24 | % Change log: 25 | % 26 | % April 3, 2015 (NB): 27 | % Works with the new StoreDB class system. 28 | 29 | % Verify that the problem description is sufficient. 30 | if ~canGetCost(problem) 31 | error('It seems no cost was provided.'); 32 | end 33 | 34 | if isfield(problem.M, 'exp') 35 | expo = problem.M.exp; 36 | str = 'Exp'; 37 | else 38 | expo = problem.M.retr; 39 | str = 'Retr'; 40 | end 41 | 42 | storedb = StoreDB(); 43 | linesearch_fun = @(ta, tb) getCost(problem, ... 44 | expo(x, problem.M.lincomb(x, ta, d1, tb, d2)), ... 45 | storedb); 46 | 47 | costs = zeros(length(t1), length(t2)); 48 | for i = 1 : length(t1) 49 | for j = 1 : length(t2) 50 | costs(i, j) = linesearch_fun(t1(i), t2(j)); 51 | end 52 | end 53 | 54 | if nargout == 0 55 | surf(t1, t2, costs.'); 56 | xlabel('t1'); 57 | ylabel('t2'); 58 | zlabel(['f(' str '_x(t1*d1+t2*d2))']); 59 | end 60 | 61 | end 62 | -------------------------------------------------------------------------------- /manopt/manopt/tools/tangentspacefactory.m: -------------------------------------------------------------------------------- 1 | function N = tangentspacefactory(M, x) 2 | % Returns a manifold structure representing the tangent space to M at x. 3 | % 4 | % N = tangentspacefactory(M, x) 5 | % 6 | % N defines a (linear) manifold that is the tangent space to M at x. Points 7 | % are represented as tangent vectors to M at x. Tangent vectors are also 8 | % represented as tangent vectors to M at x. 9 | % 10 | % This is chiefly useful to solve optimization problems involving tangent 11 | % vectors to M at x, which notably comes up when solving linear systems 12 | % involving, for example, the Hessian of the cost on M at x. The Riemannian 13 | % (actually, Euclidean) structure on N is that of the tangent space to M, 14 | % that is, the inner product is inherited. 15 | % 16 | % See also: preconhessiansolve 17 | 18 | % This file is part of Manopt: www.manopt.org. 19 | % Original author: Nicolas Boumal, April 9, 2015. 20 | % Contributors: 21 | % Change log: 22 | 23 | % N is the manifold we build. y will be a point on N, thus also a 24 | % tangent vector to M at x. This is a typical Euclidean space, hence it 25 | % will be easy to describe in terms of the tools available for M. 26 | N = struct(); 27 | 28 | % u, u1 and u2 will be tangent vectors to N at y. The tangent space to 29 | % N at y is the tangent space to M at x, thus u, u1 and u2 are also 30 | % tangent vectors to M at x. 31 | 32 | N.dim = @() M.dim(); 33 | N.inner = @(y, u1, u2) M.inner(x, u1, u2); 34 | N.norm = @(y, u) M.norm(x, u); 35 | N.proj = M.proj; 36 | N.typicaldist = @() N.dim(); 37 | N.tangent = @(y, u) u; 38 | N.egrad2rgrad = @(x, g) g; 39 | N.ehess2rhess = @(x, eg, eh, d) eh; 40 | N.exp = @exponential; 41 | N.retr = @exponential; 42 | N.log = @(y1, y2) M.lincomb(x, 1, y2, -1, y1); 43 | N.pairmean = @(y1, y2) M.lincomb(x, 0.5, y1, 0.5, y2); 44 | N.rand = @() M.randvec(x); 45 | N.randvec = @(y) M.randvec(x); 46 | N.zerovec = M.zerovec; 47 | N.lincomb = M.lincomb; 48 | N.transp = @(y1, y2, u) u; 49 | N.hash = @(y) ['z' hashmd5(M.vec(x, y))]; 50 | 51 | % In a Euclidean space, the exponential is merely the sum: y + tu. 52 | function yy = exponential(y, u, t) 53 | if nargin == 2 54 | t = 1; 55 | end 56 | yy = M.lincomb(x, 1, y, t, u); 57 | end 58 | 59 | end 60 | -------------------------------------------------------------------------------- /manopt/manopt/tools/tangentspherefactory.m: -------------------------------------------------------------------------------- 1 | function N = tangentspherefactory(M, x) 2 | % Returns a manifold struct. for the sphere on the tangent space to M at x. 3 | % 4 | % N = tangentspherefactory(M, x) 5 | % 6 | % N defines a manifold that is the unit sphere on the tangent space to M 7 | % at x. Points are represented as tangent vectors of unit norm. Tangent 8 | % vectors are represented as tangent vectors orthogonal to the root point, 9 | % with respect to the Riemannian metric on the tangent space. 10 | % 11 | % This is chiefly useful to solve optimization problems involving unit norm 12 | % tangent vectors to M at x, which notably comes up when looking for 13 | % extreme eigenvectors of the Hessian of a cost function on M at x, for 14 | % example. The Riemannian structure on this sphere is that of a Riemannian 15 | % submanifold of the (Euclidean) tangent space, equipped with the 16 | % Riemannian metric of M at that point. 17 | % 18 | % See also: hessianextreme 19 | 20 | % This file is part of Manopt: www.manopt.org. 21 | % Original author: Nicolas Boumal, March 16, 2015. 22 | % Contributors: 23 | % Change log: 24 | 25 | % N is the manifold we build. y will be a point on N, thus also a 26 | % tangent vector to M at x. This is a typical Riemannian submanifold of 27 | % a Euclidean space, hence it will be easy to describe in terms of the 28 | % tools available for M. 29 | N = struct(); 30 | 31 | % u, u1 and u2 will be tangent vectors to N at y. The tangent space to 32 | % N at y is a subspace of the tangent space to M at x, thus u, u1 and 33 | % u2 are also tangent vectors to M at x. 34 | 35 | N.dim = @() M.dim() - 1; 36 | N.inner = @(y, u1, u2) M.inner(x, u1, u2); 37 | N.norm = @(y, u) M.norm(x, u); 38 | N.proj = @(y, v) M.lincomb(x, 1, v, -M.inner(x, v, y), y); 39 | N.typicaldist = @() 1; 40 | N.tangent = N.proj; 41 | N.egrad2rgrad = N.proj; 42 | N.retr = @retraction; 43 | N.exp = N.retr; 44 | function yy = retraction(y, u, t) 45 | if nargin == 2 46 | t = 1; 47 | end 48 | y_plus_tu = M.lincomb(x, 1, y, t, u); 49 | nrm = M.norm(x, y_plus_tu); 50 | yy = M.lincomb(x, 1/nrm, y_plus_tu); 51 | end 52 | N.rand = @random; 53 | function y = random() 54 | y = M.randvec(x); 55 | nrm = M.norm(x, y); 56 | y = M.lincomb(x, 1/nrm, y); 57 | end 58 | N.randvec = @randvec; 59 | function u = randvec(y) 60 | u = N.proj(y, N.rand()); 61 | nrm = N.norm(y, u); 62 | u = M.lincomb(x, 1/nrm, u); 63 | end 64 | N.zerovec = M.zerovec; 65 | N.lincomb = M.lincomb; 66 | N.transp = @(y1, y2, u) N.proj(y2, u); 67 | N.hash = @(y) ['z' hashmd5(M.vec(x, y))]; 68 | 69 | end 70 | -------------------------------------------------------------------------------- /manopt/manopt_version.m: -------------------------------------------------------------------------------- 1 | function [version, released] = manopt_version() 2 | % Returns the version of the Manopt package you are running, as a vector. 3 | % 4 | % function [version, released] = manopt_version() 5 | % 6 | % version(1) is the primary version number. 7 | % released is the date this version was released, in the same format as the 8 | % date() function in Matlab. 9 | 10 | version = [2, 0, 0]; 11 | released = '06-Jul-2015'; 12 | 13 | end 14 | -------------------------------------------------------------------------------- /pose-hg-demo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniilidis-group/monocap/d1f9e1e8cb3b7b17a250860df6af9b22e7569fe1/pose-hg-demo/.DS_Store -------------------------------------------------------------------------------- /pose-hg-demo/.gitignore: -------------------------------------------------------------------------------- 1 | *.t7 2 | -------------------------------------------------------------------------------- /pose-hg-demo/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, University of Michigan 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /pose-hg-demo/README.md: -------------------------------------------------------------------------------- 1 | # Stacked Hourglass Networks for Human Pose Estimation (Demo Code) 2 | 3 | This repository includes Torch code for evaluation and visualization of the network presented in: 4 | 5 | Alejandro Newell, Kaiyu Yang, and Jia Deng, 6 | **Stacked Hourglass Networks for Human Pose Estimation**, 7 | [arXiv:1603.06937](http://arxiv.org/abs/1603.06937), 2016. 8 | 9 | A pretrained model is available on the [project site](http://www-personal.umich.edu/~alnewell/pose). Include the model in the main directory of this repository to run the demo code. 10 | 11 | **Check out the training and experimentation code now available at: [https://github.com/anewell/pose-hg-train](https://github.com/anewell/pose-hg-train)** 12 | 13 | In addition, if you download the full [MPII Human Pose dataset](http://human-pose.mpi-inf.mpg.de) and replace this repository's `images` directory you can generate full predictions on the validation and test sets. 14 | 15 | To run this code, the following must be installed: 16 | 17 | - [Torch7](https://github.com/torch/torch7) 18 | - hdf5 (and the [torch-hdf5](https://github.com/deepmind/torch-hdf5/) package) 19 | - cudnn 20 | - qlua (for displaying results) 21 | 22 | For displaying the demo images: 23 | `qlua main.lua demo` 24 | 25 | For generating predictions: 26 | `th main.lua predict-[valid or test]` 27 | 28 | For evaluation on a set of validation predictions: 29 | `th main.lua eval` 30 | 31 | ## Testing your own images 32 | 33 | To use the network off-the-shelf, it is critical that the target person is centered in the input image. There is some robustness to scale, but for best performance the person should be sized such that their full height is roughly three-quarters of the input height. Play around with different scale settings to see the impact it has on the network output. We offer a convenient function for generating an input image: 34 | 35 | `inputImg = crop(img, center, scale, rot, res)` 36 | 37 | `res` should be set to 256 for our network. `rot` is offered if you wish to rotate the image (in degrees). You can run the input image through the network, and get the (x,y) coordinates with: 38 | 39 | `outputHm = m:forward(inputImg:view(1,3,256,256):cuda())` 40 | 41 | `predsHm,predsImg = getPreds(outputHm, center, scale)` 42 | 43 | The two outputs of `getPreds` are coordinates with respect to either the heatmap or the original image (using center and scale to apply the appropriate transformation back to the image space). 44 | 45 | The MPII images come with center and scale annotations already. An important detail with regards to the annotations: we have modified their format slightly for ease of use with our code. In addition, we adjusted the original center and scale annotations uniformly across all images so as to reduce the chances of our function cropping out feet from the bottom of the image. This mostly involved moving the center down a fraction. 46 | 47 | -------------------------------------------------------------------------------- /pose-hg-demo/model.sh: -------------------------------------------------------------------------------- 1 | # Download Stacked Hourglass model 2 | wget http://www-personal.umich.edu/~alnewell/pose/umich-stacked-hourglass.zip 3 | unzip umich-stacked-hourglass.zip 4 | mv umich-stacked-hourglass/umich-stacked-hourglass.t7 ./ 5 | rm umich-stacked-hourglass.zip 6 | rm -r umich-stacked-hourglass -------------------------------------------------------------------------------- /pose-hg-demo/residual.lua: -------------------------------------------------------------------------------- 1 | local conv = nnlib.SpatialConvolution 2 | local batchnorm = nn.SpatialBatchNormalization 3 | local relu = nnlib.ReLU 4 | 5 | -- Main convolutional block 6 | local function convBlock(numIn,numOut) 7 | return nn.Sequential() 8 | :add(conv(numIn,numOut/2,1,1)) 9 | :add(batchnorm(numOut/2)) 10 | :add(relu(true)) 11 | :add(conv(numOut/2,numOut/2,3,3,1,1,1,1)) 12 | :add(batchnorm(numOut/2)) 13 | :add(relu(true)) 14 | :add(conv(numOut/2,numOut,1,1)) 15 | :add(batchnorm(numOut)) 16 | end 17 | 18 | -- Skip layer 19 | local function skipLayer(numIn,numOut) 20 | if numIn == numOut then 21 | return nn.Identity() 22 | else 23 | return nn.Sequential() 24 | :add(conv(numIn,numOut,1,1)) 25 | :add(batchnorm(numOut)) 26 | end 27 | end 28 | 29 | -- Residual block 30 | function Residual(numIn,numOut) 31 | return nn.Sequential() 32 | :add(nn.ConcatTable() 33 | :add(convBlock(numIn,numOut)) 34 | :add(skipLayer(numIn,numOut))) 35 | :add(nn.CAddTable(true)) 36 | end 37 | -------------------------------------------------------------------------------- /pose-hg-demo/run-hg.lua: -------------------------------------------------------------------------------- 1 | -- Generate heatmaps for all images in a folder 2 | -- The heatmaps are saved as hdf5 files in the same folder 3 | -- routine: th run-hg.lua FolderName ImageFilenameExtension 4 | -- example: th run-hg.lua ../data/tennis jpg 5 | 6 | require 'paths' 7 | paths.dofile('util.lua') 8 | paths.dofile('img.lua') 9 | 10 | local imgdir = arg[1] 11 | local ext = arg[2] 12 | 13 | model = torch.load('umich-stacked-hourglass.t7') -- Load pre-trained model 14 | 15 | for file in paths.files(imgdir) do 16 | if file:find(ext .. '$') then 17 | local name = paths.concat(imgdir,file) 18 | local img = image.load(name) 19 | local center = torch.Tensor(2) 20 | center[1] = img:size(3)/2 21 | center[2] = img:size(2)/2 22 | local scale = img:size(2) / 200 23 | local savefile = name:gsub(ext,'h5') 24 | 25 | local inp = crop(img,center,scale,0,256) 26 | local out = model:forward(inp:view(1,3,256,256):cuda()) 27 | local hm = out[2][1]:float() 28 | hm[hm:lt(0)] = 0 29 | 30 | local predFile = hdf5.open(savefile,'w') 31 | predFile:write('heatmap',hm) 32 | predFile:close() 33 | 34 | print(savefile) 35 | 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /pose-hg-demo/stacked-hourglass-model.lua: -------------------------------------------------------------------------------- 1 | paths.dofile('residual.lua') 2 | 3 | local function hourglass(n, numIn, numOut, inp) 4 | -- Upper branch 5 | local up1 = Residual(numIn,256)(inp) 6 | local up2 = Residual(256,256)(up1) 7 | local up4 = Residual(256,numOut)(up2) 8 | 9 | -- Lower branch 10 | local pool = nnlib.SpatialMaxPooling(2,2,2,2)(inp) 11 | local low1 = Residual(numIn,256)(pool) 12 | local low2 = Residual(256,256)(low1) 13 | local low5 = Residual(256,256)(low2) 14 | local low6 15 | if n > 1 then 16 | low6 = hourglass(n-1,256,numOut,low5) 17 | else 18 | low6 = Residual(256,numOut)(low5) 19 | end 20 | local low7 = Residual(numOut,numOut)(low6) 21 | local up5 = nn.SpatialUpSamplingNearest(2)(low7) 22 | 23 | -- Bring two branches together 24 | return nn.CAddTable()({up4,up5}) 25 | end 26 | 27 | local function lin(numIn,numOut,inp) 28 | -- Apply 1x1 convolution, no stride, no padding 29 | local l_ = nnlib.SpatialConvolution(numIn,numOut,1,1,1,1,0,0)(inp) 30 | return nnlib.ReLU(true)(nn.SpatialBatchNormalization(numOut)(l_)) 31 | end 32 | 33 | function createModel() 34 | 35 | local inp = nn.Identity()() 36 | 37 | -- Initial processing of the image 38 | local cnv1_ = nnlib.SpatialConvolution(3,64,7,7,2,2,3,3)(inp) -- 128 39 | local cnv1 = nnlib.ReLU(true)(nn.SpatialBatchNormalization(64)(cnv1_)) 40 | local r1 = Residual(64,128)(cnv1) 41 | local pool = nnlib.SpatialMaxPooling(2,2,2,2)(r1) -- 64 42 | local r4 = Residual(128,128)(pool) 43 | local r5 = Residual(128,128)(r4) 44 | local r6 = Residual(128,256)(r5) 45 | 46 | -- First hourglass 47 | local hg1 = hourglass(4,256,512,r6) 48 | 49 | -- Linear layers to produce first set of predictions 50 | local l1 = lin(512,512,hg1) 51 | local l2 = lin(512,256,l1) 52 | 53 | -- First predicted heatmaps 54 | local out1 = nnlib.SpatialConvolution(256,outputDim[1][1],1,1,1,1,0,0)(l2) 55 | local out1_ = nnlib.SpatialConvolution(outputDim[1][1],256+128,1,1,1,1,0,0)(out1) 56 | 57 | -- Concatenate with previous linear features 58 | local cat1 = nn.JoinTable(2)({l2,pool}) 59 | local cat1_ = nnlib.SpatialConvolution(256+128,256+128,1,1,1,1,0,0)(cat1) 60 | local int1 = nn.CAddTable()({cat1_,out1_}) 61 | 62 | -- Second hourglass 63 | local hg2 = hourglass(4,256+128,512,int1) 64 | 65 | -- Linear layers to produce predictions again 66 | local l3 = lin(512,512,hg2) 67 | local l4 = lin(512,512,l3) 68 | 69 | -- Output heatmaps 70 | local out2 = nnlib.SpatialConvolution(512,outputDim[2][1],1,1,1,1,0,0)(l4) 71 | 72 | -- Final model 73 | local model = nn.gModule({inp}, {out1,out2}) 74 | 75 | return model 76 | 77 | end 78 | -------------------------------------------------------------------------------- /ssr/composeShape.m: -------------------------------------------------------------------------------- 1 | function S = composeShape(B,C) 2 | 3 | if size(C,2) ~= size(B,1)/3 4 | C = C'; 5 | end 6 | 7 | f = size(C,1); 8 | p = size(B,2); 9 | k = size(B,1)/3; 10 | 11 | B = reshape(B',3*p,k); 12 | S = B*C'; 13 | S = reshape(S,p,3*f)'; -------------------------------------------------------------------------------- /ssr/estimateC.m: -------------------------------------------------------------------------------- 1 | function C = estimateC(W,R,B,C,lam,tol) 2 | 3 | % INPUT: 4 | % W: 2-by-P matrix 5 | % R: 2-by-3 matrix 6 | % B: 3K-by-P matrx 7 | % C: 1-by-K vector 8 | 9 | % This function estimates c by minimizing 10 | % f(C) + lam*r(C), where 11 | % f(C) = 0.5 * norm(W-R*S,'fro')^2 where S = \sum_i C_i*B_i 12 | % r(C) = \|C\|_1 13 | % It implements proximal gradient + nesterov 14 | 15 | P = size(W,2); 16 | K = size(B,1)/3; 17 | 18 | C = C'; % transpose to be a column vector 19 | C0 = C; % C0: the previous estimate 20 | t = 1; % auxiliary variable for nesterov 21 | t0 = 1; % auxiliary variable for nesterov 22 | fvalue = inf; 23 | 24 | % next we work on the linear system y = X*C 25 | y = W(:); % vectorized W 26 | X = zeros(2*P,K); % each column is a rotated Bk 27 | for k = 1:K 28 | RBk = R*B(3*k-2:3*k,:); 29 | X(:,k) = RBk(:); 30 | end 31 | 32 | if lam == 0 33 | C = X\y; 34 | C = C'; 35 | return 36 | end 37 | 38 | % mu is set as the 2-norm of the Hessian of f(C) 39 | mu = norm(X'*X); 40 | 41 | for iter = 1:1000 42 | 43 | % Z is an auxiliary variable in nesterov method 44 | Z = C + (t0-1)/t*(C-C0); 45 | 46 | % gradient descent 47 | Z = Z + X'*(y-X*Z)/mu; 48 | 49 | % nonegative thresholding 50 | % Z = Z - lam/mu; 51 | % Z = max(Z,0); 52 | 53 | % soft thresholding 54 | Z = sign(Z).*max(abs(Z)-lam/mu,0); 55 | 56 | % update C 57 | C0 = C; 58 | C = Z; 59 | 60 | % update t 61 | t0 = t; 62 | t = (1+sqrt(1+4*t^2))/2; 63 | 64 | % function value 65 | fvalue0 = fvalue; 66 | fvalue = 0.5 * norm(y-X*C,'fro')^2 + lam*sum(abs(C)); 67 | if fvalue > fvalue0 68 | t0 = 1; % APG with restart 69 | t = 1; 70 | end 71 | 72 | % check convergence 73 | RelChg = norm(C-C0,'fro')/(norm(C0,'fro')+eps) ; 74 | % fprintf('Iter %d: FunVal = %f, RelChg = %f\n',iter,fvalue,RelChg); 75 | if RelChg < tol 76 | break 77 | end 78 | 79 | end 80 | 81 | C = C'; % transpose back to be a row vector 82 | -------------------------------------------------------------------------------- /ssr/estimateR_manopt.m: -------------------------------------------------------------------------------- 1 | function R = estimateR_manopt(S,W,R0) 2 | 3 | A = S'; 4 | B = W'; 5 | X0 = R0(1:2,:)'; 6 | 7 | warning('off', 'manopt:getHessian:approx'); 8 | 9 | [m,n,N] = size(A); 10 | p = size(B,2); 11 | 12 | At = zeros([n,m,N]); 13 | for i=1:N 14 | At(:,:,i) = A(:,:,i)'; 15 | end 16 | 17 | 18 | manifold = stiefelfactory(n,p, N); 19 | problem.M = manifold; 20 | 21 | function [f, store] = cost(X, store) 22 | if ~isfield(store, 'E') 23 | store.E = multiprod(A,X) - B; 24 | end 25 | E = store.E; 26 | f = (E(:)'*E(:))/(2*N); 27 | end 28 | 29 | % Riemannian gradient of the cost function. 30 | function [g, store] = grad(X, store) 31 | 32 | if ~isfield(store, 'E') 33 | [~, store] = cost(X, store); 34 | end 35 | E = store.E; 36 | % Compute the Euclidean gradient of the cost wrt the rotations R 37 | % and wrt the cloud A, 38 | egrad = multiprod(At/N,E); 39 | % then transform this Euclidean gradient into the Riemannian 40 | % gradient. 41 | g = manifold.egrad2rgrad(X, egrad); 42 | store.egrad = egrad; 43 | end 44 | 45 | 46 | % Setup the problem structure with manifold M and cost+grad functions. 47 | 48 | problem.cost = @cost; 49 | problem.grad = @grad; 50 | 51 | options.verbosity = 0; 52 | options.tolgradnorm = 1e-3; 53 | options.maxiter = 100; 54 | X = trustregions(problem,X0,options); 55 | 56 | R = X'; 57 | 58 | end -------------------------------------------------------------------------------- /ssr/estimateR_proj.m: -------------------------------------------------------------------------------- 1 | function R = estimateR_proj(S,W) 2 | 3 | R = W/S; 4 | [U,~,V] = svd(R,'econ'); 5 | R = U*V'; 6 | 7 | -------------------------------------------------------------------------------- /ssr/learnPoseDict.m: -------------------------------------------------------------------------------- 1 | function [B,mu,ERR,SP] = learnPoseDict(S_train,skel,K,lam) 2 | 3 | % Input: 4 | % K: size of dictionary 5 | % lam: regularization weight 6 | 7 | %% normalization and alignment 8 | S_train = normalizeS(S_train); 9 | S_train = alignHuman(S_train,skel.torso); 10 | [F,P] = size(S_train); 11 | F = F/3; 12 | 13 | %% run dictionary learning 14 | Y = reshape(S_train',3*P,F); 15 | [D,X] = nnscDL(Y,K,lam); 16 | 17 | %% calculate reconstruction error 18 | S_rec = reshape(D*X,P,3*F)'; 19 | for i=1:F 20 | x = lsqnonneg(D(:,X(:,i)>0),Y(:,i)); 21 | S_rec(3*i-2:3*i,:) = reshape(D(:,X(:,i)>0)*x,P,3)'; 22 | err(i) = sum(sqrt(sum((S_train(3*i-2:3*i,:)-S_rec(3*i-2:3*i,:)).^2)))/P; 23 | sp(i) = sum(x>0); 24 | end 25 | ERR = mean(err); % reconstruction error 26 | SP = mean(sp); % average sparsity (tune lam to change sparsity, sp < 10 is recommended) 27 | 28 | %% output dictionary 29 | B = reshape(D,P,3*size(D,2))'; 30 | mu = meanShape(S_train); 31 | 32 | fprintf('Dictionary learning is done, \n reconstr. err. = %f, average sparsity = %f \n',ERR,SP); -------------------------------------------------------------------------------- /ssr/nnscDL.m: -------------------------------------------------------------------------------- 1 | function [D,X] = nnscDL(Y,K,lam) 2 | 3 | % This function implements dictionary learning with nonnegative sparse 4 | % coding: 5 | % min_{D,X} 1/2||Y-DX||^2 + lam ||X||_1, X > 0 6 | 7 | % INPUT: 8 | % Y: training data (each column vector is a sample) 9 | % K: dictionary size 10 | % lam: regularization parameter 11 | 12 | % OUTPUT: 13 | % D: dictionary 14 | % X: sparse codes for training data 15 | 16 | N = size(Y,2); 17 | 18 | % Initializing D by uniformly sampling 19 | % Other initialization scheme could be used 20 | D = Y(:,round(linspace(1,N,K))); 21 | nrm0 = mean(sqrt(sum(D.^2))); 22 | 23 | % Initializing X 24 | X = pinv(D)*Y; 25 | X(X(:)<0) = 0; 26 | Xp = X; 27 | 28 | 29 | for iter = 1:10000 30 | 31 | % Update X by proximal gradient 32 | mu = norm(D'*D); 33 | for i = 1:500 34 | dX = D'*(Y-D*X); 35 | X = X + 1/mu*(dX-lam); 36 | X(X(:)<0) = 0; 37 | if norm(X-Xp,'fro')/norm(Xp,'fro') < 1e-3 38 | break 39 | end 40 | Xp = X; 41 | end 42 | 43 | % Update D 44 | D = D + 1/norm(X*X')*(Y-D*X)*X'; 45 | % D = Y*pinv(X); 46 | for i = 1:size(D,2) 47 | nrm = sqrt(sum(D(:,i).^2)); 48 | if nrm > nrm0 49 | D(:,i) = D(:,i)*nrm0/nrm; 50 | end 51 | end 52 | 53 | % Calculate and print objective 54 | obj(iter) = (0.5*sum(sum((Y-D*X).^2)) + lam*sum(sum(X))); 55 | fprintf('Iter %d, obj %.3f\n', iter, obj(end)); 56 | if iter > 1 && (obj(end-1)-obj(end))/obj(end-1) < 1e-6 57 | break 58 | end 59 | 60 | end 61 | 62 | 63 | -------------------------------------------------------------------------------- /ssr/proj_deformable_approx.m: -------------------------------------------------------------------------------- 1 | % Ref: A. Del Bue, J. Xavier, L. Agapito, and M. Paladini, "Bilinear 2 | % Factorization via Augmented Lagrange Multipliers (BALM)" ECCV 2010. 3 | % 4 | % This program is free software; you can redistribute it and/or 5 | % modify it under the terms of the GNU General Public License 6 | % as published by the Free Software Foundation; version 2, June 1991 7 | % 8 | % USAGE: Y = proj_deformable_approx(X) 9 | % 10 | % This function projects a generic matrix X of size 3*K x 2 where K is the 11 | % number of basis shapes into the matrix Y that satisfy the manifold 12 | % constraints. This projection is an approximation of the projector 13 | % introduced in: M. Paladini, A. Del Bue, S. M. s, M. Dodig, J. Xavier, and 14 | % L. Agapito, "Factorization for Non-Rigid and Articulated Structure using 15 | % Metric Projections" CVPR 2009. Check the BALM paper, Sec 5.1. 16 | % 17 | % INPUT 18 | % 19 | % X: the 3*K x 2 affine matrix 20 | % 21 | % OUTPUT 22 | % 23 | % Y: the 3*K x 2 with manifold constraints 24 | 25 | function [Y,L,Q] = proj_deformable_approx(X) 26 | 27 | if nargin < 1 28 | 29 | Y = 2; % this says on how many columns of M the projection must be done 30 | return 31 | end 32 | 33 | r = size(X,1); 34 | d = r/3; 35 | 36 | A = zeros(3,3); 37 | for i = 1:d 38 | Ai = X((i-1)*3+1:i*3,:); 39 | A = A + Ai*Ai'; 40 | end; 41 | 42 | [U,S,V] = svd(A); 43 | 44 | Q = U(:,1:2); 45 | 46 | G = zeros(2,2); 47 | for i = 1:d 48 | Ai = X((i-1)*3+1:i*3,:); 49 | Ti = Q'*Ai; 50 | gi = [ trace(Ti) ; Ti(2,1)-Ti(1,2) ]; 51 | G = G + gi*gi'; 52 | end; 53 | 54 | [U1,S1,V1] = svd(G); 55 | 56 | G = zeros(2,2); 57 | for i = 1:d 58 | Ai = X((i-1)*3+1:i*3,:); 59 | Ti = Q'*Ai; 60 | gi = [ Ti(1,1)-Ti(2,2) ; Ti(1,2)+Ti(2,1) ]; 61 | G = G + gi*gi'; 62 | end; 63 | 64 | [U2,S2,V2] = svd(G); 65 | 66 | if S1(1,1) > S2(1,1) 67 | u = U1(:,1); 68 | R = [ u(1) -u(2) ; u(2) u(1) ]; 69 | else 70 | u = U2(:,1); 71 | R = [ u(1) u(2) ; u(2) -u(1) ]; 72 | end; 73 | 74 | Q = Q*R; 75 | 76 | Y = []; 77 | L = []; 78 | for i = 1:d 79 | Ai = X((i-1)*3+1:i*3,:); 80 | ti = 0.5*trace(Q'*Ai); 81 | % if i == 1 && ti < 0 82 | % ti = -ti; 83 | % Q = -Q; 84 | % end 85 | L = [ L ; ti]; 86 | Y = [ Y ; ti*Q ]; 87 | end; -------------------------------------------------------------------------------- /ssr/prox_2norm.m: -------------------------------------------------------------------------------- 1 | function [X,normX] = prox_2norm(Z,lam) 2 | 3 | [U,W,V] = svd(Z,'econ'); 4 | w = diag(W); 5 | w = prox_inf(w,lam); 6 | X = U*diag(w)*V'; 7 | normX = w(1); 8 | 9 | end -------------------------------------------------------------------------------- /ssr/ssr2D3D_alm.m: -------------------------------------------------------------------------------- 1 | function [S,info] = ssr2D3D_alm(W,B,lam,beta,varargin) 2 | 3 | tol = 1e-3; 4 | refine = false; 5 | verb = true; 6 | if nargin < 4 7 | beta = inf; 8 | end 9 | 10 | ivargin = 1; 11 | while ivargin <= length(varargin) 12 | switch lower(varargin{ivargin}) 13 | case 'tol' 14 | ivargin = ivargin + 1; 15 | tol = varargin{ivargin}; 16 | case 'refine' 17 | ivargin = ivargin + 1; 18 | refine = varargin{ivargin}; 19 | case 'verb' 20 | ivargin = ivargin + 1; 21 | verb = varargin{ivargin}; 22 | otherwise 23 | fprintf('Unknown option ''%s'' is ignored !\n',varargin{ivargin}); 24 | end 25 | ivargin = ivargin + 1; 26 | end 27 | 28 | % centralize basis 29 | B = bsxfun(@minus,B,mean(B,2)); 30 | 31 | % data size 32 | [k,p] = size(B); 33 | k = k/3; 34 | 35 | % initialization 36 | M = zeros(2,3*k); 37 | C = zeros(1,k); % norm of each Xi 38 | E = zeros(size(W)); 39 | T = mean(W,2); 40 | % auxiliary variables for ADMM 41 | Z = M; 42 | Y = M; 43 | mu = 1/mean(abs(W(:))); 44 | % pre-computing 45 | BBt = B*B'; 46 | 47 | % flagOD detection? 48 | if beta > max(abs(W(:))) % too large 49 | flagOD = false; 50 | else 51 | flagOD = true; 52 | end 53 | 54 | t0 = tic; 55 | 56 | for iter = 1:1000 57 | 58 | % update motion matrix Z 59 | Z0 = Z; 60 | Z = ((W-E-T*ones(1,p))*B'+mu*M+Y)/(BBt+mu*eye(3*k)); 61 | 62 | % update motion matrix M 63 | Q = Z - Y/mu; 64 | for i = 1:k 65 | [M(:,3*i-2:3*i),C(i)] = prox_2norm(Q(:,3*i-2:3*i),lam/mu); 66 | end 67 | 68 | if flagOD 69 | 70 | % update flagOD term 71 | E = W - Z*B - T*ones(1,p); 72 | E = sign(E).*max(abs(E)-beta,0); 73 | 74 | % update translation 75 | T = mean(W-Z*B-E,2); 76 | 77 | end 78 | 79 | % update dual variable 80 | Y = Y + mu*(M-Z); 81 | 82 | PrimRes = norm(M-Z,'fro')/norm(Z0,'fro'); 83 | DualRes = mu*norm(Z-Z0,'fro')/norm(Z0,'fro'); 84 | 85 | % show info 86 | if verb && mod(iter,10) == 0 87 | fprintf('Iter %d: PrimRes = %f, DualRes = %f, mu = %f\n',... 88 | iter,PrimRes,DualRes,mu); 89 | end 90 | 91 | % Convergent? 92 | if PrimRes < tol && DualRes < tol 93 | break 94 | else 95 | if PrimRes>10*DualRes 96 | mu = 2*mu; 97 | elseif DualRes>10*PrimRes 98 | mu = mu/2; 99 | else 100 | end 101 | end 102 | 103 | end 104 | 105 | info.time = toc(t0); 106 | 107 | if refine 108 | [R,C] = syncRot(M); 109 | S = R*composeShape(B,C); 110 | [S,info1] = ssr2D3D_alt(W,B,lam,beta,'S0',R'*S,'R0',R,'E0',E,... 111 | 'method','manopt','verb',verb); 112 | info.M = M; 113 | info.R = info1.R; 114 | info.C = info1.C; 115 | info.T = info1.T; 116 | info.E = info1.E; 117 | info.fval = info1.fval; 118 | info.timeAlt = info1.time; 119 | else 120 | R = zeros(3,3*k); 121 | C(C<1e-6) = 0; 122 | for i = find(C>0) 123 | R(1:2,3*i-2:3*i) = M(:,3*i-2:3*i)/C(i); 124 | R(3,3*i-2:3*i) = cross(R(1,3*i-2:3*i),R(2,3*i-2:3*i)); 125 | end 126 | S = R*kron(diag(C),eye(3))*B; 127 | info.M = M; 128 | info.R = R; 129 | info.C = C; 130 | info.T = T; 131 | info.E = E; 132 | info.fval = 0; 133 | end 134 | 135 | end 136 | 137 | function [X,normX] = prox_2norm(Z,lam) 138 | % X is a 3-by-2 matrix 139 | [U,W,V] = svd(Z,'econ'); 140 | w = diag(W); 141 | if sum(w) <= lam 142 | w = [0,0]; 143 | elseif w(1)-w(2) <= lam 144 | w(1) = (sum(w)-lam)/2; 145 | w(2) = w(1); 146 | else 147 | w(1) = w(1) - lam; 148 | w(2) = w(2); 149 | end 150 | X = U*diag(w)*V'; 151 | normX = w(1); 152 | end -------------------------------------------------------------------------------- /ssr/ssr2D3D_alt.m: -------------------------------------------------------------------------------- 1 | function [S,info] = ssr2D3D_alt(W,B,lam,beta,varargin) 2 | 3 | if nargin < 4 4 | beta = inf; 5 | end 6 | 7 | % centralize data 8 | B = bsxfun(@minus,B,mean(B,2)); 9 | 10 | % data size 11 | k = size(B,1)/3; 12 | p = size(B,2); 13 | 14 | % initialize 15 | C = zeros(1,k); 16 | S = meanShape(B); 17 | R = eye(3); 18 | E = zeros(size(W)); 19 | T = mean(W,2); 20 | tol = 1e-4; 21 | method = 'manopt'; 22 | verb = true; 23 | 24 | ivargin = 1; 25 | while ivargin <= length(varargin) 26 | switch lower(varargin{ivargin}) 27 | case 'tol' 28 | ivargin = ivargin + 1; 29 | tol = varargin{ivargin}; 30 | case 's0' 31 | ivargin = ivargin + 1; 32 | S = varargin{ivargin}; 33 | case 'r0' 34 | ivargin = ivargin + 1; 35 | R = varargin{ivargin}; 36 | case 'e0' 37 | ivargin = ivargin + 1; 38 | E = varargin{ivargin}; 39 | case 'method' 40 | ivargin = ivargin + 1; 41 | method = varargin{ivargin}; 42 | case 'verb' 43 | ivargin = ivargin + 1; 44 | verb = varargin{ivargin}; 45 | otherwise 46 | fprintf('Unknown option ''%s'' is ignored !\n',varargin{ivargin}); 47 | end 48 | ivargin = ivargin + 1; 49 | end 50 | 51 | % outlier detection? 52 | if beta > max(abs(W(:))) % too large 53 | flagOD = false; 54 | else 55 | flagOD = true; 56 | end 57 | 58 | R = R(1:2,:); 59 | 60 | fval = inf; 61 | t0 = tic; 62 | for iter = 1:1000 63 | 64 | % update rotation 65 | W2fit = W - E - T*ones(1,p); 66 | switch method 67 | case 'proj' % greedy projection 68 | R = estimateR_proj(S,W2fit); 69 | case 'manopt' % manifold optimizaiton 70 | R = estimateR_manopt(S,W2fit,R); 71 | otherwise 72 | error('Invalid input for option:method!'); 73 | end 74 | 75 | % update shape 76 | C = estimateC(W2fit,R,B,C,lam,1e-4); 77 | S = kron(C,eye(3))*B; 78 | 79 | if flagOD 80 | 81 | % update outlier 82 | E = W - R*S - T*ones(1,p); 83 | E = sign(E).*max(abs(E)-beta,0); 84 | 85 | % update translation 86 | T = mean(W-R*S-E,2); 87 | 88 | % evaluate obj. func. 89 | fvaltm1 = fval; 90 | fval = 0.5*norm(W-R*S-E-T*ones(1,p),'fro')^2 + lam*sum(abs(C(:))) + beta*sum(abs(E(:))); 91 | 92 | else 93 | 94 | fvaltm1 = fval; 95 | fval = 0.5*norm(W-R*S-E-T*ones(1,p),'fro')^2 + lam*sum(abs(C(:))); 96 | 97 | end 98 | 99 | % show info 100 | if verb 101 | fprintf('Iter: %d, fval = %f\n',iter,fval); 102 | end 103 | 104 | % check convergence 105 | if abs(fval-fvaltm1)/fvaltm1 < tol 106 | break 107 | end 108 | 109 | end 110 | 111 | R(3,:) = cross(R(1,:),R(2,:)); 112 | 113 | % output 114 | S = R*S; 115 | info.R = R; 116 | info.C = C; 117 | info.T = T; 118 | info.E = E; 119 | info.fval = fval; 120 | info.time = toc(t0); 121 | -------------------------------------------------------------------------------- /ssr/ssr2D3D_wrapper.m: -------------------------------------------------------------------------------- 1 | function [S,info] = ssr2D3D_wrapper(W,B,method,varargin) 2 | 3 | lam = 1; 4 | beta = 1; 5 | verb = false; 6 | 7 | ivargin = 1; 8 | while ivargin <= length(varargin) 9 | switch lower(varargin{ivargin}) 10 | case 'lam' 11 | ivargin = ivargin + 1; 12 | lam = varargin{ivargin}; 13 | case 'beta' 14 | ivargin = ivargin + 1; 15 | beta = varargin{ivargin}; 16 | case 'verb' 17 | ivargin = ivargin + 1; 18 | verb = varargin{ivargin}; 19 | otherwise 20 | fprintf('Unknown option ''%s'' is ignored !\n',varargin{ivargin}); 21 | end 22 | ivargin = ivargin + 1; 23 | end 24 | 25 | % run solvers 26 | switch lower(method) 27 | case 'convex' 28 | [S,info] = ssr2D3D_alm(W,B,lam,inf,'verb',verb); 29 | case 'convex+refine' 30 | [S,info] = ssr2D3D_alm(W,B,lam,inf,'refine',true,'verb',verb); 31 | case 'convex+robust' 32 | [S,info] = ssr2D3D_alm(W,B,lam,beta,'verb',verb); 33 | case 'convex+robust+refine' 34 | [S,info] = ssr2D3D_alm(W,B,lam,beta,'refine',true,'verb',verb); 35 | case 'altern' 36 | [S,info] = ssr2D3D_alt(W,B,lam,inf,'method','proj','verb',verb); 37 | case 'altern+robust' 38 | [S,info] = ssr2D3D_alt(W,B,lam,beta,'method','proj','verb',verb); 39 | otherwise 40 | error('Undefined method!'); 41 | end 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /ssr/syncRot.m: -------------------------------------------------------------------------------- 1 | function [R,C] = syncRot(T) 2 | 3 | [~,L,Q] = proj_deformable_approx(T'); 4 | s = sign(L(find(abs(L)==max(abs(L)),1))); 5 | C = s*L'; 6 | R = s*Q'; 7 | R(3,:) = cross(R(1,:),R(2,:)); 8 | 9 | % [R,C] = projectNonrigid(T); 10 | % R(3,:) = cross(R(1,:),R(2,:)); 11 | -------------------------------------------------------------------------------- /startup.m: -------------------------------------------------------------------------------- 1 | addpath em 2 | addpath general 3 | addpath ssr 4 | addpath utils 5 | addpath(genpath('manopt')); -------------------------------------------------------------------------------- /utils/getMPIIdict.m: -------------------------------------------------------------------------------- 1 | function mpiidict = getMPIIdict(dict,source) 2 | 3 | % create dictionary for mpii human pose dataset from other 3D datasets 4 | 5 | switch lower(source) 6 | case 'hm36m' 7 | ind_new = 1:16; 8 | ind_old = [7,6,5,2,3,4,1,9,10,11,17,16,15,12,13,14]; 9 | mpiidict.B(:,ind_new) = dict.B(:,ind_old); 10 | mpiidict.mu(:,ind_new) = dict.mu(:,ind_old); 11 | case 'cmu' 12 | ind_new = [1:8,10:16]; 13 | ind_old = [7,6,5,2,3,4,1,8,9,15,14,13,10,11,12]; 14 | mpiidict.B(:,ind_new) = dict.B(:,ind_old); 15 | mpiidict.mu(:,ind_new) = dict.mu(:,ind_old); 16 | % interpolate the location of neck = 1/3*head + 2/3*thorax 17 | mpiidict.B(:,9) = mpiidict.B(:,8)*2/3 + mpiidict.B(:,10)*1/3; 18 | mpiidict.mu(:,9) = mpiidict.mu(:,8)*2/3 + mpiidict.mu(:,10)*1/3; 19 | otherwise 20 | error('Unknown source of 3D data!'); 21 | end 22 | 23 | mpiidict.skel.tree(1).name = ['RAnk']; 24 | mpiidict.skel.tree(2).name = ['RKne']; 25 | mpiidict.skel.tree(3).name = ['RHip']; 26 | mpiidict.skel.tree(4).name = ['LHip']; 27 | mpiidict.skel.tree(5).name = ['LKne']; 28 | mpiidict.skel.tree(6).name = ['LAnk']; 29 | mpiidict.skel.tree(7).name = ['Pelv']; 30 | mpiidict.skel.tree(8).name = ['Thrx']; 31 | mpiidict.skel.tree(9).name = ['Neck']; 32 | mpiidict.skel.tree(10).name = ['Head']; 33 | mpiidict.skel.tree(11).name = ['RWri']; 34 | mpiidict.skel.tree(12).name = ['RElb']; 35 | mpiidict.skel.tree(13).name = ['RSho']; 36 | mpiidict.skel.tree(14).name = ['LSho']; 37 | mpiidict.skel.tree(15).name = ['LElb']; 38 | mpiidict.skel.tree(16).name = ['LWri']; 39 | 40 | mpiidict.skel.tree(1).children = []; 41 | mpiidict.skel.tree(2).children = [1]; 42 | mpiidict.skel.tree(3).children = [2]; 43 | mpiidict.skel.tree(4).children = [5]; 44 | mpiidict.skel.tree(5).children = [6]; 45 | mpiidict.skel.tree(6).children = []; 46 | mpiidict.skel.tree(7).children = [3,4,8]; 47 | mpiidict.skel.tree(8).children = [9,13,14]; 48 | mpiidict.skel.tree(9).children = [10]; 49 | mpiidict.skel.tree(10).children = []; 50 | mpiidict.skel.tree(11).children = []; 51 | mpiidict.skel.tree(12).children = [11]; 52 | mpiidict.skel.tree(13).children = [12]; 53 | mpiidict.skel.tree(14).children = [15]; 54 | mpiidict.skel.tree(15).children = [16]; 55 | mpiidict.skel.tree(16).children = []; 56 | 57 | mpiidict.skel.tree(1).color = ['g']; 58 | mpiidict.skel.tree(2).color = ['g']; 59 | mpiidict.skel.tree(3).color = ['g']; 60 | mpiidict.skel.tree(4).color = ['r']; 61 | mpiidict.skel.tree(5).color = ['r']; 62 | mpiidict.skel.tree(6).color = ['r']; 63 | mpiidict.skel.tree(7).color = ['b']; 64 | mpiidict.skel.tree(8).color = ['b']; 65 | mpiidict.skel.tree(9).color = ['b']; 66 | mpiidict.skel.tree(10).color = ['b']; 67 | mpiidict.skel.tree(11).color = ['g']; 68 | mpiidict.skel.tree(12).color = ['g']; 69 | mpiidict.skel.tree(13).color = ['g']; 70 | mpiidict.skel.tree(14).color = ['r']; 71 | mpiidict.skel.tree(15).color = ['r']; 72 | mpiidict.skel.tree(16).color = ['r']; 73 | 74 | mpiidict.skel.torso = [3,4,7,8,13,14]; 75 | -------------------------------------------------------------------------------- /utils/transformMPII.m: -------------------------------------------------------------------------------- 1 | function new_pt = transformMPII(pt,center,scale,res,invert) 2 | 3 | t = get_transform(center,scale,res); 4 | if invert 5 | t = inv(t); 6 | end 7 | 8 | new_pt = [pt(1,:);pt(2,:)-0.5;ones(1,size(pt,2))]; 9 | new_pt = t*new_pt; 10 | new_pt = new_pt(1:2,:); 11 | 12 | end 13 | 14 | function t = get_transform(center,scale,res) 15 | h = 200*scale; 16 | t = eye(3,3); 17 | t(1,1) = res(2)/h; 18 | t(2,2) = res(1)/h; 19 | t(1,3) = res(2)*(-center(1)/h + 0.5); 20 | t(2,3) = res(1)*(-center(2)/h + 0.5); 21 | t(3,3) = 1; 22 | end 23 | 24 | --------------------------------------------------------------------------------