Dem Bones  1.2.0
Skinning Decomposition Library
ConvexLS.h
Go to the documentation of this file.
1 // Dem Bones - Skinning Decomposition Library //
3 // Copyright (c) 2019, Electronic Arts. All rights reserved. //
5 
6 
7 
8 #ifndef DEM_BONES_CONVEX_LS
9 #define DEM_BONES_CONVEX_LS
10 
11 #include <Eigen/Dense>
12 #include <Eigen/StdVector>
13 #include "Indexing.h"
14 
15 namespace Dem
16 {
17 
30 template<class _Scalar>
31 class ConvexLS {
32 public:
33  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
34  using MatrixX=Eigen::Matrix<_Scalar, Eigen::Dynamic, Eigen::Dynamic>;
35  using VectorX=Eigen::Matrix<_Scalar, Eigen::Dynamic, 1>;
36 
40  ConvexLS(int maxSize=1) {
41  q2.resize(0);
42  init(maxSize);
43  }
44 
48  void init(int maxSize) {
49  int curN=(int)q2.size()+1;
50  if (curN<maxSize) {
51  q2.resize(maxSize-1);
52  #pragma omp parallel for
53  for (int n=curN-1; n<maxSize-1; n++)
54  q2[n]=MatrixX(VectorX::Constant(n+2, _Scalar(1)).householderQr().householderQ()).rightCols(n+1);
55  }
56  }
57 
65  void solve(const MatrixX& aTa, const VectorX& aTb, VectorX& x, bool affine, bool warmStart=false) {
66  int n=int(aTa.cols());
67 
68  if (!warmStart) x=VectorX::Constant(n, _Scalar(1)/n);
69 
70  Eigen::ArrayXi idx(n);
71  int np=0;
72  for (int i=0; i<n; i++)
73  if (x(i)>0) idx[np++]=i; else idx[n-i+np-1]=i;
74 
75  VectorX p;
76 
77  for (int rep=0; rep<n; rep++) {
78  solveP(aTa, aTb, x, idx, np, affine, p);
79 
80  if ((indexing_vector(x, idx.head(np))+indexing_vector(p, idx.head(np))).minCoeff()>=0) {
81  x+=p;
82  if (np==n) break;
83  Eigen::Index iMax;
84  (indexing_vector(aTb, idx.tail(n-np))-indexing_row(aTa, idx.tail(n-np))*x).maxCoeff(&iMax);
85  std::swap(idx[iMax+np], idx[np]);
86  np++;
87  } else {
88  _Scalar alpha;
89  int iMin=-1;
90  for (int i=0; i<np; i++)
91  if (p(idx[i])<0) {
92  if ((iMin==-1)||(x(idx[i])<-alpha*p(idx[i]))) {
93  alpha=-x(idx[i])/p(idx[i]);
94  iMin=i;
95  }
96  }
97  x+=alpha*p;
98  _Scalar eps=std::abs(x(idx[iMin]));
99  x(idx[iMin])=0;
100  for (int i=0; i<np; i++)
101  if (x(idx[i])<=eps) std::swap(idx[i--], idx[--np]);
102  }
103  if (affine) x/=x.sum();
104  }
105  }
106 
107 private:
109  std::vector<MatrixX, Eigen::aligned_allocator<MatrixX>> q2;
110 
120  void solveP(const MatrixX& aTa, const VectorX& aTb, const VectorX& x, const Eigen::ArrayXi& idx, int np, bool zeroSum, VectorX& p) {
121  VectorX z;
122  p.setZero(aTb.size());
123  if (!zeroSum) {
124  z= indexing_row_col(aTa, idx.head(np), idx.head(np)).colPivHouseholderQr().solve( //A
125  indexing_vector(aTb, idx.head(np))-indexing_row(aTa, idx.head(np))*x); //b
126  for (int ip=0; ip<np; ip++) p(idx[ip])=z(ip);
127  } else if (np>1) {
128  z=q2[np-2]*( //Re-project
129  (q2[np-2].transpose()*indexing_row_col(aTa, idx.head(np), idx.head(np))*q2[np-2]).colPivHouseholderQr().solve( //A
130  q2[np-2].transpose()*(indexing_vector(aTb, idx.head(np))-indexing_row(aTa, idx.head(np))*x) )); //b
131  for (int ip=0; ip<np; ip++) p(idx[ip])=z(ip);
132  }
133  }
134 };
135 
136 }
137 
138 #endif
Dem::indexing_row
Eigen::CwiseNullaryOp< indexing_functor_row< ArgType, RowIndexType >, typename indexing_functor_row< ArgType, RowIndexType >::MatrixType > indexing_row(const Eigen::MatrixBase< ArgType > &arg, const RowIndexType &row_indices)
Definition: Indexing.h:81
Dem::ConvexLS::MatrixX
Eigen::Matrix< _Scalar, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Definition: ConvexLS.h:34
Dem::ConvexLS::ConvexLS
ConvexLS(int maxSize=1)
Definition: ConvexLS.h:40
Dem
Definition: ConvexLS.h:15
Dem::ConvexLS::init
void init(int maxSize)
Definition: ConvexLS.h:48
Dem::indexing_vector
Eigen::CwiseNullaryOp< indexing_functor_vector< ArgType, IndexType >, typename indexing_functor_vector< ArgType, IndexType >::VectorType > indexing_vector(const Eigen::MatrixBase< ArgType > &arg, const IndexType &indices)
Definition: Indexing.h:115
Dem::ConvexLS
Linear least squares solver with non-negativity constraint and optional affinity constraint.
Definition: ConvexLS.h:31
Dem::ConvexLS::VectorX
Eigen::Matrix< _Scalar, Eigen::Dynamic, 1 > VectorX
Definition: ConvexLS.h:35
Dem::ConvexLS::solve
void solve(const MatrixX &aTa, const VectorX &aTb, VectorX &x, bool affine, bool warmStart=false)
Definition: ConvexLS.h:65
Dem::indexing_row_col
Eigen::CwiseNullaryOp< indexing_functor_row_col< ArgType, RowIndexType, ColIndexType >, typename indexing_functor_row_col< ArgType, RowIndexType, ColIndexType >::MatrixType > indexing_row_col(const Eigen::MatrixBase< ArgType > &arg, const RowIndexType &row_indices, const ColIndexType &col_indices)
Definition: Indexing.h:47
Indexing.h