1 /*
2  knowledge_graph.cpp     MindForger thinking notebook
3 
4  Copyright (C) 2016-2020 Martin Dvorak <martin.dvorak@mindforger.com>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License
8  as published by the Free Software Foundation; either version 2
9  of the License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "knowledge_graph.h"
20 
21 namespace m8r {
22 
23 using namespace std;
24 
25 /*
26  * Knowledge SUB graph
27  */
28 
KnowledgeSubGraph(KnowledgeGraphNode * centralNode,int maxSubgraphNodes)29 KnowledgeSubGraph::KnowledgeSubGraph(KnowledgeGraphNode* centralNode, int maxSubgraphNodes)
30     : centralNode(centralNode), maxSubgraphNodes(maxSubgraphNodes)
31 {
32     this->count = maxSubgraphNodes-1;
33 }
34 
35 /*
36  * Knowledge graph
37  */
38 
KnowledgeGraph(Mind * mind,long unsigned mindColor,long unsigned coreColor,long unsigned outlinesColor,long unsigned notesColor)39 KnowledgeGraph::KnowledgeGraph(
40         Mind* mind,
41         long unsigned mindColor,
42         long unsigned coreColor,
43         long unsigned outlinesColor,
44         long unsigned notesColor
45         )
46     : mind{mind}
47 {
48     mindNode = new KnowledgeGraphNode{KnowledgeGraphNodeType::MIND, "MIND", mindColor, 5};
49     tagsNode = new KnowledgeGraphNode{KnowledgeGraphNodeType::TAGS, "tags"};
50     outlinesNode = new KnowledgeGraphNode{KnowledgeGraphNodeType::OUTLINES, "notebooks"};
51     notesNode = new KnowledgeGraphNode{KnowledgeGraphNodeType::NOTES, "notes"};
52     //limboNode = new KnowledgeGraphNode{KnowledgeGraphNodeType::LIMBO, "limbo"};
53     //stencilsNode = new KnowledgeGraphNode{KnowledgeGraphNodeType::STENCILS, "stencils"};
54 
55     this->coreColor = coreColor;
56     this->outlinesColor = outlinesColor;
57     this->notesColor = notesColor;
58 }
59 
~KnowledgeGraph()60 KnowledgeGraph::~KnowledgeGraph()
61 {
62     delete mindNode;
63     delete tagsNode;
64     delete outlinesNode;
65     delete notesNode;
66     //delete limboNode;
67     //delete stencilsNode;
68 }
69 
getNode(KnowledgeGraphNodeType type)70 KnowledgeGraphNode* KnowledgeGraph::getNode(KnowledgeGraphNodeType type)
71 {
72     switch(type) {
73     case KnowledgeGraphNodeType::MIND:
74         return mindNode;
75     case KnowledgeGraphNodeType::OUTLINES:
76         return outlinesNode;
77     case KnowledgeGraphNodeType::NOTES:
78         return notesNode;
79     case KnowledgeGraphNodeType::TAGS:
80         return tagsNode;
81     /*
82     case KnowledgeGraphNodeType::STENCILS:
83         return stencilsNode;
84     case KnowledgeGraphNodeType::LIMBO:
85         return limboNode;
86     case KnowledgeGraphNodeType::STENCIL:
87     */
88     case KnowledgeGraphNodeType::OUTLINE:
89     case KnowledgeGraphNodeType::NOTE:
90     case KnowledgeGraphNodeType::TAG:
91         return nullptr;
92     }
93 
94     return nullptr;
95 }
96 
getNode(Outline * o)97 KnowledgeGraphNode* KnowledgeGraph::getNode(Outline* o)
98 {
99     KnowledgeGraphNode* k = new KnowledgeGraphNode{
100             KnowledgeGraphNodeType::OUTLINE,
101             o->getName(),
102             outlinesColor,
103             static_cast<unsigned int>(o->getNotesCount())};
104     k->setThing(o);
105 
106     return k;
107 }
108 
getNode(Note * n)109 KnowledgeGraphNode* KnowledgeGraph::getNode(Note* n)
110 {
111     KnowledgeGraphNode* k = new KnowledgeGraphNode{KnowledgeGraphNodeType::NOTE, n->getName(), notesColor};
112     k->setThing(n);
113     k->setCardinality(n->getOutline()->getDirectNoteChildrenCount(n));
114 
115     return k;
116 }
117 
118 // TODO this method leaks a lot - knowledge graph nodes
getRelatedNodes(KnowledgeGraphNode * centralNode,KnowledgeSubGraph & subgraph)119 void KnowledgeGraph::getRelatedNodes(KnowledgeGraphNode* centralNode, KnowledgeSubGraph& subgraph)
120 {
121     subgraph.clear();
122 
123     // refresh core nodes cardinalities
124     tagsNode->setCardinality(static_cast<unsigned int>(mind->getTags().size()));
125     outlinesNode->setCardinality(mind->remind().getOutlinesCount());
126     notesNode->setCardinality(mind->remind().getNotesCount());
127     //stencilsNode->setCardinality(static_cast<unsigned int>(mind->remind().getStencils().size()));
128     //limboNode->...
129 
130     // significant ontology things
131     if(centralNode == mindNode) {
132         subgraph.setCentralNode(mindNode);
133 
134         subgraph.addChild(tagsNode);
135         subgraph.addChild(outlinesNode);
136         subgraph.addChild(notesNode);
137         //subgraph.addChild(stencilsNode);
138         //subgraph.addChild(limboNode);
139 
140         return;
141     } else if(centralNode == outlinesNode) {
142         subgraph.setCentralNode(outlinesNode);
143 
144         const vector<Outline*>& outlines = mind->getOutlines();
145         if(outlines.size()) {
146             KnowledgeGraphNode* k;
147             for(Outline* o:outlines) {
148                 // TODO: reuse and delete - map<Thing*,Node*>
149                 k = new KnowledgeGraphNode{KnowledgeGraphNodeType::OUTLINE, o->getName(), outlinesColor, static_cast<unsigned int>(o->getNotesCount())};
150                 k->setThing(o);
151                 subgraph.addChild(k);
152             }
153         }
154 
155         subgraph.addParent(mindNode);
156 
157         return;
158     } else if(centralNode == notesNode) {
159         subgraph.setCentralNode(notesNode);
160 
161         // IMPROVE limit maximum number of Ns to be rendered - avoid MF trashing when rendering 1M of nodes
162         vector<Note*> notes{};
163         mind->getAllNotes(notes);
164         if(notes.size()) {
165             KnowledgeGraphNode* k;
166             std::vector<Note*> nc;
167             for(Note* n:notes) {
168                 // TODO: reuse and delete - map<Thing*,Node*>
169                 k = new KnowledgeGraphNode{KnowledgeGraphNodeType::NOTE, n->getName(), notesColor};
170                 k->setThing(n);
171                 k->setCardinality(n->getOutline()->getDirectNoteChildrenCount(n));
172                 subgraph.addChild(k);
173             }
174         }
175 
176         subgraph.addParent(mindNode);
177 
178         return;
179     } else if(centralNode == tagsNode) {
180         subgraph.setCentralNode(tagsNode);
181 
182         // IMPROVE iterate map, don't load tags
183         map<const Tag*,int> tagsCardinality{};
184         mind->getTagsCardinality(tagsCardinality);
185         KnowledgeGraphNode* n;
186         vector<const Tag*>& tags = mind->getTags().values();
187         for(const Tag* t:tags) {
188             // TODO: reuse and delete - map<Thing*,Node*>
189             n = new KnowledgeGraphNode{KnowledgeGraphNodeType::TAG, t->getName(), t->getColor().asLong(), static_cast<unsigned>(tagsCardinality[t])};
190             subgraph.addChild(n);
191         }
192 
193         subgraph.addParent(mindNode);
194 
195         return;
196     } else /* if(centralNode == stencilsNode) {
197         subgraph.setCentralNode(stencilsNode);
198 
199         subgraph.addParent(mindNode);
200 
201         return;
202     } else if(centralNode == limboNode) {
203         subgraph.setCentralNode(limboNode);
204 
205         subgraph.addParent(mindNode);
206 
207         return;
208     } */
209 
210     // things by type
211     if(centralNode->getType() == KnowledgeGraphNodeType::OUTLINE) {
212         subgraph.setCentralNode(centralNode);
213 
214         Outline* o = static_cast<Outline*>(centralNode->getThing());
215         KnowledgeGraphNode* k;
216         // child Ns only
217         vector<Note*> children{};
218         o->getDirectNoteChildren(children);
219         for(Note* n:children) {
220             // TODO: reuse and delete - map<Thing*,Node*>
221             k = new KnowledgeGraphNode{KnowledgeGraphNodeType::NOTE, n->getName(), notesColor};
222             k->setThing(n);
223             k->setCardinality(n->getOutline()->getDirectNoteChildrenCount(n));
224             subgraph.addChild(k);
225         }
226 
227         const std::vector<const Tag*>* tags = o->getTags();
228         for(const Tag* t:*tags) {
229             // TODO: reuse and delete - map<Thing*,Node*>
230             k = new KnowledgeGraphNode{KnowledgeGraphNodeType::TAG, t->getName(), t->getColor().asLong()};
231             subgraph.addChild(k);
232         }
233 
234         subgraph.addParent(outlinesNode);
235 
236         return;
237     } else if(centralNode->getType() == KnowledgeGraphNodeType::NOTE) {
238         subgraph.setCentralNode(centralNode);
239 
240         Note* n = static_cast<Note*>(centralNode->getThing());
241         KnowledgeGraphNode* k;
242         k = new KnowledgeGraphNode{KnowledgeGraphNodeType::OUTLINE, n->getOutline()->getName(), outlinesColor, static_cast<unsigned int>(n->getOutline()->getNotesCount())};
243         k->setThing(n->getOutline());
244         subgraph.addParent(k);
245 
246         // child Ns
247         vector<Note*> children{};
248         n->getOutline()->getDirectNoteChildren(n, children);
249         for(Note* n:children) {
250             // TODO: reuse and delete - map<Thing*,Node*>
251             k = new KnowledgeGraphNode{KnowledgeGraphNodeType::NOTE, n->getName(), notesColor};
252             k->setThing(n);
253             k->setCardinality(n->getOutline()->getDirectNoteChildrenCount(n));
254             subgraph.addChild(k);
255         }
256 
257         const std::vector<const Tag*>* tags = n->getTags();
258         for(const Tag* t:*tags) {
259             // TODO: reuse and delete - map<Thing*,Node*>
260             k = new KnowledgeGraphNode{KnowledgeGraphNodeType::TAG, t->getName(), t->getColor().asLong()};
261             subgraph.addChild(k);
262         }
263 
264         subgraph.addParent(notesNode);
265 
266         return;
267     } else if(centralNode->getType() == KnowledgeGraphNodeType::TAG) {
268         subgraph.setCentralNode(centralNode);
269 
270         vector<const Tag*> tags{};
271         tags.push_back(mind->getOntology().findOrCreateTag(centralNode->getName()));
272         // Os
273         vector<Outline*> outlines{};
274         mind->findOutlinesByTags(tags, outlines);
275         if(outlines.size()) {
276             KnowledgeGraphNode* k;
277             for(Outline* o:outlines) {
278                 // TODO: reuse and delete - map<Thing*,Node*>
279                 k = new KnowledgeGraphNode{KnowledgeGraphNodeType::OUTLINE, o->getName(), outlinesColor, static_cast<unsigned int>(o->getNotesCount())};
280                 k->setThing(o);
281                 subgraph.addChild(k);
282             }
283         }
284 
285         // Ns
286         vector<Note*> notes{};
287         mind->findNotesByTags(tags, notes);
288         if(notes.size()) {
289             KnowledgeGraphNode* k;
290             for(Note* n:notes) {
291                 // TODO: reuse and delete - map<Thing*,Node*>
292                 k = new KnowledgeGraphNode{KnowledgeGraphNodeType::NOTE, n->getName(), notesColor};
293                 k->setThing(n);
294                 k->setCardinality(n->getOutline()->getDirectNoteChildrenCount(n));
295                 subgraph.addChild(k);
296             }
297         }
298 
299         subgraph.addParent(tagsNode);
300 
301         return;
302     } /* else if(centralNode->getType() == KnowledgeGraphNodeType::STENCIL) {
303         subgraph.setCentralNode(centralNode);
304 
305         subgraph.addParent(stencilsNode);
306 
307         return;
308     } */
309 }
310 
311 } // m8r namespace
312