-
Notifications
You must be signed in to change notification settings - Fork 0
/
pynerv.cc
102 lines (87 loc) · 3.03 KB
/
pynerv.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*Copyright (C) Kristian Nybo, Jarkko Venna
*
*This software is released under the GNU Lesser General Public
*License. See the included file LICENSE for details.*/
#include <iostream>
#include <string>
#include <fstream>
#include "dataset.hh"
#include "distancematrix.hh"
#include "nervcostfunction.hh"
#include "nervoptstrat.hh"
#include "goldensectionsearch.hh"
#include "conjugategradientopt.hh"
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
using namespace dredviz;
namespace py = pybind11;
// Interface flexibility moves to nerv.py
py::tuple nerv(py::array_t<double>& pyInputDist,
double lambda,
size_t lastNeighbor,
py::array_t<double>& init,
size_t outputDimension,
py::array_t<double>& pyWeights,
double initrad,
size_t iterations,
size_t stepsPerRound,
size_t stepsOnLastRound,
py::object& pyFilenameStem
) {
size_t n = pyInputDist.shape(0);
std::vector<size_t> embedding_shape = {n, outputDimension};
py::array_t<double> embedding(embedding_shape);
ConjugateGradientOpt *optStep = NULL;
try {
DistanceMatrix origDataDist(n);
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < n; j++) {
origDataDist(i, j) = *pyInputDist.data(i, j);
}
}
std::vector<double> weights(n);
for (size_t i = 0; i < n; i++) {
weights[i] = *pyWeights.data(i);
}
DataSet projData(n, outputDimension);
for (size_t i = 0; i < n; i++) {
for (size_t d = 0; d < outputDimension; d++) {
projData(i, d) = *init.data(i, d);
}
}
origDataDist.scale (1.0 / origDataDist.getAverage ());
DynamicDouble initialRadius (initrad, 0);
GoldenSectionSearch linesearch;
NeRVCostFunction costFunc (origDataDist, projData, linesearch,
initialRadius, lambda, lastNeighbor,
weights, std::cout);
if (pyFilenameStem.is_none()) {
optStep = new ConjugateGradientOpt(costFunc, linesearch, std::cerr);
}
else {
std::string filename_stem = py::str(pyFilenameStem);
optStep = new ConjugateGradientOpt(costFunc, linesearch, std::cerr,
filename_stem);
}
std::string tmpoutputfile;
NeRVOptStrat optStrategy(iterations, stepsPerRound, stepsOnLastRound, tmpoutputfile);
optStrategy.optimize(origDataDist, projData, *optStep, costFunc, std::cerr);
for (size_t i = 0; i < n; i++) {
for (size_t d = 0; d < outputDimension; d++) {
*embedding.mutable_data(i, d) = projData(i, d);
}
}
}
catch (Exception & exc)
{
std::cerr << "Error: " << exc.getErrMsg () << std::endl;
}
double finalCost = optStep->getFinalCost();
return py::make_tuple(embedding, finalCost);
delete optStep;
}
PYBIND11_PLUGIN(pynerv) {
py::module m("pynerv", "A Python wrapper of Neighbor Retrieval Visualizer (NeRV)");
m.def("nerv", &nerv, "NeRV's Python wrapper");
return m.ptr();
}