summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/assimilate.c')
-rw-r--r--src/core/assimilate.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/src/core/assimilate.c b/src/core/assimilate.c
new file mode 100644
index 0000000..eb6aa17
--- /dev/null
+++ b/src/core/assimilate.c
@@ -0,0 +1,232 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "../io/error.h"
+
+#include "knowledge.h"
+
+static int link_to
+(
+ ZoO_index links_count [const restrict static 1],
+ ZoO_index * links_occurrences [const restrict static 1],
+ ZoO_index * links [const restrict static 1],
+ ZoO_index const target
+)
+{
+ ZoO_index i, * new_p;
+
+ for (i = 0; i < *links_count; ++i)
+ {
+ if ((*links)[i] == target)
+ {
+ if ((*links_occurrences)[i] == ZoO_INDEX_MAX)
+ {
+ ZoO_S_WARNING
+ (
+ "Maximum link occurrences count has been reached."
+ );
+
+ return -1;
+ }
+
+ (*links_occurrences)[i] += 1;
+
+ return 0;
+ }
+ }
+
+ if (*links_count == ZoO_INDEX_MAX)
+ {
+ ZoO_S_WARNING("Maximum links count has been reached.");
+
+ return -1;
+ }
+
+ new_p =
+ (ZoO_index *) realloc
+ (
+ *links_occurrences,
+ (
+ (
+ /* Safe: *links_count < ZoO_INDEX_MAX */
+ (size_t) (*links_count + 1)
+ )
+ * sizeof(ZoO_index)
+ )
+ );
+
+ if (new_p == (ZoO_index *) NULL)
+ {
+ ZoO_S_ERROR("Could not reallocate a link occurrences list.");
+
+ return -1;
+ }
+
+ new_p[*links_count] = 1;
+
+ *links_occurrences = new_p;
+
+ new_p =
+ (ZoO_index *) realloc
+ (
+ *links,
+ (
+ (
+ /* Safe: *links_count < ZoO_INDEX_MAX */
+ (size_t) (*links_count + 1)
+ ) * sizeof(ZoO_index)
+ )
+ );
+
+ if (new_p == (ZoO_index *) NULL)
+ {
+ ZoO_S_ERROR("Could not reallocate a link list.");
+
+ return -1;
+ }
+
+ new_p[*links_count] = target;
+
+ *links = new_p;
+
+ *links_count += 1;
+
+ return 0;
+}
+
+static int link_words
+(
+ struct ZoO_knowledge k [const restrict static 1],
+ ZoO_index const a,
+ ZoO_index const b
+)
+{
+ int error;
+
+ error =
+ link_to
+ (
+ &(k->words[a].forward_links_count),
+ &(k->words[a].forward_links_occurrences),
+ &(k->words[a].forward_links),
+ b
+ );
+
+ error =
+ (
+ link_to
+ (
+ &(k->words[b].backward_links_count),
+ &(k->words[b].backward_links_occurrences),
+ &(k->words[b].backward_links),
+ a
+ )
+ | error
+ );
+
+ return error;
+}
+
+int ZoO_knowledge_assimilate
+(
+ struct ZoO_knowledge k [const static 1],
+ struct ZoO_strings string [const restrict static 1],
+ ZoO_index const aliases_count,
+ const char * restrict aliases [const restrict static aliases_count]
+)
+{
+ int error;
+ ZoO_index curr_word, next_word;
+ ZoO_index curr_word_id, next_word_id;
+
+ curr_word = 0;
+
+ if (string->words_count == 0)
+ {
+ return 0;
+ }
+
+ for (curr_word = 0; curr_word < aliases_count; ++curr_word)
+ {
+ if (ZoO_IS_PREFIX(aliases[curr_word], string->words[0]))
+ {
+ return 0;
+ }
+ }
+
+ curr_word = 0;
+
+ if (ZoO_knowledge_learn(k, string->words[curr_word], &curr_word_id) < 0)
+ {
+ return -1;
+ }
+
+ if (link_words(k, ZoO_WORD_START_OF_LINE, curr_word_id) < 0)
+ {
+ error = -1;
+
+ ZoO_WARNING
+ (
+ "Could not indicate that '"
+ ZoO_CHAR_STRING_SYMBOL
+ "' was the first word of the sentence.",
+ string->words[0]
+ );
+ }
+
+ next_word = 1;
+
+ error = 0;
+
+ while (next_word < string->words_count)
+ {
+ /* prevents words [restrict], k [restrict] */
+ if (ZoO_knowledge_learn(k, string->words[next_word], &next_word_id) < 0)
+ {
+ return -1;
+ }
+
+ if (link_words(k, curr_word_id, next_word_id) < 0)
+ {
+ error = -1;
+
+ ZoO_WARNING
+ (
+ "Could not add a link between words '"
+ ZoO_CHAR_STRING_SYMBOL
+ "' and '"
+ ZoO_CHAR_STRING_SYMBOL
+ "'.",
+ string->words[curr_word],
+ string->words[next_word]
+ );
+ }
+
+ curr_word = next_word;
+ curr_word_id = next_word_id;
+ /*
+ * Safe:
+ * - next_word < words_count
+ * - words_count =< ZoO_INDEX_MAX
+ * ----
+ * next_word < ZoO_INDEX_MAX
+ */
+ next_word += 1;
+ }
+
+ if (link_words(k, curr_word_id, ZoO_WORD_END_OF_LINE) < 0)
+ {
+ error = -1;
+
+ ZoO_WARNING
+ (
+ "Could not indicate that '"
+ ZoO_CHAR_STRING_SYMBOL
+ "' was the last word of the sentence.",
+ string->words[curr_word_id]
+ );
+ }
+
+ return error;
+}
+