Skip to content

Commit 4c0f5b2

Browse files
author
NeiroYT
committed
New implementation
1 parent 5d6f266 commit 4c0f5b2

4 files changed

Lines changed: 207 additions & 91 deletions

File tree

include/graph/graph.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,29 @@ class Graph {
105105
V_++;
106106
in_edges_.resize(1);
107107
}
108+
109+
void addSingleLayer(Layer& lay) {
110+
bool layer_exists = false;
111+
for (const auto* layer : layers_) {
112+
if (layer == &lay) {
113+
layer_exists = true;
114+
break;
115+
}
116+
}
117+
118+
if (!layer_exists) {
119+
lay.setID(V_);
120+
layers_.push_back(&lay);
121+
arrayV_.push_back(static_cast<int>(arrayE_.size()));
122+
123+
if (V_ >= static_cast<int>(in_edges_.size())) {
124+
in_edges_.resize(V_ + 1);
125+
}
126+
127+
V_++;
128+
}
129+
}
130+
108131
void makeConnection(const Layer& layPrev, Layer& layNext) {
109132
bool layer_exists = false;
110133
for (const auto* layer : layers_) {
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
#include <algorithm>
12
#include <vector>
23

34
#include "graph/graph.hpp"
45
#include "layers/Layer.hpp"
56

67
namespace it_lab_ai {
7-
std::vector<int> find_subgraphs(const Graph& graph, const Graph& subgraph);
8-
bool layer_conditions(const Layer& layer, const Layer& layer_sub);
9-
bool check_child(const Graph& graph, const Graph& subgraph, int i, int iter,
10-
int recursionDepth);
8+
std::vector<std::vector<int>> find_subgraphs(const Graph& graph,
9+
const Graph& subgraph);
10+
bool has_edge(const Graph& graph, int id_from, int id_to);
11+
bool is_root(const Graph& graph, int id);
12+
bool is_leaf(const Graph& graph, int id);
13+
bool run_search(const Graph& graph, const Graph& subgraph,
14+
std::vector<int>& assignments,
15+
std::vector<std::vector<int>>& results);
1116
} // namespace it_lab_ai

src/graph_transformations/graph_transformations.cpp

Lines changed: 78 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,96 +2,98 @@
22

33
namespace it_lab_ai {
44

5-
std::vector<int> find_subgraphs(const Graph& graph, const Graph& subgraph) {
5+
bool layer_conditions(const Layer& layer, const Layer& layer_sub) {
6+
return layer.getName() == layer_sub.getName();
7+
}
8+
9+
std::vector<std::vector<int>> find_subgraphs(const Graph& graph,
10+
const Graph& subgraph) {
611
// requirements for subgraph:
7-
// 1 input, 1 output
12+
// one or multiple inputs, one or multiple outputs
813
// requirements for graph:
9-
// can't be connected with subgraph from _outside_, except input and output
10-
std::vector<int> result;
11-
for (int i = 0; i < graph.getLayersCount(); i++) {
12-
bool temp = check_child(graph, subgraph, i, 0, 0); // recursion starts
13-
if (temp) {
14-
result.push_back(i);
14+
// can't be connected from outside, except IO for input and O for output
15+
std::vector<int> assignments; // cur assumption for graph
16+
std::vector<std::vector<int>> results;
17+
run_search(graph, subgraph, assignments, results);
18+
return results;
19+
}
20+
21+
bool has_edge(const Graph& graph, int id_from, int id_to) {
22+
for (int i = graph.getVertexValue(id_from);
23+
i < graph.getVertexValue(id_from + 1); i++) {
24+
if (graph.getEdgeValue(i) == id_to) {
25+
return true;
1526
}
1627
}
17-
return result;
28+
return false;
1829
}
1930

20-
bool layer_conditions(const Layer& layer, const Layer& layer_sub) {
21-
std::cerr << "Comparing type " << static_cast<int>(layer.getName()) << " and "
22-
<< static_cast<int>(layer_sub.getName()) << std::endl;
23-
return layer.getName() == layer_sub.getName();
31+
bool is_root(const Graph& graph, int id) {
32+
return graph.getInputsSize(id) == 0;
2433
}
2534

26-
// void erase_inequality_for_first(
27-
// std::vector<std::pair<int, LayerType>>& vec1,
28-
// const std::vector<std::pair<int, LayerType>>& vec2) {
29-
// for (int i = 0; i < std::min(vec1.size(), vec2.size()); i++) {
30-
// if (vec1[i].second != vec2[i].second) {
31-
// vec1.erase(vec1.begin() + i);
32-
// }
33-
// }
34-
// if (vec1.size() > vec2.size()) {
35-
// vec1.resize(vec2.size());
36-
// }
37-
// }
35+
bool is_leaf(const Graph& graph, int id) {
36+
return graph.getVertexValue(id + 1) - graph.getVertexValue(id) == 0;
37+
}
3838

39-
bool check_child(const Graph& graph, const Graph& subgraph, int i, int iter,
40-
int recursionDepth) {
41-
int amount_connected1 = graph.getVertexValue(i + 1) - graph.getVertexValue(i);
42-
int amount_connected2 =
43-
subgraph.getVertexValue(iter + 1) - subgraph.getVertexValue(iter);
44-
if (amount_connected1 != amount_connected2 && amount_connected2 != 0) {
45-
std::cerr << "Depth " << recursionDepth << " false by outputs\n";
46-
return false;
39+
bool run_search(const Graph& graph, const Graph& subgraph,
40+
std::vector<int>& assignments,
41+
std::vector<std::vector<int>>& results) {
42+
size_t cur_size = assignments.size();
43+
for (int prev_id = 0; prev_id < subgraph.getLayersCount(); prev_id++) {
44+
size_t amount_connected_s =
45+
subgraph.getVertexValue(prev_id + 1) - subgraph.getVertexValue(prev_id);
46+
for (int j = 0; j < amount_connected_s; j++) {
47+
int next_id = subgraph.getEdgeValue(subgraph.getVertexValue(prev_id) + j);
48+
if (prev_id < cur_size && next_id < cur_size) {
49+
if (!has_edge(graph, assignments[prev_id], assignments[next_id])) {
50+
return false;
51+
}
52+
std::vector<int> ids = {prev_id, next_id};
53+
for (int k = 0; k < 2; k++) {
54+
if (!layer_conditions(subgraph.getLayerFromID(ids[k]),
55+
graph.getLayerFromID(assignments[ids[k]]))) {
56+
return false;
57+
}
58+
// input node shouldn't be checked for it's inputs
59+
if (!is_root(subgraph, ids[k]) &&
60+
subgraph.getInputsSize(ids[k]) !=
61+
graph.getInputsSize(assignments[ids[k]])) {
62+
return false;
63+
}
64+
// input & output node shouldn't be checked for it's outputs
65+
if (!is_leaf(subgraph, ids[k]) && !is_root(subgraph, ids[k])) {
66+
size_t amount_connected_s1 = subgraph.getVertexValue(ids[k] + 1) -
67+
subgraph.getVertexValue(ids[k]);
68+
size_t amount_connected_1 =
69+
graph.getVertexValue(assignments[ids[k]] + 1) -
70+
graph.getVertexValue(assignments[ids[k]]);
71+
if (amount_connected_1 != amount_connected_s1) {
72+
return false;
73+
}
74+
}
75+
}
76+
}
77+
}
4778
}
48-
if (!layer_conditions(graph.getLayerFromID(i),
49-
subgraph.getLayerFromID(iter))) {
50-
std::cerr << "Depth " << recursionDepth << " false by layertypes\n";
51-
return false;
79+
80+
// assumption is good -> return true
81+
if (cur_size == subgraph.getLayersCount()) {
82+
return true;
5283
}
53-
if (amount_connected2 != 0) {
54-
using id_name = std::pair<int, LayerType>;
55-
std::vector<id_name> order_a;
56-
std::vector<id_name> order_b;
57-
for (int j = 0; j < amount_connected1; j++) {
58-
order_a.emplace_back(
59-
graph.getEdgeValue(graph.getVertexValue(i) + j),
60-
graph.getLayerFromID(graph.getEdgeValue(graph.getVertexValue(i) + j))
61-
.getName());
62-
order_b.emplace_back(
63-
subgraph.getEdgeValue(subgraph.getVertexValue(iter) + j),
64-
subgraph
65-
.getLayerFromID(
66-
subgraph.getEdgeValue(subgraph.getVertexValue(iter) + j))
67-
.getName());
68-
}
69-
std::sort(order_a.begin(), order_a.end(),
70-
[&](id_name a1, id_name a2) { return a1.second < a2.second; });
71-
std::sort(order_b.begin(), order_b.end(),
72-
[&](id_name a1, id_name a2) { return a1.second < a2.second; });
73-
// ^ interested in LayerType order to prevent any shuffling for childs
74-
// if (first_inequally) {
75-
// erase_inequality_for_first(order_a, order_b);
76-
// }
77-
for (int j = 0; j < amount_connected1; j++) {
78-
int id1 = graph.getEdgeValue(graph.getVertexValue(i) + j);
79-
int id2 = subgraph.getEdgeValue(subgraph.getVertexValue(iter) + j);
80-
if (graph.getInputsSize(id1) != subgraph.getInputsSize(id2)) {
81-
std::cerr << "Depth " << recursionDepth << " false by child inputs\n";
82-
return false;
83-
}
84-
bool temp = check_child(graph, subgraph, order_a[j].first,
85-
order_b[j].first, recursionDepth + 1);
86-
if (!temp) {
87-
std::cerr << "Depth " << recursionDepth
88-
<< " false by child conditions\n";
89-
return false;
84+
85+
// add new nodes for assumption and try recursion
86+
for (int id = 0; id < graph.getLayersCount(); id++) {
87+
auto it = std::find(assignments.begin(), assignments.end(), id);
88+
if (it == assignments.end()) {
89+
assignments.push_back(id);
90+
if (run_search(graph, subgraph, assignments, results)) {
91+
results.emplace_back(assignments);
9092
}
93+
assignments.pop_back();
9194
}
9295
}
93-
std::cerr << "Depth " << recursionDepth << " true\n";
94-
return true;
96+
return false;
9597
}
9698

9799
} // namespace it_lab_ai

test/graph/test_graph.cpp

Lines changed: 97 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <algorithm>
2+
#include <random>
13
#include <vector>
24

35
#include "graph/graph.hpp"
@@ -6,6 +8,7 @@
68
#include "layers/EWLayer.hpp"
79
#include "layers/FCLayer.hpp"
810
#include "layers/InputLayer.hpp"
11+
#include "perf/benchmarking.hpp"
912

1013
using namespace it_lab_ai;
1114

@@ -224,8 +227,9 @@ TEST(graph_transformations, check_subgraphs_search) {
224227

225228
subgraph.setInput(fcLayer, input);
226229
subgraph.makeConnection(fcLayer, fcLayer2);
227-
228-
ASSERT_EQ(find_subgraphs(graph, subgraph), std::vector<int>({1}));
230+
auto res = find_subgraphs(graph, subgraph);
231+
auto it = std::find(res.begin(), res.end(), std::vector<int>({1, 2}));
232+
ASSERT_NE(it, res.end());
229233
}
230234

231235
TEST(graph_transformations, check_subgraphs_search1) {
@@ -241,19 +245,20 @@ TEST(graph_transformations, check_subgraphs_search1) {
241245
FCLayer fcLayer2(weights, bias);
242246
FCLayer fcLayer3(weights, bias);
243247
FCLayer fcLayer4(weights, bias);
244-
FCLayer fcLayer5(weights, bias);
248+
EWLayer ewLayer5("relu");
245249

246250
graph.setInput(fcLayer, input);
247251
graph.makeConnection(fcLayer, fcLayer2);
248252
graph.makeConnection(fcLayer2, fcLayer3);
249253
graph.makeConnection(fcLayer, fcLayer4);
250-
graph.makeConnection(fcLayer4, fcLayer5);
251-
graph.setOutput(fcLayer5, output);
254+
graph.makeConnection(fcLayer4, ewLayer5);
255+
graph.setOutput(ewLayer5, output);
252256

253257
subgraph.setInput(fcLayer, input);
254-
subgraph.makeConnection(fcLayer, fcLayer2);
255-
256-
ASSERT_EQ(find_subgraphs(graph, subgraph), std::vector<int>({1, 3}));
258+
subgraph.makeConnection(fcLayer, ewLayer5);
259+
auto res = find_subgraphs(graph, subgraph);
260+
auto it = std::find(res.begin(), res.end(), std::vector<int>({3, 4}));
261+
ASSERT_NE(it, res.end());
257262
}
258263

259264
TEST(graph_transformations, check_subgraphs_search2) {
@@ -281,7 +286,9 @@ TEST(graph_transformations, check_subgraphs_search2) {
281286
subgraph.makeConnection(fcLayer, fcLayer2);
282287
subgraph.makeConnection(fcLayer2, fcLayer3);
283288

284-
ASSERT_EQ(find_subgraphs(graph, subgraph), std::vector<int>({0}));
289+
auto res = find_subgraphs(graph, subgraph);
290+
auto it = std::find(res.begin(), res.end(), std::vector<int>({0, 1, 2}));
291+
ASSERT_NE(it, res.end());
285292
}
286293

287294
TEST(graph_transformations, check_subgraphs_search3) {
@@ -309,7 +316,9 @@ TEST(graph_transformations, check_subgraphs_search3) {
309316
subgraph.makeConnection(fcLayer, fcLayer2);
310317
subgraph.makeConnection(fcLayer2, fcLayer3);
311318

312-
ASSERT_EQ(find_subgraphs(graph, subgraph), std::vector<int>({2}));
319+
auto res = find_subgraphs(graph, subgraph);
320+
auto it = std::find(res.begin(), res.end(), std::vector<int>({2, 0, 1}));
321+
ASSERT_NE(it, res.end());
313322
}
314323

315324
TEST(graph_transformations, check_subgraphs_search4) {
@@ -337,5 +346,82 @@ TEST(graph_transformations, check_subgraphs_search4) {
337346
subgraph.makeConnection(fcLayer, fcLayer2);
338347
subgraph.makeConnection(fcLayer2, fcLayer3);
339348

340-
ASSERT_EQ(find_subgraphs(graph, subgraph), std::vector<int>({1}));
349+
auto res = find_subgraphs(graph, subgraph);
350+
auto it = std::find(res.begin(), res.end(), std::vector<int>({1, 2, 0}));
351+
ASSERT_NE(it, res.end());
352+
}
353+
354+
TEST(graph_transformations, check_subgraphs_search5) {
355+
const std::vector<float> vec1 = {2.0F, 1.5F, 0.1F, 1.9F, 0.0F, 5.5F};
356+
Tensor weights = make_tensor<float>(vec1, {3, 2});
357+
Tensor bias = make_tensor<float>({0.5F, 0.5F, 1.0F});
358+
Tensor input = make_tensor<float>({1.0F, 2.0F}, {2});
359+
Tensor output;
360+
361+
Graph graph(5);
362+
Graph subgraph(2);
363+
FCLayer fcLayer(weights, bias);
364+
FCLayer fcLayer2(weights, bias);
365+
FCLayer fcLayer3(weights, bias);
366+
FCLayer fcLayer4(weights, bias);
367+
EWLayer ewLayer5("relu");
368+
369+
graph.setInput(fcLayer, input);
370+
graph.makeConnection(fcLayer, fcLayer2);
371+
graph.makeConnection(fcLayer, fcLayer4);
372+
graph.makeConnection(fcLayer2, fcLayer3);
373+
graph.makeConnection(fcLayer4, ewLayer5);
374+
graph.setOutput(ewLayer5, output);
375+
376+
subgraph.setInput(fcLayer, input);
377+
subgraph.makeConnection(fcLayer, fcLayer2);
378+
subgraph.addSingleLayer(fcLayer3);
379+
subgraph.makeConnection(fcLayer3, ewLayer5);
380+
381+
auto res = find_subgraphs(graph, subgraph);
382+
auto it = std::find(res.begin(), res.end(), std::vector<int>({1, 3, 2, 4}));
383+
ASSERT_NE(it, res.end());
384+
}
385+
386+
TEST(graph_transformations, check_subgraphs_big_random) {
387+
const int num_vertices = 1000;
388+
const std::vector<float> vec1 = {2.0F, 1.5F, 0.1F, 1.9F, 0.0F, 5.5F};
389+
Tensor weights = make_tensor<float>(vec1, {3, 2});
390+
Tensor bias = make_tensor<float>({0.5F, 0.5F, 1.0F});
391+
Tensor input = make_tensor<float>({1.0F, 2.0F}, {2});
392+
Tensor output;
393+
Graph graph(num_vertices);
394+
Graph subgraph(3);
395+
std::vector<std::shared_ptr<Layer>> layers;
396+
for (int i = 0; i < num_vertices / 2; i++) {
397+
layers.push_back(std::make_shared<FCLayer>(weights, bias));
398+
}
399+
for (int i = 0; i < num_vertices / 2; i++) {
400+
layers.push_back(std::make_shared<EWLayer>("relu"));
401+
}
402+
graph.setInput(*layers[0], input);
403+
for (int i = 0; i < num_vertices; i++) {
404+
int rFirst = rand() % (num_vertices - 1);
405+
int rSecond = 1 + rand() % (num_vertices - 1);
406+
if ((rFirst == rSecond) ||
407+
((*layers[rFirst]).getID() == (*layers[rSecond]).getID()) &&
408+
((*layers[rFirst]).getID() != 0)) {
409+
continue;
410+
}
411+
if (((*layers[rFirst]).getID() >= graph.getLayersCount()) ||
412+
(rFirst != 0 && (*layers[rFirst]).getID() == 0)) {
413+
graph.addSingleLayer(*layers[rFirst]);
414+
}
415+
graph.makeConnection(*layers[rFirst], *layers[rSecond]);
416+
}
417+
graph.setOutput(*layers[num_vertices - 1], output);
418+
419+
subgraph.setInput(*layers[0], input);
420+
subgraph.makeConnection(*layers[0], *layers[50]);
421+
subgraph.makeConnection(*layers[50], *layers[1]);
422+
423+
std::vector<std::vector<int>> res1 = find_subgraphs(graph, subgraph);
424+
double res1_time =
425+
elapsed_time_avg<double, std::milli>(10, find_subgraphs, graph, subgraph);
426+
std::cerr << "Find subgraphs time in ms " << res1_time << std::endl;
341427
}

0 commit comments

Comments
 (0)