Maniverse 0.2.1__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Maniverse might be problematic. Click here for more details.
- {Maniverse-0.2.1 → Maniverse-0.2.3/Maniverse.egg-info}/PKG-INFO +1 -1
- Maniverse-0.2.3/Maniverse.egg-info/SOURCES.txt +41 -0
- Maniverse-0.2.3/Maniverse.egg-info/top_level.txt +1 -0
- Maniverse-0.2.3/PKG-INFO +8 -0
- Maniverse-0.2.3/pyproject.toml +3 -0
- Maniverse-0.2.3/setup.py +66 -0
- Maniverse-0.2.3/src/Macro.h +19 -0
- Maniverse-0.2.3/src/Manifold/Grassmann.cpp +147 -0
- Maniverse-0.2.3/src/Manifold/Grassmann.h +27 -0
- Maniverse-0.2.3/src/Manifold/Manifold.cpp +220 -0
- Maniverse-0.2.3/src/Manifold/Manifold.h +47 -0
- Maniverse-0.2.3/src/Manifold/Orthogonal.cpp +150 -0
- Maniverse-0.2.3/src/Manifold/Orthogonal.h +23 -0
- Maniverse-0.2.3/src/Manifold/PyManifoldIn.h +5 -0
- Maniverse-0.2.3/src/Manifold/PyManifoldOut.h +5 -0
- Maniverse-0.2.3/src/Manifold/Simplex.cpp +105 -0
- Maniverse-0.2.3/src/Manifold/Simplex.h +24 -0
- Maniverse-0.2.3/src/Manifold/TransRotInvPointCloud.cpp +154 -0
- Maniverse-0.2.3/src/Manifold/TransRotInvPointCloud.h +23 -0
- Maniverse-0.2.3/src/Manifold/makefile +18 -0
- Maniverse-0.2.3/src/Maniverse.egg-info/SOURCES.txt +8 -0
- Maniverse-0.2.3/src/Maniverse.egg-info/top_level.txt +2 -0
- Maniverse-0.2.3/src/Optimizer/HessUpdate.cpp +208 -0
- Maniverse-0.2.3/src/Optimizer/HessUpdate.h +21 -0
- Maniverse-0.2.3/src/Optimizer/PyOptimizerIn.h +3 -0
- Maniverse-0.2.3/src/Optimizer/PyOptimizerOut.h +3 -0
- Maniverse-0.2.3/src/Optimizer/SubSolver.cpp +121 -0
- Maniverse-0.2.3/src/Optimizer/SubSolver.h +16 -0
- Maniverse-0.2.3/src/Optimizer/TrustRegion.cpp +199 -0
- Maniverse-0.2.3/src/Optimizer/TrustRegion.h +33 -0
- Maniverse-0.2.3/src/Optimizer/makefile +12 -0
- Maniverse-0.2.3/src/PyManiverse.cpp +10 -0
- Maniverse-0.2.3/src/makefile +12 -0
- Maniverse-0.2.1/Maniverse.egg-info/SOURCES.txt +0 -8
- Maniverse-0.2.1/setup.py +0 -73
- {Maniverse-0.2.1 → Maniverse-0.2.3}/LICENSE +0 -0
- {Maniverse-0.2.1 → Maniverse-0.2.3}/Maniverse.egg-info/dependency_links.txt +0 -0
- {Maniverse-0.2.1 → Maniverse-0.2.3}/README.md +0 -0
- {Maniverse-0.2.1 → Maniverse-0.2.3}/setup.cfg +0 -0
- {Maniverse-0.2.1 → Maniverse-0.2.3/src}/Maniverse.egg-info/PKG-INFO +0 -0
- /Maniverse-0.2.1/Maniverse.egg-info/top_level.txt → /Maniverse-0.2.3/src/Maniverse.egg-info/dependency_links.txt +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.cfg
|
|
5
|
+
setup.py
|
|
6
|
+
Maniverse.egg-info/PKG-INFO
|
|
7
|
+
Maniverse.egg-info/SOURCES.txt
|
|
8
|
+
Maniverse.egg-info/dependency_links.txt
|
|
9
|
+
Maniverse.egg-info/top_level.txt
|
|
10
|
+
src/Macro.h
|
|
11
|
+
src/Manifold
|
|
12
|
+
src/Maniverse.egg-info
|
|
13
|
+
src/Optimizer
|
|
14
|
+
src/PyManiverse.cpp
|
|
15
|
+
src/makefile
|
|
16
|
+
src/Manifold/Grassmann.cpp
|
|
17
|
+
src/Manifold/Grassmann.h
|
|
18
|
+
src/Manifold/Manifold.cpp
|
|
19
|
+
src/Manifold/Manifold.h
|
|
20
|
+
src/Manifold/Orthogonal.cpp
|
|
21
|
+
src/Manifold/Orthogonal.h
|
|
22
|
+
src/Manifold/PyManifoldIn.h
|
|
23
|
+
src/Manifold/PyManifoldOut.h
|
|
24
|
+
src/Manifold/Simplex.cpp
|
|
25
|
+
src/Manifold/Simplex.h
|
|
26
|
+
src/Manifold/TransRotInvPointCloud.cpp
|
|
27
|
+
src/Manifold/TransRotInvPointCloud.h
|
|
28
|
+
src/Manifold/makefile
|
|
29
|
+
src/Maniverse.egg-info/PKG-INFO
|
|
30
|
+
src/Maniverse.egg-info/SOURCES.txt
|
|
31
|
+
src/Maniverse.egg-info/dependency_links.txt
|
|
32
|
+
src/Maniverse.egg-info/top_level.txt
|
|
33
|
+
src/Optimizer/HessUpdate.cpp
|
|
34
|
+
src/Optimizer/HessUpdate.h
|
|
35
|
+
src/Optimizer/PyOptimizerIn.h
|
|
36
|
+
src/Optimizer/PyOptimizerOut.h
|
|
37
|
+
src/Optimizer/SubSolver.cpp
|
|
38
|
+
src/Optimizer/SubSolver.h
|
|
39
|
+
src/Optimizer/TrustRegion.cpp
|
|
40
|
+
src/Optimizer/TrustRegion.h
|
|
41
|
+
src/Optimizer/makefile
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Maniverse
|
Maniverse-0.2.3/PKG-INFO
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: Maniverse
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Function optimization on manifolds
|
|
5
|
+
Home-page: https://github.com/FreemanTheMaverick/Maniverse.git
|
|
6
|
+
Author: FreemanTheMaverick
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
License-File: LICENSE
|
Maniverse-0.2.3/setup.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import wget
|
|
3
|
+
import tarfile
|
|
4
|
+
import subprocess
|
|
5
|
+
from glob import glob
|
|
6
|
+
from setuptools import setup, find_packages
|
|
7
|
+
from setuptools.command.build import build
|
|
8
|
+
import pybind11
|
|
9
|
+
from pybind11.setup_helpers import Pybind11Extension, ParallelCompile, naive_recompile
|
|
10
|
+
|
|
11
|
+
__version__ = "0.2.3"
|
|
12
|
+
pwd = os.path.dirname(__file__)
|
|
13
|
+
|
|
14
|
+
# Checking dependencies
|
|
15
|
+
PYTHON3 = os.getenv("PYTHON3", default = '')
|
|
16
|
+
print("Looking for Python.h at %s ..." % PYTHON3, end='')
|
|
17
|
+
if os.path.isfile(PYTHON3 + "/Python.h"):
|
|
18
|
+
print("Found!")
|
|
19
|
+
else:
|
|
20
|
+
raise RuntimeError("Python.h does not exist!")
|
|
21
|
+
EIGEN3 = os.getenv("EIGEN3", default = '')
|
|
22
|
+
if len(EIGEN3) > 0:
|
|
23
|
+
print("Looking for Eigen3 at %s ..." % EIGEN3, end='')
|
|
24
|
+
if os.path.exists(EIGEN3 + "/Eigen/") and os.path.exists(EIGEN3 + "/unsupported/") and os.path.isfile(EIGEN3 + "/signature_of_eigen3_matrix_library"):
|
|
25
|
+
print("Found!")
|
|
26
|
+
else:
|
|
27
|
+
raise RuntimeError("Python.h does not exist!")
|
|
28
|
+
else:
|
|
29
|
+
print("The environment variable $EIGEN3 is not set. -> Downloading ...")
|
|
30
|
+
filename = wget.download("https://gitlab.com/libeigen/eigen/-/archive/3.4-rc1/eigen-3.4-rc1.tar.gz", bar = None)
|
|
31
|
+
with tarfile.open(filename) as tar:
|
|
32
|
+
tar.extractall(path = pwd) # Directory: eigen-3.4-rc1
|
|
33
|
+
EIGEN3 = pwd + "/eigen-3.4-rc1/"
|
|
34
|
+
print("EIGEN3 is %s." % EIGEN3)
|
|
35
|
+
PYBIND11 = pybind11.get_include()
|
|
36
|
+
print("PYBIND11 is %s." % PYBIND11)
|
|
37
|
+
|
|
38
|
+
BASE_DIR = os.path.dirname(__file__)
|
|
39
|
+
os.chdir(BASE_DIR)
|
|
40
|
+
|
|
41
|
+
ParallelCompile(
|
|
42
|
+
"NPY_NUM_BUILD_JOBS",
|
|
43
|
+
needs_recompile = naive_recompile,
|
|
44
|
+
default = 4
|
|
45
|
+
).install()
|
|
46
|
+
|
|
47
|
+
ext_modules = [ Pybind11Extension(
|
|
48
|
+
"Maniverse",
|
|
49
|
+
sorted(glob("src/*")) + sorted(glob("src/*/*")),
|
|
50
|
+
define_macros = ["__PYTHON__", "EIGEN_INITIALIZE_MATRICES_BY_ZERO"],
|
|
51
|
+
undef_macros = ["DEBUG"],
|
|
52
|
+
include_dirs = [PYTHON3, EIGEN3, PYBIND11],
|
|
53
|
+
extra_compile_args = ["-O3"],
|
|
54
|
+
cxx_std = 17,
|
|
55
|
+
language = "c++"
|
|
56
|
+
)]
|
|
57
|
+
|
|
58
|
+
setup(
|
|
59
|
+
name = "Maniverse",
|
|
60
|
+
version = __version__,
|
|
61
|
+
author = "FreemanTheMaverick",
|
|
62
|
+
description = "Function optimization on manifolds",
|
|
63
|
+
ext_modules = ext_modules,
|
|
64
|
+
url = "https://github.com/FreemanTheMaverick/Maniverse.git",
|
|
65
|
+
classifiers = ["Programming Language :: Python :: 3"]
|
|
66
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#define EigenArray Eigen::ArrayXd
|
|
2
|
+
#define EigenVector Eigen::VectorXd
|
|
3
|
+
#define EigenDiagonal Eigen::DiagonalMatrix<double, -1, -1>
|
|
4
|
+
#define EigenMatrix Eigen::MatrixXd
|
|
5
|
+
#define EigenZero Eigen::MatrixXd::Zero
|
|
6
|
+
#define EigenOne Eigen::MatrixXd::Identity
|
|
7
|
+
|
|
8
|
+
#define Diag(X) (X).diagonal().asDiagonal()
|
|
9
|
+
#define Dot(X, Y) ( (X).transpose() * (Y) ).trace()
|
|
10
|
+
|
|
11
|
+
#define __Not_Implemented__\
|
|
12
|
+
std::string func_name = __func__;\
|
|
13
|
+
std::string class_name = typeid(*this).name();\
|
|
14
|
+
throw std::runtime_error(func_name + " for " + class_name + " is not implemented!");
|
|
15
|
+
|
|
16
|
+
#define __True_False__(x) ( x ? "True" : "False" )
|
|
17
|
+
|
|
18
|
+
#define __now__ std::chrono::high_resolution_clock::now()
|
|
19
|
+
#define __duration__(start, end) std::chrono::duration<double>(end - start).count()
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#ifdef __PYTHON__
|
|
2
|
+
#include <pybind11/pybind11.h>
|
|
3
|
+
#include <pybind11/stl.h>
|
|
4
|
+
#include <pybind11/eigen.h>
|
|
5
|
+
#include <pybind11/functional.h>
|
|
6
|
+
#endif
|
|
7
|
+
#include <Eigen/Dense>
|
|
8
|
+
#include <unsupported/Eigen/MatrixFunctions>
|
|
9
|
+
#include <cmath>
|
|
10
|
+
#include <functional>
|
|
11
|
+
#include <tuple>
|
|
12
|
+
#include <cassert>
|
|
13
|
+
#include <memory>
|
|
14
|
+
|
|
15
|
+
#include "../Macro.h"
|
|
16
|
+
|
|
17
|
+
#include "Grassmann.h"
|
|
18
|
+
|
|
19
|
+
#include <iostream>
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Grassmann::Grassmann(EigenMatrix p, bool matrix_free): Manifold(p, matrix_free){
|
|
23
|
+
this->Name = "Grassmann";
|
|
24
|
+
this->P.resize(p.rows(), p.cols());
|
|
25
|
+
this->Ge.resize(p.rows(), p.cols());
|
|
26
|
+
this->Gr.resize(p.rows(), p.cols());
|
|
27
|
+
this->P = p;
|
|
28
|
+
Eigen::SelfAdjointEigenSolver<EigenMatrix> eigensolver;
|
|
29
|
+
eigensolver.compute(p);
|
|
30
|
+
const EigenVector eigenvalues = eigensolver.eigenvalues();
|
|
31
|
+
const EigenMatrix eigenvectors = eigensolver.eigenvectors();
|
|
32
|
+
int rank = 0;
|
|
33
|
+
for ( int i = 0; i < p.rows(); i++ )
|
|
34
|
+
if ( eigenvalues(i) > 0.5 ) rank++;
|
|
35
|
+
this->Projector.resize(p.rows(), rank);
|
|
36
|
+
this->Projector = eigenvectors.rightCols(rank);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
int Grassmann::getDimension() const{
|
|
40
|
+
const double rank = this->Projector.cols();
|
|
41
|
+
return rank * ( this->P.rows() - rank );
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
double Grassmann::Inner(EigenMatrix X, EigenMatrix Y) const{
|
|
45
|
+
return Dot(X, Y);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
EigenMatrix Grassmann::Exponential(EigenMatrix X) const{
|
|
49
|
+
const EigenMatrix Xp = X * this->P - this->P * X;
|
|
50
|
+
const EigenMatrix pX = - Xp;
|
|
51
|
+
const EigenMatrix expXp = Xp.exp();
|
|
52
|
+
const EigenMatrix exppX = pX.exp();
|
|
53
|
+
return expXp * this->P * exppX;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
EigenMatrix Grassmann::Logarithm(Manifold& N) const{
|
|
57
|
+
for ( auto& [cached_NP, cached_Log] : this->LogCache )
|
|
58
|
+
if ( N.P.isApprox(cached_NP) ) return cached_Log;
|
|
59
|
+
__Check_Log_Map__
|
|
60
|
+
Grassmann& N_ = dynamic_cast<Grassmann&>(N);
|
|
61
|
+
const EigenMatrix U = this->Projector;
|
|
62
|
+
const EigenMatrix Y = N_.Projector;
|
|
63
|
+
Eigen::JacobiSVD<EigenMatrix> svd;
|
|
64
|
+
svd.compute(Y.transpose() * U, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
|
65
|
+
const EigenMatrix Ystar = Y * svd.matrixU() * svd.matrixV().transpose();
|
|
66
|
+
svd.compute( (EigenOne(U.rows(), U.rows()) - U * U.transpose() ) * Ystar);
|
|
67
|
+
const EigenArray Sigma = svd.singularValues().array().asin();
|
|
68
|
+
EigenMatrix SIGMA = EigenZero(U.rows(), U.cols());
|
|
69
|
+
for ( int i = 0; i < Sigma.size(); i++ ) SIGMA(i, i) = Sigma[i];
|
|
70
|
+
const EigenMatrix Delta = svd.matrixU() * SIGMA * svd.matrixV().transpose();
|
|
71
|
+
const EigenMatrix Log = Delta * U.transpose() + U * Delta.transpose();
|
|
72
|
+
const EigenMatrix result = this->TangentPurification(Log);
|
|
73
|
+
this->LogCache.push_back(std::make_tuple(N_.P, result));
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
EigenMatrix Grassmann::TangentProjection(EigenMatrix X) const{
|
|
78
|
+
// X must be symmetric.
|
|
79
|
+
// https://sites.uclouvain.be/absil/2013.01
|
|
80
|
+
const EigenMatrix adPX = this->P * X - X * this->P;
|
|
81
|
+
return this->P * adPX - adPX * this->P;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
EigenMatrix Grassmann::TangentPurification(EigenMatrix A) const{
|
|
85
|
+
const EigenMatrix symA = 0.5 * ( A + A.transpose() );
|
|
86
|
+
const EigenMatrix pureA = symA - this->P * symA * this->P;
|
|
87
|
+
return 0.5 * ( pureA + pureA.transpose() );
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
EigenMatrix Grassmann::TransportTangent(EigenMatrix X, EigenMatrix Y) const{
|
|
91
|
+
// X - Vector to transport from P
|
|
92
|
+
// Y - Destination on the tangent space of P
|
|
93
|
+
for ( auto& [cached_Y, cached_expdp, cached_exppd]: this->TransportTangentCache )
|
|
94
|
+
if ( Y.isApprox(cached_Y) ) return cached_expdp * X * cached_exppd;
|
|
95
|
+
const EigenMatrix dp = Y * this->P - this->P * Y;
|
|
96
|
+
const EigenMatrix pd = - dp;
|
|
97
|
+
const EigenMatrix expdp = dp.exp();
|
|
98
|
+
const EigenMatrix exppd = pd.exp();
|
|
99
|
+
this->TransportTangentCache.push_back(std::make_tuple(Y, expdp, exppd));
|
|
100
|
+
return expdp * X * exppd;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
EigenMatrix Grassmann::TransportManifold(EigenMatrix X, Manifold& N) const{
|
|
104
|
+
// X - Vector to transport from P
|
|
105
|
+
__Check_Vec_Transport__
|
|
106
|
+
Grassmann& N_ = dynamic_cast<Grassmann&>(N);
|
|
107
|
+
const EigenMatrix Y = this->Logarithm(N_);
|
|
108
|
+
return this->TransportTangent(X, Y);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
void Grassmann::Update(EigenMatrix p, bool purify){
|
|
112
|
+
this->P = p;
|
|
113
|
+
Eigen::SelfAdjointEigenSolver<EigenMatrix> eigensolver;
|
|
114
|
+
eigensolver.compute(p);
|
|
115
|
+
const EigenMatrix eigenvectors = eigensolver.eigenvectors();
|
|
116
|
+
const int ncols = this->Projector.cols();
|
|
117
|
+
this->Projector = eigenvectors.rightCols(ncols);
|
|
118
|
+
this->LogCache.clear();
|
|
119
|
+
this->TransportTangentCache.clear();
|
|
120
|
+
if (purify) this->P = this->Projector * this->Projector.transpose();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
void Grassmann::getGradient(){
|
|
124
|
+
this->Gr = this->TangentPurification(this->TangentProjection(this->Ge));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void Grassmann::getHessian(){
|
|
128
|
+
// https://arxiv.org/abs/0709.2205
|
|
129
|
+
this->Hr = [P = this->P, Ge = this->Ge, He = this->He](EigenMatrix v){
|
|
130
|
+
const EigenMatrix he = He(v);
|
|
131
|
+
const EigenMatrix partA = P * he - he * P;
|
|
132
|
+
const EigenMatrix partB = Ge * v - v * Ge;
|
|
133
|
+
const EigenMatrix sum = partA - partB;
|
|
134
|
+
return (EigenMatrix)(P * sum - sum * P);
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
std::unique_ptr<Manifold> Grassmann::Clone() const{
|
|
139
|
+
return std::make_unique<Grassmann>(*this);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#ifdef __PYTHON__
|
|
143
|
+
void Init_Grassmann(pybind11::module_& m){
|
|
144
|
+
pybind11::class_<Grassmann, Manifold>(m, "Grassmann")
|
|
145
|
+
.def(pybind11::init<EigenMatrix, bool>());
|
|
146
|
+
}
|
|
147
|
+
#endif
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#include "Manifold.h"
|
|
2
|
+
|
|
3
|
+
class Grassmann: public Manifold{ public:
|
|
4
|
+
EigenMatrix Projector;
|
|
5
|
+
mutable std::vector<std::tuple<EigenMatrix, EigenMatrix>> LogCache;
|
|
6
|
+
mutable std::vector<std::tuple<EigenMatrix, EigenMatrix, EigenMatrix>> TransportTangentCache;
|
|
7
|
+
|
|
8
|
+
Grassmann(EigenMatrix p, bool matrix_free);
|
|
9
|
+
|
|
10
|
+
int getDimension() const override;
|
|
11
|
+
double Inner(EigenMatrix X, EigenMatrix Y) const override;
|
|
12
|
+
|
|
13
|
+
EigenMatrix Exponential(EigenMatrix X) const override;
|
|
14
|
+
EigenMatrix Logarithm(Manifold& N) const override;
|
|
15
|
+
|
|
16
|
+
EigenMatrix TangentProjection(EigenMatrix A) const override;
|
|
17
|
+
EigenMatrix TangentPurification(EigenMatrix A) const override;
|
|
18
|
+
|
|
19
|
+
EigenMatrix TransportTangent(EigenMatrix X, EigenMatrix Y) const override;
|
|
20
|
+
EigenMatrix TransportManifold(EigenMatrix X, Manifold& N) const override;
|
|
21
|
+
|
|
22
|
+
void Update(EigenMatrix p, bool purify) override;
|
|
23
|
+
void getGradient() override;
|
|
24
|
+
void getHessian() override;
|
|
25
|
+
|
|
26
|
+
std::unique_ptr<Manifold> Clone() const override;
|
|
27
|
+
};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#ifdef __PYTHON__
|
|
2
|
+
#include <pybind11/pybind11.h>
|
|
3
|
+
#include <pybind11/stl.h>
|
|
4
|
+
#include <pybind11/eigen.h>
|
|
5
|
+
#include <pybind11/functional.h>
|
|
6
|
+
#endif
|
|
7
|
+
#include <Eigen/Dense>
|
|
8
|
+
#include <typeinfo>
|
|
9
|
+
#include <memory>
|
|
10
|
+
|
|
11
|
+
#include "../Macro.h"
|
|
12
|
+
|
|
13
|
+
#include "Manifold.h"
|
|
14
|
+
|
|
15
|
+
#include <iostream>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Manifold::Manifold(EigenMatrix p, bool matrix_free){
|
|
19
|
+
this->P.resize(p.rows(), p.cols());
|
|
20
|
+
this->Ge.resize(p.rows(), p.cols());
|
|
21
|
+
this->Gr.resize(p.rows(), p.cols());
|
|
22
|
+
this->P = p;
|
|
23
|
+
this->MatrixFree = matrix_free;
|
|
24
|
+
if (this->MatrixFree){
|
|
25
|
+
this->Hem.resize(0, 0);
|
|
26
|
+
this->Hrm.resize(0);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
int Manifold::getDimension() const{
|
|
31
|
+
__Not_Implemented__
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
double Manifold::Inner(EigenMatrix X, EigenMatrix Y) const{
|
|
36
|
+
__Not_Implemented__
|
|
37
|
+
return X.rows() * Y.cols() * 0; // Avoiding the unused-variable warning
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static std::tuple<EigenVector, EigenMatrix> ThinEigen(EigenMatrix A, int m){
|
|
41
|
+
// n - Total number of eigenvalues
|
|
42
|
+
// m - Number of non-trivial eigenvalues
|
|
43
|
+
const int n = A.rows();
|
|
44
|
+
Eigen::SelfAdjointEigenSolver<EigenMatrix> es;
|
|
45
|
+
es.compute(A);
|
|
46
|
+
std::vector<std::tuple<double, EigenVector>> eigen_tuples;
|
|
47
|
+
eigen_tuples.reserve(n);
|
|
48
|
+
for ( int i = 0; i < n; i++ )
|
|
49
|
+
eigen_tuples.push_back(std::make_tuple(es.eigenvalues()(i), es.eigenvectors().col(i)));
|
|
50
|
+
std::sort( // Sorting the eigenvalues in decreasing order of magnitude.
|
|
51
|
+
eigen_tuples.begin(), eigen_tuples.end(),
|
|
52
|
+
[](std::tuple<double, EigenVector>& a, std::tuple<double, EigenVector>& b){
|
|
53
|
+
return std::abs(std::get<0>(a)) > std::abs(std::get<0>(b));
|
|
54
|
+
}
|
|
55
|
+
); // Now the eigenvalues closest to zero are in the back.
|
|
56
|
+
eigen_tuples.resize(m); // Deleting them.
|
|
57
|
+
std::sort( // Resorting the eigenvalues in increasing order.
|
|
58
|
+
eigen_tuples.begin(), eigen_tuples.end(),
|
|
59
|
+
[](std::tuple<double, EigenVector>& a, std::tuple<double, EigenVector>& b){
|
|
60
|
+
return std::get<0>(a) < std::get<0>(b);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
EigenVector eigenvalues = EigenZero(m, 1);
|
|
64
|
+
EigenMatrix eigenvectors = EigenZero(n, m);
|
|
65
|
+
for ( int i = 0; i < m; i++ ){
|
|
66
|
+
eigenvalues(i) = std::get<0>(eigen_tuples[i]);
|
|
67
|
+
eigenvectors.col(i) = std::get<1>(eigen_tuples[i]);
|
|
68
|
+
}
|
|
69
|
+
return std::make_tuple(eigenvalues, eigenvectors);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void Manifold::getBasisSet(){
|
|
73
|
+
const int nrows = this->P.rows();
|
|
74
|
+
const int ncols = this->P.cols();
|
|
75
|
+
const int size = nrows * ncols;
|
|
76
|
+
const int rank = this->getDimension();
|
|
77
|
+
EigenMatrix euclidean_basis = EigenZero(nrows, ncols);
|
|
78
|
+
std::vector<EigenMatrix> unorthogonal_basis_set(size, EigenZero(nrows, ncols));
|
|
79
|
+
for ( int i = 0, n = 0; i < nrows; i++ ) for ( int j = 0; j < ncols; j++ , n++){
|
|
80
|
+
euclidean_basis(i, j) = 1;
|
|
81
|
+
unorthogonal_basis_set[n] = TangentProjection(euclidean_basis);
|
|
82
|
+
euclidean_basis(i, j) = 0;
|
|
83
|
+
}
|
|
84
|
+
EigenMatrix gram = EigenZero(size, size);
|
|
85
|
+
for ( int i = 0; i < size; i++ ) for ( int j = 0; j <= i; j++ ){
|
|
86
|
+
gram(i, j) = gram(j, i) = this->Inner(unorthogonal_basis_set[i], unorthogonal_basis_set[j]);
|
|
87
|
+
}
|
|
88
|
+
auto [Sigma, U] = ThinEigen(gram, rank);
|
|
89
|
+
const EigenMatrix C = U * Sigma.cwiseSqrt().asDiagonal();
|
|
90
|
+
this->BasisSet.resize(rank);
|
|
91
|
+
for ( int i = 0; i < rank; i++ ){
|
|
92
|
+
this->BasisSet[i].resize(nrows, ncols); this->BasisSet[i].setZero();
|
|
93
|
+
for ( int j = 0; j < size; j++ ){
|
|
94
|
+
this->BasisSet[i] += C(j, i) * unorthogonal_basis_set[j].reshaped<Eigen::RowMajor>(nrows, ncols);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
std::vector<std::tuple<double, EigenMatrix>> Diagonalize(
|
|
100
|
+
EigenMatrix& A, std::vector<EigenMatrix>& basis_set){
|
|
101
|
+
Eigen::SelfAdjointEigenSolver<EigenMatrix> es;
|
|
102
|
+
es.compute( ( A + A.transpose() ) / 2 );
|
|
103
|
+
const EigenMatrix Lambda = es.eigenvalues();
|
|
104
|
+
const EigenMatrix Y = es.eigenvectors();
|
|
105
|
+
const int nrows = basis_set[0].rows();
|
|
106
|
+
const int ncols = basis_set[0].cols();
|
|
107
|
+
const int rank = basis_set.size();
|
|
108
|
+
std::vector<std::tuple<double, EigenMatrix>> hrm(rank, std::tuple(0, EigenZero(nrows, ncols)));
|
|
109
|
+
for ( int i = 0; i < rank; i++ ){
|
|
110
|
+
std::get<0>(hrm[i]) = Lambda(i);
|
|
111
|
+
for ( int j = 0; j < rank; j++ ){
|
|
112
|
+
std::get<1>(hrm[i]) += basis_set[j] * Y(j, i);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return hrm;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
void Manifold::getHessianMatrix(){
|
|
119
|
+
// Representing the Riemannian hessian with the orthogonal basis set
|
|
120
|
+
const int rank = this->getDimension();
|
|
121
|
+
EigenMatrix hrm = EigenZero(rank, rank);
|
|
122
|
+
for ( int i = 0; i < rank; i++ ) for ( int j = 0; j <= i; j++ ){
|
|
123
|
+
hrm(i, j) = hrm(j, i) = this->Inner(this->BasisSet[i], this->Hr(this->BasisSet[j]));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Diagonalizing the Riemannian hessian and representing the eigenvectors in Euclidean space
|
|
127
|
+
this->Hrm = Diagonalize(hrm, this->BasisSet);
|
|
128
|
+
|
|
129
|
+
// Updating the Riemannian hessian operator
|
|
130
|
+
this->Hr = [&hrm = this->Hrm](EigenMatrix v){ // Passing reference instead of value to std::function, so that the eigenvalues can be modified elsewhere without rewriting this part.
|
|
131
|
+
EigenMatrix Hv = EigenZero(v.rows(), v.cols());
|
|
132
|
+
for ( auto [eigenvalue, eigenvector] : hrm ){
|
|
133
|
+
Hv += eigenvalue * eigenvector.cwiseProduct(v).sum() * eigenvector;
|
|
134
|
+
}
|
|
135
|
+
return Hv;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
EigenMatrix Manifold::Exponential(EigenMatrix X) const{
|
|
140
|
+
__Not_Implemented__
|
|
141
|
+
return EigenZero(X.rows(), X.cols());
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
EigenMatrix Manifold::Logarithm(Manifold& N) const{
|
|
145
|
+
__Not_Implemented__
|
|
146
|
+
return EigenZero(N.P.rows(), N.P.cols());
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
EigenMatrix Manifold::TangentProjection(EigenMatrix A) const{
|
|
150
|
+
__Not_Implemented__
|
|
151
|
+
return EigenZero(A.rows(), A.cols());
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
EigenMatrix Manifold::TangentPurification(EigenMatrix A) const{
|
|
155
|
+
__Not_Implemented__
|
|
156
|
+
return EigenZero(A.rows(), A.cols());
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
EigenMatrix Manifold::TransportTangent(EigenMatrix X, EigenMatrix Y) const{
|
|
160
|
+
__Not_Implemented__
|
|
161
|
+
return EigenZero(X.rows(), Y.cols());
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
EigenMatrix Manifold::TransportManifold(EigenMatrix X, Manifold& N) const{
|
|
165
|
+
__Not_Implemented__
|
|
166
|
+
return EigenZero(X.rows(), N.P.cols());
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
void Manifold::Update(EigenMatrix p, bool purify){
|
|
170
|
+
if ( purify ? p.rows() : p.cols() ){ // To avoid the unused-variable warning.
|
|
171
|
+
__Not_Implemented__
|
|
172
|
+
}else{
|
|
173
|
+
__Not_Implemented__
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
void Manifold::getGradient(){
|
|
178
|
+
__Not_Implemented__
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
void Manifold::getHessian(){
|
|
182
|
+
__Not_Implemented__
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
std::unique_ptr<Manifold> Manifold::Clone() const{
|
|
186
|
+
__Not_Implemented__
|
|
187
|
+
return std::make_unique<Manifold>(*this);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#ifdef __PYTHON__
|
|
191
|
+
void Init_Manifold(pybind11::module_& m){
|
|
192
|
+
pybind11::class_<Manifold>(m, "Manifold")
|
|
193
|
+
.def_readwrite("Name", &Manifold::Name)
|
|
194
|
+
.def_readwrite("P", &Manifold::P)
|
|
195
|
+
.def_readwrite("Ge", &Manifold::Ge)
|
|
196
|
+
.def_readwrite("Gr", &Manifold::Gr)
|
|
197
|
+
.def_readwrite("MatrixFree", &Manifold::MatrixFree)
|
|
198
|
+
.def_readwrite("Hem", &Manifold::Hem)
|
|
199
|
+
.def_readwrite("Hrm", &Manifold::Hrm)
|
|
200
|
+
.def_readwrite("He", &Manifold::He)
|
|
201
|
+
.def_readwrite("Hr", &Manifold::Hr)
|
|
202
|
+
.def_readwrite("BasisSet", &Manifold::BasisSet)
|
|
203
|
+
.def(pybind11::init<EigenMatrix, bool>())
|
|
204
|
+
.def("getDimension", &Manifold::getDimension)
|
|
205
|
+
.def("Inner", &Manifold::Inner)
|
|
206
|
+
.def("getBasisSet", &Manifold::getBasisSet)
|
|
207
|
+
.def("getHessianMatrix", &Manifold::getHessianMatrix)
|
|
208
|
+
.def("Exponential", &Manifold::Exponential)
|
|
209
|
+
.def("Logarithm", &Manifold::Logarithm)
|
|
210
|
+
.def("TangentProjection", &Manifold::TangentProjection)
|
|
211
|
+
.def("TangentPurification", &Manifold::TangentPurification)
|
|
212
|
+
.def("TransportTangent", &Manifold::TransportTangent)
|
|
213
|
+
.def("TransportManifold", &Manifold::TransportManifold)
|
|
214
|
+
.def("Update", &Manifold::Update)
|
|
215
|
+
.def("getGradient", &Manifold::getGradient)
|
|
216
|
+
.def("getHessian", &Manifold::getHessian)
|
|
217
|
+
.def("Clone", &Manifold::Clone);
|
|
218
|
+
m.def("Diagonalize", &Diagonalize);
|
|
219
|
+
}
|
|
220
|
+
#endif
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#define __Check_Log_Map__\
|
|
4
|
+
if ( typeid(N) != typeid(*this) )\
|
|
5
|
+
throw std::runtime_error("The point to logarithm map is not in " + std::string(typeid(*this).name()) + "but in " + std::string(typeid(N).name()) + "!");
|
|
6
|
+
|
|
7
|
+
#define __Check_Vec_Transport__\
|
|
8
|
+
if ( typeid(N) != typeid(*this) )\
|
|
9
|
+
throw std::runtime_error("The destination of vector transport is not in " + std::string(typeid(*this).name()) + "but in " + std::string(typeid(N).name()) + "!");
|
|
10
|
+
|
|
11
|
+
class Manifold{ public:
|
|
12
|
+
std::string Name;
|
|
13
|
+
EigenMatrix P;
|
|
14
|
+
EigenMatrix Ge;
|
|
15
|
+
EigenMatrix Gr;
|
|
16
|
+
bool MatrixFree;
|
|
17
|
+
EigenMatrix Hem;
|
|
18
|
+
std::vector<std::tuple<double, EigenMatrix>> Hrm;
|
|
19
|
+
std::function<EigenMatrix (EigenMatrix)> He;
|
|
20
|
+
std::function<EigenMatrix (EigenMatrix)> Hr;
|
|
21
|
+
std::vector<EigenMatrix> BasisSet;
|
|
22
|
+
|
|
23
|
+
Manifold(EigenMatrix p, bool matrix_free);
|
|
24
|
+
virtual int getDimension() const;
|
|
25
|
+
virtual double Inner(EigenMatrix X, EigenMatrix Y) const;
|
|
26
|
+
void getBasisSet();
|
|
27
|
+
void getHessianMatrix();
|
|
28
|
+
|
|
29
|
+
virtual EigenMatrix Exponential(EigenMatrix X) const;
|
|
30
|
+
virtual EigenMatrix Logarithm(Manifold& N) const;
|
|
31
|
+
|
|
32
|
+
virtual EigenMatrix TangentProjection(EigenMatrix A) const;
|
|
33
|
+
virtual EigenMatrix TangentPurification(EigenMatrix A) const;
|
|
34
|
+
|
|
35
|
+
virtual EigenMatrix TransportTangent(EigenMatrix X, EigenMatrix Y) const;
|
|
36
|
+
virtual EigenMatrix TransportManifold(EigenMatrix X, Manifold& N) const;
|
|
37
|
+
|
|
38
|
+
virtual void Update(EigenMatrix p, bool purify);
|
|
39
|
+
virtual void getGradient();
|
|
40
|
+
virtual void getHessian();
|
|
41
|
+
|
|
42
|
+
virtual ~Manifold() = default;
|
|
43
|
+
virtual std::unique_ptr<Manifold> Clone() const;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
std::vector<std::tuple<double, EigenMatrix>> Diagonalize(
|
|
47
|
+
EigenMatrix& A, std::vector<EigenMatrix>& basis_set);
|