2018-02-11 09:13:32 +00:00
|
|
|
#include "message_handler.h"
|
|
|
|
#include "query_utils.h"
|
2018-05-28 00:50:02 +00:00
|
|
|
#include "pipeline.hh"
|
|
|
|
using namespace ccls;
|
2018-02-11 09:13:32 +00:00
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <numeric>
|
|
|
|
|
2018-04-30 04:49:03 +00:00
|
|
|
MAKE_HASHABLE(SymbolIdx, t.usr, t.kind);
|
2018-04-08 17:32:08 +00:00
|
|
|
|
2018-02-11 09:13:32 +00:00
|
|
|
namespace {
|
2018-03-31 03:16:33 +00:00
|
|
|
MethodType kMethodType = "$ccls/random";
|
2018-03-22 04:05:25 +00:00
|
|
|
|
2018-03-31 03:16:33 +00:00
|
|
|
struct In_CclsRandom : public RequestInMessage {
|
2018-03-22 04:05:25 +00:00
|
|
|
MethodType GetMethodType() const override { return kMethodType; }
|
2018-02-11 09:13:32 +00:00
|
|
|
};
|
2018-03-31 03:16:33 +00:00
|
|
|
MAKE_REFLECT_STRUCT(In_CclsRandom, id);
|
|
|
|
REGISTER_IN_MESSAGE(In_CclsRandom);
|
2018-02-11 09:13:32 +00:00
|
|
|
|
|
|
|
const double kDeclWeight = 3;
|
|
|
|
const double kDamping = 0.1;
|
|
|
|
|
2018-04-30 04:49:03 +00:00
|
|
|
template <auto Q>
|
2018-02-11 09:13:32 +00:00
|
|
|
void Add(const std::unordered_map<SymbolIdx, int>& sym2id,
|
|
|
|
std::vector<std::unordered_map<int, double>>& adj,
|
2018-04-30 04:49:03 +00:00
|
|
|
const std::vector<Usr>& collection,
|
2018-02-11 09:13:32 +00:00
|
|
|
int n,
|
|
|
|
double w = 1) {
|
2018-04-30 04:49:03 +00:00
|
|
|
for (Usr usr : collection) {
|
|
|
|
auto it = sym2id.find(SymbolIdx{usr, Q});
|
2018-02-11 09:13:32 +00:00
|
|
|
if (it != sym2id.end())
|
|
|
|
adj[it->second][n] += w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-31 03:16:33 +00:00
|
|
|
struct Handler_CclsRandom : BaseMessageHandler<In_CclsRandom> {
|
2018-03-22 04:05:25 +00:00
|
|
|
MethodType GetMethodType() const override { return kMethodType; }
|
|
|
|
|
2018-03-31 03:16:33 +00:00
|
|
|
void Run(In_CclsRandom* request) override {
|
2018-02-11 09:13:32 +00:00
|
|
|
std::unordered_map<SymbolIdx, int> sym2id;
|
|
|
|
std::vector<SymbolIdx> syms;
|
|
|
|
int n = 0;
|
|
|
|
|
2018-04-30 04:49:03 +00:00
|
|
|
for (auto& it : db->usr2func)
|
|
|
|
if (it.second.AnyDef()) {
|
|
|
|
syms.push_back(SymbolIdx{it.first, SymbolKind::Func});
|
2018-02-11 09:13:32 +00:00
|
|
|
sym2id[syms.back()] = n++;
|
|
|
|
}
|
2018-04-30 04:49:03 +00:00
|
|
|
for (auto& it : db->usr2type)
|
|
|
|
if (it.second.AnyDef()) {
|
|
|
|
syms.push_back(SymbolIdx{it.first, SymbolKind::Type});
|
2018-02-11 09:13:32 +00:00
|
|
|
sym2id[syms.back()] = n++;
|
|
|
|
}
|
2018-04-30 04:49:03 +00:00
|
|
|
for (auto& it : db->usr2var)
|
|
|
|
if (it.second.AnyDef()) {
|
|
|
|
syms.push_back(SymbolIdx{it.first, SymbolKind::Var});
|
2018-02-11 09:13:32 +00:00
|
|
|
sym2id[syms.back()] = n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::unordered_map<int, double>> adj(n);
|
|
|
|
auto add = [&](const std::vector<Use>& uses, double w) {
|
|
|
|
for (Use use : uses) {
|
2018-02-11 18:25:37 +00:00
|
|
|
auto it = sym2id.find(use);
|
2018-02-11 09:13:32 +00:00
|
|
|
if (it != sym2id.end())
|
|
|
|
adj[it->second][n] += w;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
n = 0;
|
2018-04-30 04:49:03 +00:00
|
|
|
for (auto& it : db->usr2func)
|
|
|
|
if (it.second.AnyDef()) {
|
|
|
|
add(it.second.declarations, kDeclWeight);
|
|
|
|
add(it.second.uses, 1);
|
|
|
|
Add<SymbolKind::Func>(sym2id, adj, it.second.derived, n);
|
2018-02-11 09:13:32 +00:00
|
|
|
n++;
|
|
|
|
}
|
2018-04-30 04:49:03 +00:00
|
|
|
for (auto& it : db->usr2type)
|
|
|
|
if (const auto* def = it.second.AnyDef()) {
|
|
|
|
add(it.second.uses, 1);
|
|
|
|
Add<SymbolKind::Var>(sym2id, adj, it.second.instances, n);
|
|
|
|
Add<SymbolKind::Func>(sym2id, adj, def->funcs, n);
|
|
|
|
Add<SymbolKind::Type>(sym2id, adj, def->types, n);
|
|
|
|
Add<SymbolKind::Var>(sym2id, adj, def->vars, n);
|
2018-02-11 09:13:32 +00:00
|
|
|
n++;
|
|
|
|
}
|
2018-04-30 04:49:03 +00:00
|
|
|
for (auto& it : db->usr2var)
|
|
|
|
if (it.second.AnyDef()) {
|
|
|
|
add(it.second.declarations, kDeclWeight);
|
|
|
|
add(it.second.uses, 1);
|
2018-02-11 09:13:32 +00:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
double sum = 0;
|
|
|
|
adj[i][i] += 1;
|
|
|
|
for (auto& it : adj[i])
|
|
|
|
sum += it.second;
|
|
|
|
for (auto& it : adj[i])
|
|
|
|
it.second = it.second / sum * (1 - kDamping);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<double> x(n, 1), y;
|
2018-02-21 04:26:17 +00:00
|
|
|
for (int j = 0; j < 8; j++) {
|
2018-02-11 09:13:32 +00:00
|
|
|
y.assign(n, kDamping);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
for (auto& it : adj[i])
|
|
|
|
y[it.first] += x[i] * it.second;
|
|
|
|
double d = 0;
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
d = std::max(d, fabs(x[i] - y[i]));
|
2018-02-22 07:34:32 +00:00
|
|
|
if (d < 1e-5)
|
|
|
|
break;
|
2018-02-11 09:13:32 +00:00
|
|
|
x.swap(y);
|
|
|
|
}
|
|
|
|
|
2018-02-15 04:58:42 +00:00
|
|
|
double sum = std::accumulate(x.begin(), x.end(), 0.);
|
2018-02-11 09:13:32 +00:00
|
|
|
Out_LocationList out;
|
|
|
|
out.id = request->id;
|
|
|
|
double roulette = rand() / (RAND_MAX + 1.0) * sum;
|
|
|
|
sum = 0;
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
sum += x[i];
|
|
|
|
if (sum >= roulette) {
|
2018-04-04 06:05:41 +00:00
|
|
|
if (Maybe<Use> use = GetDefinitionExtent(db, syms[i]))
|
|
|
|
if (auto ls_loc = GetLsLocationEx(db, working_files, *use,
|
|
|
|
g_config->xref.container))
|
|
|
|
out.result.push_back(*ls_loc);
|
2018-02-11 09:13:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-05-28 00:50:02 +00:00
|
|
|
pipeline::WriteStdout(kMethodType, out);
|
2018-02-11 09:13:32 +00:00
|
|
|
}
|
|
|
|
};
|
2018-03-31 03:16:33 +00:00
|
|
|
REGISTER_MESSAGE_HANDLER(Handler_CclsRandom);
|
2018-02-11 09:13:32 +00:00
|
|
|
} // namespace
|