1 #include "MUQ/Approximation/Regression/LocalRegression.h"
2
3 #if MUQ_HAS_PARCER
4 #include <parcer/Eigen.h>
5 #endif
6
7 namespace pt = boost::property_tree;
8 using namespace muq::Modeling;
9 using namespace muq::Approximation;
10
LocalRegression(std::shared_ptr<ModPiece> function,pt::ptree & pt)11 LocalRegression::LocalRegression(std::shared_ptr<ModPiece> function, pt::ptree& pt) : ModPiece(function->inputSizes, function->outputSizes), kn(pt.get<unsigned int>("NumNeighbors")) {
12 SetUp(function, pt);
13 }
14
15 #if MUQ_HAS_PARCER
LocalRegression(std::shared_ptr<muq::Modeling::ModPiece> function,boost::property_tree::ptree & pt,std::shared_ptr<parcer::Communicator> comm)16 LocalRegression::LocalRegression(std::shared_ptr<muq::Modeling::ModPiece> function, boost::property_tree::ptree& pt, std::shared_ptr<parcer::Communicator> comm) : ModPiece(function->inputSizes, function->outputSizes), kn(pt.get<unsigned int>("NumNeighbors")), comm(comm) /*tagSingle(comm->GetSize()+1), tagMulti(comm->GetSize()+2)*/ {
17 SetUp(function, pt);
18 }
19
~LocalRegression()20 LocalRegression::~LocalRegression() {
21 if( comm ) {
22 // needs to be destroyed on all processors
23 comm->Barrier();
24
25 // clear any messages
26 Probe();
27 }
28 }
29 #endif
30
SetUp(std::shared_ptr<muq::Modeling::ModPiece> function,boost::property_tree::ptree & pt)31 void LocalRegression::SetUp(std::shared_ptr<muq::Modeling::ModPiece> function, boost::property_tree::ptree& pt) {
32 // can only have one input and output
33 assert(inputSizes.size()==1);
34 assert(outputSizes.size()==1);
35
36 // create a cache of model evaluations
37 cache = std::make_shared<FlannCache>(function);
38
39 // create a regression object
40 pt.put<std::string>("PolynomialBasis", pt.get<std::string>("PolynomialBasis", "Legendre")); // set default to Legendre
41 pt.put<unsigned int>("Order", pt.get<unsigned int>("Order", 2)); // set default order to 2
42 pt.put<double>("MaxPoisednessRadius", pt.get<double>("MaxPoisednessRadius", 1.0));
43 pt.put<unsigned int>("InputSize", function->inputSizes(0));
44 reg = std::make_shared<Regression>(pt);
45 }
46
ClearCache()47 void LocalRegression::ClearCache() {
48 assert(cache);
49 cache = std::make_shared<FlannCache>(cache->Function());
50 }
51
FitRegression(Eigen::VectorXd const & input) const52 void LocalRegression::FitRegression(Eigen::VectorXd const& input) const {
53 // find the nearest neighbors
54 std::vector<Eigen::VectorXd> neighbors;
55 std::vector<Eigen::VectorXd> result;
56 cache->NearestNeighbors(input, kn, neighbors, result);
57
58 // fit the regression
59 reg->Fit(neighbors, result, input);
60 }
61
EvaluateImpl(ref_vector<Eigen::VectorXd> const & inputs)62 void LocalRegression::EvaluateImpl(ref_vector<Eigen::VectorXd> const& inputs) {
63 #if MUQ_HAS_PARCER
64 Probe();
65 #endif
66
67 // fit the regressor
68 FitRegression(inputs[0]);
69
70 // evaluate the regressor
71 outputs.resize(1);
72 outputs[0] = (Eigen::VectorXd)boost::any_cast<Eigen::MatrixXd const&>(reg->Evaluate(inputs[0].get()) [0]).col(0);
73 }
74
CacheSize() const75 unsigned int LocalRegression::CacheSize() const {
76 assert(cache);
77 return cache->Size();
78 }
79
CachePoint(unsigned int const index) const80 Eigen::VectorXd LocalRegression::CachePoint(unsigned int const index) const {
81 assert(cache);
82 return cache->at(index);
83 }
84
InCache(Eigen::VectorXd const & point) const85 bool LocalRegression::InCache(Eigen::VectorXd const& point) const {
86 assert(cache);
87 return cache->InCache(point)>=0;
88 }
89
Add(Eigen::VectorXd const & input) const90 Eigen::VectorXd LocalRegression::Add(Eigen::VectorXd const& input) const {
91 assert(cache);
92 const Eigen::VectorXd result = cache->Add(input);
93
94 #if MUQ_HAS_PARCER
95 if( comm ) {
96 for( unsigned int i=0; i<comm->GetSize(); ++i ) {
97 if( i==comm->GetRank() ) { continue; }
98
99 comm->Send(std::pair<Eigen::VectorXd, Eigen::VectorXd>(input, result), i, tagSingle);
100 }
101 Probe();
102 }
103 #endif
104
105 return result;
106 }
107
Add(std::vector<Eigen::VectorXd> const & inputs) const108 void LocalRegression::Add(std::vector<Eigen::VectorXd> const& inputs) const {
109 for( auto it : inputs ) { Add(it); }
110 }
111
PoisednessConstant(Eigen::VectorXd const & input) const112 std::tuple<Eigen::VectorXd, double, unsigned int> LocalRegression::PoisednessConstant(Eigen::VectorXd const& input) const {
113 // find the nearest neighbors
114 std::vector<Eigen::VectorXd> neighbors;
115 cache->NearestNeighbors(input, kn, neighbors);
116
117 return PoisednessConstant(input, neighbors);
118 }
119
PoisednessConstant(Eigen::VectorXd const & input,std::vector<Eigen::VectorXd> const & neighbors) const120 std::tuple<Eigen::VectorXd, double, unsigned int> LocalRegression::PoisednessConstant(Eigen::VectorXd const& input, std::vector<Eigen::VectorXd> const& neighbors) const {
121 assert(neighbors.size()>=kn);
122 assert(reg);
123 std::pair<Eigen::VectorXd, double> lambda = reg->PoisednessConstant(neighbors, input, kn);
124
125 double dist = 0.0;
126 unsigned int index = 0;
127 for( unsigned int i=0; i<kn; ++i ) {
128 const double d = (input-neighbors[i]).norm();
129 if( d<dist ) { dist = d; index = i; }
130 }
131
132 return std::tuple<Eigen::VectorXd, double, unsigned int>(lambda.first, lambda.second, index);
133 }
134
ErrorIndicator(Eigen::VectorXd const & input) const135 std::pair<double, double> LocalRegression::ErrorIndicator(Eigen::VectorXd const& input) const {
136 // find the nearest neighbors
137 std::vector<Eigen::VectorXd> neighbors;
138 cache->NearestNeighbors(input, kn, neighbors);
139
140 return ErrorIndicator(input, neighbors);
141 }
142
Order() const143 unsigned int LocalRegression::Order() const { return reg->order; }
144
ErrorIndicator(Eigen::VectorXd const & input,std::vector<Eigen::VectorXd> const & neighbors) const145 std::pair<double, double> LocalRegression::ErrorIndicator(Eigen::VectorXd const& input, std::vector<Eigen::VectorXd> const& neighbors) const {
146 assert(neighbors.size()==kn);
147
148 // create a local factorial function (caution: may be problematic if n is sufficiently large)
149 //std::function<int(int)> factorial = [&factorial](int const n) { return ((n==2 || n==1)? n : n*factorial(n-1)); };
150
151 // compute the radius
152 double delta = 0.0;
153 for( auto n : neighbors) { delta = std::max(delta, (n-input).norm()); }
154 /*Eigen::ArrayXd radius = Eigen::ArrayXd::Zero(input.size());
155 for( auto n : neighbors) {
156 //std::cout << n.transpose() << std::endl;
157 radius = radius.max((n-input).array().abs());
158 }*/
159
160 return std::pair<double, double>(((double)reg->order+1.0)*std::log(delta), delta);
161 }
162
NearestNeighbors(Eigen::VectorXd const & input,std::vector<Eigen::VectorXd> & neighbors) const163 void LocalRegression::NearestNeighbors(Eigen::VectorXd const& input, std::vector<Eigen::VectorXd>& neighbors) const {
164 assert(cache);
165 cache->NearestNeighbors(input, kn, neighbors);
166 }
167
NearestNeighbors(Eigen::VectorXd const & input,std::vector<Eigen::VectorXd> & neighbors,std::vector<Eigen::VectorXd> & result) const168 void LocalRegression::NearestNeighbors(Eigen::VectorXd const& input, std::vector<Eigen::VectorXd>& neighbors, std::vector<Eigen::VectorXd>& result) const {
169 assert(cache);
170 cache->NearestNeighbors(input, kn, neighbors, result);
171 }
172
EvaluateRegressor(Eigen::VectorXd const & input,std::vector<Eigen::VectorXd> const & neighbors,std::vector<Eigen::VectorXd> const & result) const173 Eigen::VectorXd LocalRegression::EvaluateRegressor(Eigen::VectorXd const& input, std::vector<Eigen::VectorXd> const& neighbors, std::vector<Eigen::VectorXd> const& result) const {
174 #if MUQ_HAS_PARCER
175 Probe();
176 #endif
177
178 // fit the regression
179 reg->Fit(neighbors, result, input);
180
181 // evaluate the regressor
182 return (Eigen::VectorXd)boost::any_cast<Eigen::MatrixXd const&>(reg->Evaluate(input) [0]).col(0);
183 }
184
185 #if MUQ_HAS_PARCER
Probe() const186 void LocalRegression::Probe() const {
187 if( !comm ) { return; }
188 //std::cout << "START PROBE!!! ";// /*<< comm->GetRank() */<< std::endl;
189
190 for( unsigned int i=0; i<comm->GetSize(); ++i ) {
191 // std::cout << "CHECKING " << i << " of " << comm->GetSize() << " rank: " << comm->GetRank();// << std::endl;
192 //std::cout << "START RECIEVING " << i+1 << " of " << 2 << std::endl;
193 if( i==comm->GetRank() ) { continue; }
194 //std::cout << "START RECIEVING " << i << " of " << comm->GetSize() << " rank: " << comm->GetRank();// << std::endl;
195
196 //{ // get single adds
197 //parcer::RecvRequest recvReq;
198 //bool enter = comm->Iprobe(i, tagSingle, recvReq);
199 while( true ) {
200 parcer::RecvRequest recvReq;
201 if( !comm->Iprobe(i, tagSingle, recvReq) ) { break; }
202 //std::cout << "PROBED ";
203 // get the point
204 comm->Irecv(i, tagSingle, recvReq);
205 //std::cout << "RECIEVED, proc: " << std::endl << std::flush;
206 //std::cout << "RECIEVED, proc: " << comm->GetRank() << std::endl << std::flush;
207 const std::pair<Eigen::VectorXd, Eigen::VectorXd> point = recvReq.GetObject<std::pair<Eigen::VectorXd, Eigen::VectorXd> >();
208 //std::cout << std::flush;
209 //auto point = recvReq.GetObject<std::pair<Eigen::VectorXd, Eigen::VectorXd> >();
210 //std::cout << "GOT OBJECT!" << " rank: " << comm->GetRank() << " ";
211 //std::cout << "GOT OBJECT!" << std::endl;
212
213 // add the point
214 cache->Add(point.first, point.second);
215
216 //std::cout << "ADDED!" << " rank: " << comm->GetRank() << " ";
217
218 recvReq.Clear();
219
220 //std::cout << "CLEARED!" << " rank: " << comm->GetRank() << " ";
221
222 //enter = comm->Iprobe(i, tagSingle, recvReq);
223
224 // std::cout << "PROBED!" << " rank: " << comm->GetRank();
225 }
226 //}
227
228 //std::cout << "DONE WITH THIS BIT" << " rank: " << comm->GetRank() << " ";
229 //std::cout << "DONE RECIEVING " << i << " of " << comm->GetSize() << " ";// << std::endl;
230 }
231
232 // std::cout << "DONE WITH PROBE!!!" << std::endl;
233 }
234 #endif
235
CacheCentroid() const236 Eigen::VectorXd LocalRegression::CacheCentroid() const {
237 assert(cache);
238 return cache->Centroid();
239 }
240