blob: 9d073a4cddd1df92a152b5d41b5549038a19c3ca [file] [log] [blame]
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001#include <collocatordb.h>
Marc Kupietz969cab92019-08-05 11:13:42 +02002#include <math.h>
3#include <pthread.h>
4#include <stdio.h>
Marc Kupietzc0d41872021-02-25 16:33:22 +01005#include <stdlib.h>
Marc Kupietz969cab92019-08-05 11:13:42 +02006#include <string.h>
7#include <sys/mman.h>
Marc Kupietze288d8e2024-11-15 16:18:50 +01008#include <fcntl.h>
9#include <unistd.h>
10#include <perl.h>
Marc Kupietzf11d20c2019-08-02 15:42:04 +020011
12#define max_size 2000
13#define max_w 50
14#define MAX_NEIGHBOURS 1000
15#define MAX_WORDS -1
16#define MAX_THREADS 100
17#define MAX_CC 50
18#define EXP_TABLE_SIZE 1000
19#define MAX_EXP 6
20#define MIN_RESP 0.50
21
22//the thread function
23void *connection_handler(void *);
24
25typedef struct {
Marc Kupietz969cab92019-08-05 11:13:42 +020026 long long wordi;
27 long position;
28 float activation;
29 float average;
30 float cprobability; // column wise probability
31 float cprobability_sum;
32 float probability;
33 float activation_sum;
34 float max_activation;
35 float heat[16];
Marc Kupietzf11d20c2019-08-02 15:42:04 +020036} collocator;
37
38typedef struct {
Marc Kupietz969cab92019-08-05 11:13:42 +020039 collocator *best;
40 int length;
Marc Kupietzf11d20c2019-08-02 15:42:04 +020041} knn;
Marc Kupietz969cab92019-08-05 11:13:42 +020042
Marc Kupietzf11d20c2019-08-02 15:42:04 +020043typedef struct {
44 long long wordi[MAX_NEIGHBOURS];
45 char sep[MAX_NEIGHBOURS];
46 int length;
47} wordlist;
48
49typedef struct {
50 long cutoff;
51 wordlist *wl;
Marc Kupietz969cab92019-08-05 11:13:42 +020052 char *token;
53 int N;
54 long from;
55 unsigned long upto;
Marc Kupietzf11d20c2019-08-02 15:42:04 +020056 collocator *best;
57 float *target_sums;
58 float *window_sums;
59 float threshold;
60} knnpars;
61
62typedef struct {
63 uint32_t index;
64 float value;
65} sparse_t;
66
67typedef struct {
68 uint32_t len;
69 sparse_t nbr[100];
70} profile_t;
71
Marc Kupietz969cab92019-08-05 11:13:42 +020072float *M, *M2 = 0L, *syn1neg_window, *expTable;
Marc Kupietzf11d20c2019-08-02 15:42:04 +020073char *vocab;
74char *garbage = NULL;
75COLLOCATORDB *cdb = NULL;
76profile_t *sprofiles = NULL;
77size_t sprofiles_qty = 0;
78
79long long words, size, merged_end;
80long long merge_words = 0;
Marc Kupietz969cab92019-08-05 11:13:42 +020081int num_threads = 20;
82int latin_enc = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +020083int window;
84
85/* load collocation profiles if file exists */
86int load_sprofiles(char *vecsname) {
87 char *basename = strdup(vecsname);
88 char *pos = strstr(basename, ".vecs");
Marc Kupietz969cab92019-08-05 11:13:42 +020089 if (pos)
90 *pos = 0;
91
Marc Kupietzf11d20c2019-08-02 15:42:04 +020092 char binsprofiles_fname[256];
93 strcpy(binsprofiles_fname, basename);
Marc Kupietz969cab92019-08-05 11:13:42 +020094 strcat(binsprofiles_fname, ".sprofiles.bin");
Marc Kupietzf11d20c2019-08-02 15:42:04 +020095 FILE *fp = fopen(binsprofiles_fname, "rb");
96 if (fp == NULL) {
97 printf("Collocation profiles %s not found. No problem.\n", binsprofiles_fname);
98 return 0;
99 }
100 fseek(fp, 0L, SEEK_END);
101 size_t sz = ftell(fp);
102 fclose(fp);
103
104 int fd = open(binsprofiles_fname, O_RDONLY);
Marc Kupietz969cab92019-08-05 11:13:42 +0200105 sprofiles = mmap(0, sz, PROT_READ, MAP_SHARED, fd, 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200106 if (sprofiles == MAP_FAILED) {
107 close(fd);
108 fprintf(stderr, "Cannot mmap %s\n", binsprofiles_fname);
109 sprofiles = NULL;
110 return 0;
Marc Kupietz969cab92019-08-05 11:13:42 +0200111 } else {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200112 sprofiles_qty = sz / sizeof(profile_t);
113 fprintf(stderr, "Successfully mmaped %s containing similar profiles for %ld word forms.\n", binsprofiles_fname, sprofiles_qty);
114 }
115 return 1;
116}
117
Marc Kupietzc0d41872021-02-25 16:33:22 +0100118char *removeExtension(char* myStr) {
119 char *retStr;
120 char *lastExt;
121 if (myStr == NULL) return NULL;
122 if ((retStr = malloc (strlen (myStr) + 1)) == NULL) return NULL;
123 strcpy (retStr, myStr);
124 lastExt = strrchr (retStr, '.');
125 if (lastExt != NULL)
126 *lastExt = '\0';
127 return retStr;
128}
129
Marc Kupietz0efe49b2020-04-06 18:30:22 +0200130int init_net(char *file_name, char *net_name, int latin, int do_open_cdb) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200131 FILE *f, *binvecs, *binwords;
Marc Kupietz969cab92019-08-05 11:13:42 +0200132 int binwords_fd, binvecs_fd, net_fd, i;
Marc Kupietz59865a92021-03-11 17:16:51 +0100133 long long a, b;
Marc Kupietz969cab92019-08-05 11:13:42 +0200134 float len;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200135 double val;
136
Marc Kupietzc0d41872021-02-25 16:33:22 +0100137 char binvecs_fname[1024], binwords_fname[1024];
138
139 if (strstr(file_name, ".txt")) {
140 strcpy(binwords_fname, removeExtension(file_name));
141 } else {
142 strcpy(binwords_fname, file_name);
143 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200144 strcat(binwords_fname, ".words");
145 strcpy(binvecs_fname, file_name);
146 strcat(binvecs_fname, ".vecs");
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200147
148 latin_enc = latin;
149 f = fopen(file_name, "rb");
150 if (f == NULL) {
151 printf("Input file %s not found\n", file_name);
152 return -1;
153 }
154 fscanf(f, "%lld", &words);
Marc Kupietz969cab92019-08-05 11:13:42 +0200155 if (MAX_WORDS > 0 && words > MAX_WORDS) words = MAX_WORDS;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200156 fscanf(f, "%lld", &size);
Marc Kupietz969cab92019-08-05 11:13:42 +0200157 if ((binvecs_fd = open(binvecs_fname, O_RDONLY)) < 0 || (binwords_fd = open(binwords_fname, O_RDONLY)) < 0) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200158 printf("Converting %s to memory mappable structures\n", file_name);
Marc Kupietz969cab92019-08-05 11:13:42 +0200159 vocab = (char *)malloc((long long)words * max_w * sizeof(char));
160 M = (float *)malloc((long long)words * (long long)size * sizeof(float));
161 if (M == NULL) {
162 printf("Cannot allocate memory: %lld MB %lld %lld\n", (long long)words * size * sizeof(float) / 1048576, words, size);
163 return -1;
164 }
165 if (strstr(file_name, ".txt")) {
Marc Kupietzc0d41872021-02-25 16:33:22 +0100166 printf("%lld words in ascii vector file with vector size %lld\n", words, size);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200167 for (b = 0; b < words; b++) {
168 a = 0;
169 while (1) {
170 vocab[b * max_w + a] = fgetc(f);
171 if (feof(f) || (vocab[b * max_w + a] == ' ')) break;
172 if ((a < max_w) && (vocab[b * max_w + a] != '\n')) a++;
173 }
174 vocab[b * max_w + a] = 0;
175 len = 0;
176 for (a = 0; a < size; a++) {
177 fscanf(f, "%lf", &val);
178 M[a + b * size] = val;
179 len += val * val;
Marc Kupietz969cab92019-08-05 11:13:42 +0200180 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200181 len = sqrt(len);
182 for (a = 0; a < size; a++) M[a + b * size] /= len;
183 }
184 } else {
185 for (b = 0; b < words; b++) {
186 a = 0;
187 while (1) {
188 vocab[b * max_w + a] = fgetc(f);
189 if (feof(f) || (vocab[b * max_w + a] == ' ')) break;
190 if ((a < max_w) && (vocab[b * max_w + a] != '\n')) a++;
191 }
192 vocab[b * max_w + a] = 0;
193 fread(&M[b * size], sizeof(float), size, f);
194 len = 0;
195 for (a = 0; a < size; a++) len += M[a + b * size] * M[a + b * size];
196 len = sqrt(len);
197 for (a = 0; a < size; a++) M[a + b * size] /= len;
198 }
199 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200200 if ((binvecs = fopen(binvecs_fname, "wb")) != NULL && (binwords = fopen(binwords_fname, "wb")) != NULL) {
201 fwrite(M, sizeof(float), (long long)words * (long long)size, binvecs);
202 fclose(binvecs);
203 fwrite(vocab, sizeof(char), (long long)words * max_w, binwords);
204 fclose(binwords);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200205 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200206 }
207 if ((binvecs_fd = open(binvecs_fname, O_RDONLY)) >= 0 && (binwords_fd = open(binwords_fname, O_RDONLY)) >= 0) {
208 M = mmap(0, sizeof(float) * (long long)words * (long long)size, PROT_READ, MAP_SHARED, binvecs_fd, 0);
209 vocab = mmap(0, sizeof(char) * (long long)words * max_w, PROT_READ, MAP_SHARED, binwords_fd, 0);
210 if (M == MAP_FAILED || vocab == MAP_FAILED) {
211 close(binvecs_fd);
212 close(binwords_fd);
213 fprintf(stderr, "Cannot mmap %s or %s\n", binwords_fname, binvecs_fname);
214 exit(-1);
215 }
216 } else {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200217 fprintf(stderr, "Cannot open %s or %s\n", binwords_fname, binvecs_fname);
218 exit(-1);
Marc Kupietz969cab92019-08-05 11:13:42 +0200219 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200220 fclose(f);
221
Marc Kupietz969cab92019-08-05 11:13:42 +0200222 if (net_name && strlen(net_name) > 0) {
223 if ((net_fd = open(net_name, O_RDONLY)) >= 0) {
224 window = (lseek(net_fd, 0, SEEK_END) - sizeof(float) * words * size) / words / size / sizeof(float) / 2;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200225 // lseek(net_fd, sizeof(float) * words * size, SEEK_SET);
226 // munmap(M, sizeof(float) * words * size);
227 M2 = mmap(0, sizeof(float) * words * size + sizeof(float) * 2 * window * size * words, PROT_READ, MAP_SHARED, net_fd, 0);
228 if (M2 == MAP_FAILED) {
229 close(net_fd);
230 fprintf(stderr, "Cannot mmap %s\n", net_name);
231 exit(-1);
232 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200233 syn1neg_window = M2 + words * size;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200234 } else {
235 fprintf(stderr, "Cannot open %s\n", net_name);
236 exit(-1);
237 }
238 fprintf(stderr, "Successfully memmaped %s. Determined window size: %d\n", net_name, window);
239
Marc Kupietz0efe49b2020-04-06 18:30:22 +0200240 if (do_open_cdb) {
241 char collocatordb_name[2048];
242 strcpy(collocatordb_name, net_name);
243 char *ext = rindex(collocatordb_name, '.');
244 if (ext) {
245 strcpy(ext, ".rocksdb");
246 if (access(collocatordb_name, R_OK) == 0) {
247 *ext = 0;
248 fprintf(stderr, "Opening collocator DB %s\n", collocatordb_name);
249 cdb = open_collocatordb(collocatordb_name);
Marc Kupietzc0d41872021-02-25 16:33:22 +0100250 } else {
251 fprintf(stderr, "Cannot open collocator DB %s\n", collocatordb_name);
Marc Kupietz0efe49b2020-04-06 18:30:22 +0200252 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200253 }
254 }
255 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200256
Marc Kupietz969cab92019-08-05 11:13:42 +0200257 expTable = (float *)malloc((EXP_TABLE_SIZE + 1) * sizeof(float));
258 for (i = 0; i < EXP_TABLE_SIZE; i++) {
259 expTable[i] = exp((i / (float)EXP_TABLE_SIZE * 2 - 1) * MAX_EXP); // Precompute the exp() table
260 expTable[i] = expTable[i] / (expTable[i] + 1); // Precompute f(x) = x / (x + 1)
261 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200262
263 return 0;
264}
265
Marc Kupietzd6a163c2026-07-30 14:48:10 +0900266/* The collocator threads of one request accumulate their activation sums per
267 window position here. This must not be shared between requests, so every
268 request allocates its own array. Only valid once init_net() has determined
269 the window size, i.e. if M2 is set. */
270float *new_window_sums() {
271 return calloc((window + 1) * 2, sizeof(float));
272}
273
Marc Kupietz969cab92019-08-05 11:13:42 +0200274long mergeVectors(char *file_name) {
Marc Kupietz59865a92021-03-11 17:16:51 +0100275 FILE *f;
276 int binwords_fd, binvecs_fd;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200277 float *merge_vecs;
278 char *merge_vocab;
Marc Kupietz969cab92019-08-05 11:13:42 +0200279 /* long long merge_words, merge_size; */
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200280 long long merge_size;
281
Marc Kupietz969cab92019-08-05 11:13:42 +0200282 char binvecs_fname[256], binwords_fname[256];
Marc Kupietzc0d41872021-02-25 16:33:22 +0100283
284
Marc Kupietz969cab92019-08-05 11:13:42 +0200285 strcpy(binwords_fname, file_name);
286 strcat(binwords_fname, ".words");
287 strcpy(binvecs_fname, file_name);
288 strcat(binvecs_fname, ".vecs");
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200289
290 f = fopen(file_name, "rb");
291 if (f == NULL) {
292 printf("Input file %s not found\n", file_name);
Marc Kupietz59865a92021-03-11 17:16:51 +0100293 exit(-1);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200294 }
295 fscanf(f, "%lld", &merge_words);
296 fscanf(f, "%lld", &merge_size);
Marc Kupietz969cab92019-08-05 11:13:42 +0200297 if (merge_size != size) {
298 fprintf(stderr, "vectors must have the same length\n");
299 exit(-1);
300 }
301 if ((binvecs_fd = open(binvecs_fname, O_RDONLY)) >= 0 && (binwords_fd = open(binwords_fname, O_RDONLY)) >= 0) {
302 merge_vecs = malloc(sizeof(float) * (words + merge_words) * size);
303 merge_vocab = malloc(sizeof(char) * (words + merge_words) * max_w);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200304 if (merge_vecs == NULL || merge_vocab == NULL) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200305 close(binvecs_fd);
306 close(binwords_fd);
307 fprintf(stderr, "Cannot reserve memory for %s or %s\n", binwords_fname, binvecs_fname);
308 exit(-1);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200309 }
310 read(binvecs_fd, merge_vecs, merge_words * size * sizeof(float));
311 read(binwords_fd, merge_vocab, merge_words * max_w);
Marc Kupietz969cab92019-08-05 11:13:42 +0200312 } else {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200313 fprintf(stderr, "Cannot open %s or %s\n", binwords_fname, binvecs_fname);
314 exit(-1);
Marc Kupietz969cab92019-08-05 11:13:42 +0200315 }
316 printf("Successfully reallocated memory\nMerging...\n");
317 fflush(stdout);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200318 memcpy(merge_vecs + merge_words * size, M, words * size * sizeof(float));
319 memcpy(merge_vocab + merge_words * max_w, vocab, words * max_w);
320 munmap(M, words * size * sizeof(float));
321 munmap(vocab, words * max_w);
322 M = merge_vecs;
323 vocab = merge_vocab;
324 merged_end = merge_words;
325 words += merge_words;
326 fclose(f);
Marc Kupietz969cab92019-08-05 11:13:42 +0200327 printf("merged_end: %lld, words: %lld\n", merged_end, words);
328 //printBiggestMergedDifferences();
329 return ((long)merged_end);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200330}
331
332void filter_garbage() {
333 long i;
334 unsigned char *w, previous, c;
335 garbage = malloc(words);
336 memset(garbage, 0, words);
337 for (i = 0; i < words; i++) {
Marc Kupietz59865a92021-03-11 17:16:51 +0100338 w = (unsigned char *) vocab + i * max_w;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200339 previous = 0;
Marc Kupietz59865a92021-03-11 17:16:51 +0100340 if (strncmp("quot", (const char *)w, 4) == 0) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200341 garbage[i] = 1;
342 // printf("Gargabe: %s\n", vocab + i * max_w);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200343 } else {
Marc Kupietz969cab92019-08-05 11:13:42 +0200344 while ((c = *w++) && !garbage[i]) {
345 if (((c <= 90 && c >= 65) && (previous >= 97 && previous <= 122)) ||
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200346 (previous == '-' && (c & 32)) ||
Marc Kupietz969cab92019-08-05 11:13:42 +0200347 (previous == 0xc2 && (c == 0xa4 || c == 0xb6)) ||
348 (previous == 'q' && c == 'u' && *(w) == 'o' && *(w + 1) == 't') || /* quot */
349 c == '<') {
350 garbage[i] = 1;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200351 continue;
352 }
353 previous = c;
354 }
355 }
356 }
357 return;
358}
359
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200360knn *simpleGetCollocators(int word, int number, long cutoff, int *result) {
361 knnpars *pars = calloc(sizeof(knnpars), 1);
Marc Kupietz59865a92021-03-11 17:16:51 +0100362 float *target_sums = NULL;
363 float *my_window_sums = malloc(sizeof(float) * (window + 1) * 2);
Marc Kupietz969cab92019-08-05 11:13:42 +0200364 pars->cutoff = (cutoff ? cutoff : 300000);
Marc Kupietz59865a92021-03-11 17:16:51 +0100365 long a;
Marc Kupietz969cab92019-08-05 11:13:42 +0200366 for (a = 0; a < cutoff; a++)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200367 target_sums[a] = 0;
368 pars->target_sums = target_sums;
Marc Kupietz59865a92021-03-11 17:16:51 +0100369 pars->window_sums = my_window_sums;
Marc Kupietz969cab92019-08-05 11:13:42 +0200370 pars->N = (number ? number : 20);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200371 pars->from = 0;
Marc Kupietz969cab92019-08-05 11:13:42 +0200372 pars->upto = window * 2 - 1;
373 knn *syn_nbs = NULL; // = (knn*) getCollocators(pars);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200374 free(pars);
Marc Kupietz59865a92021-03-11 17:16:51 +0100375 free(my_window_sums);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200376 free(target_sums);
377 return syn_nbs;
378}
379
Marc Kupietz04135302026-07-30 14:40:02 +0900380/* Frees a knn result as returned by getCollocators() via pthread_exit(). */
381void free_knn(knn *nbs) {
382 if (nbs == NULL)
383 return;
384 free(nbs->best);
385 free(nbs);
386}
387
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200388void *getCollocators(void *args) {
389 knnpars *pars = args;
Marc Kupietz969cab92019-08-05 11:13:42 +0200390 int N = pars->N;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200391
392 int cc = pars->wl->wordi[0];
Marc Kupietz969cab92019-08-05 11:13:42 +0200393 knn *nbs = NULL;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200394 long window_layer_size = size * window * 2;
Marc Kupietz59865a92021-03-11 17:16:51 +0100395 long a, b, c, d, window_offset, target, max_target = 0, maxmax_target;
Marc Kupietz969cab92019-08-05 11:13:42 +0200396 float f, max_f, maxmax_f;
397 float *target_sums = NULL, worstbest, wpos_sum;
398 collocator *best;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200399
Marc Kupietz969cab92019-08-05 11:13:42 +0200400 if (M2 == NULL || cc == -1)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200401 return NULL;
402
Marc Kupietz969cab92019-08-05 11:13:42 +0200403 a = posix_memalign((void **)&target_sums, 128, pars->cutoff * sizeof(float));
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200404 memset(target_sums, 0, pars->cutoff * sizeof(float));
Marc Kupietz969cab92019-08-05 11:13:42 +0200405 best = malloc((N > 200 ? N : 200) * sizeof(collocator));
406 memset(best, 0, (N > 200 ? N : 200) * sizeof(collocator));
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200407 worstbest = pars->threshold;
408
409 for (b = 0; b < pars->cutoff; b++)
Marc Kupietz969cab92019-08-05 11:13:42 +0200410 target_sums[b] = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200411 for (b = 0; b < N; b++) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200412 best[b].wordi = -1;
413 best[b].probability = 1;
414 best[b].activation = worstbest;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200415 }
416
417 d = cc;
418 maxmax_f = -1;
419 maxmax_target = 0;
420
421 for (a = pars->from; a < pars->upto; a++) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200422 if (a >= window)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200423 a++;
424 wpos_sum = 0;
425 printf("window pos: %ld\n", a);
426 if (a != window) {
427 max_f = -1;
428 window_offset = a * size;
429 if (a > window)
430 window_offset -= size;
Marc Kupietz969cab92019-08-05 11:13:42 +0200431 for (target = 0; target < pars->cutoff; target++) {
432 if (garbage && garbage[target]) continue;
433 if (target == d)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200434 continue;
435 f = 0;
436 for (c = 0; c < size; c++)
Marc Kupietz969cab92019-08-05 11:13:42 +0200437 f += M2[d * size + c] * syn1neg_window[target * window_layer_size + window_offset + c];
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200438 if (f < -MAX_EXP)
439 continue;
440 else if (f > MAX_EXP)
441 continue;
442 else
Marc Kupietz969cab92019-08-05 11:13:42 +0200443 f = expTable[(int)((f + MAX_EXP) * (EXP_TABLE_SIZE / MAX_EXP / 2))];
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200444 wpos_sum += f;
445
446 target_sums[target] += f;
Marc Kupietz969cab92019-08-05 11:13:42 +0200447 if (f > worstbest) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200448 for (b = 0; b < N; b++) {
449 if (f > best[b].activation) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200450 memmove(best + b + 1, best + b, (N - b - 1) * sizeof(collocator));
451 best[b].activation = f;
452 best[b].wordi = target;
453 best[b].position = window - a;
454 break;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200455 }
456 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200457 if (b == N - 1)
458 worstbest = best[N - 1].activation;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200459 }
460 }
Marc Kupietz59865a92021-03-11 17:16:51 +0100461 printf("%ld %.2f\n", max_target, max_f);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200462 printf("%s (%.2f) ", &vocab[max_target * max_w], max_f);
Marc Kupietz969cab92019-08-05 11:13:42 +0200463 if (max_f > maxmax_f) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200464 maxmax_f = max_f;
465 maxmax_target = max_target;
466 }
467 for (b = 0; b < N; b++)
Marc Kupietz969cab92019-08-05 11:13:42 +0200468 if (best[b].position == window - a)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200469 best[b].cprobability = best[b].activation / wpos_sum;
470 } else {
Marc Kupietz969cab92019-08-05 11:13:42 +0200471 printf("\x1b[1m%s\x1b[0m ", &vocab[d * max_w]);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200472 }
473 pars->window_sums[a] = wpos_sum;
474 }
475 for (b = 0; b < pars->cutoff; b++)
Marc Kupietz969cab92019-08-05 11:13:42 +0200476 pars->target_sums[b] += target_sums[b]; //(target_sums[b] / wpos_sum ) / (window * 2);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200477
478 free(target_sums);
Marc Kupietz969cab92019-08-05 11:13:42 +0200479 for (b = 0; b < N && best[b].wordi >= 0; b++)
480 ;
Marc Kupietz59865a92021-03-11 17:16:51 +0100481 // THIS LOOP IS NEEDED (b...)
Marc Kupietz969cab92019-08-05 11:13:42 +0200482 // printf("%d: best syn: %s %.2f %.5f\n", b, &vocab[best[b].wordi*max_w], best[b].activation, best[b].probability);
483 // printf("\n");
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200484 nbs = malloc(sizeof(knn));
Marc Kupietz969cab92019-08-05 11:13:42 +0200485 nbs->best = best;
486 nbs->length = b - 1;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200487 pthread_exit(nbs);
488}
489
Marc Kupietz0efe49b2020-04-06 18:30:22 +0200490float getOutputWeight(int hidden, long target, int window_position) {
491 const long window_layer_size = size * window * 2;
492 int a;
493
494 if (window_position == 0 || window_position > window || window_position < -window) {
495 fprintf(stderr, "window_position: %d - assert: -%d <= window_position <= %d && window_position != 0 failed.\n", window_position, window, window);
496 exit(-1);
497 }
498
499 if (hidden >= size) {
Marc Kupietz59865a92021-03-11 17:16:51 +0100500 fprintf(stderr, "hidden: %d - assert: hidden < %lld failed.\n", hidden, size);
Marc Kupietz0efe49b2020-04-06 18:30:22 +0200501 exit(-1);
502 }
503
504 if (target >= words) {
Marc Kupietz59865a92021-03-11 17:16:51 +0100505 fprintf(stderr, "target: %ld - assert: target < %lld failed.\n", target, words);
Marc Kupietz0efe49b2020-04-06 18:30:22 +0200506 exit(-1);
507 }
508
509 a = window_position + window;
510 if (a > window) {
511 --a;
512 }
513 long window_offset = a * size;
514 return syn1neg_window[target * window_layer_size + window_offset + hidden];
515}
516
Marc Kupietz04135302026-07-30 14:40:02 +0900517/* Returns an SV* (not an AV*) on purpose: for an AV* return value Inline::C
518 generates newRV(), which leaves the array itself with a reference count of
519 one after the mortal reference is gone, i.e. it leaks the whole array on
520 every call. */
521SV *getVecs(AV *array) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200522 int i, b;
523 AV *result = newAV();
Marc Kupietz969cab92019-08-05 11:13:42 +0200524 for (i = 0; i <= av_len(array); i++) {
525 SV **elem = av_fetch(array, i, 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200526 if (elem != NULL) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200527 long j = (long)SvNV(*elem);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200528 AV *vector = newAV();
529 for (b = 0; b < size; b++) {
530 av_push(vector, newSVnv(M[b + j * size]));
531 }
Marc Kupietzbdd779a2024-08-05 10:02:29 +0200532 av_push(result, newRV_noinc((SV *)vector));
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200533 }
534 }
Marc Kupietz04135302026-07-30 14:40:02 +0900535 return newRV_noinc((SV *)result);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200536}
537
Marc Kupietz04135302026-07-30 14:40:02 +0900538/* All functions handing a string back to perl return an SV*, because for a
539 char* return value Inline::C only copies the string into the return SV and
540 never frees the buffer we allocated here. */
541SV *getSimilarProfiles(long node) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200542 int i;
543 char buffer[120000];
544 char pair_buffer[2048];
Marc Kupietz969cab92019-08-05 11:13:42 +0200545 buffer[0] = '[';
546 buffer[1] = 0;
547 if (node >= sprofiles_qty) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200548 printf("Not available in precomputed profile\n");
Marc Kupietz04135302026-07-30 14:40:02 +0900549 return newSVpv("[{\"w\":\"not available\", \"v\":0}]\n", 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200550 }
551
552 printf("******* %s ******\n", &vocab[max_w * node]);
Marc Kupietz969cab92019-08-05 11:13:42 +0200553
554 for (i = 0; i < 100 && i < sprofiles[node].len; i++) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200555 sprintf(pair_buffer, "{\"w\":\"%s\", \"v\":%f},", &vocab[max_w * (sprofiles[node].nbr[i].index)], sprofiles[node].nbr[i].value);
556 strcat(buffer, pair_buffer);
557 }
Marc Kupietz04135302026-07-30 14:40:02 +0900558 if (i > 0)
559 buffer[strlen(buffer) - 1] = ']';
560 else
561 strcat(buffer, "]");
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200562 strcat(buffer, "\n");
Marc Kupietz59865a92021-03-11 17:16:51 +0100563 printf("%s", buffer);
Marc Kupietz04135302026-07-30 14:40:02 +0900564 return newSVpv(buffer, 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200565}
566
Marc Kupietz04135302026-07-30 14:40:02 +0900567/* get_collocat*_as_json() hand out strdup()ed buffers that we own. */
568SV *getCollocationScores(long node, long collocate) {
569 char *json = (cdb ? (char *)get_collocation_scores_as_json(cdb, node, collocate) : NULL);
570 SV *res = newSVpv(json ? json : "[]", 0);
571 free(json);
572 return res;
Marc Kupietzf6080012021-03-12 09:14:42 +0100573}
574
Marc Kupietz04135302026-07-30 14:40:02 +0900575SV *getClassicCollocators(long node) {
576 char *json = (cdb ? (char *)get_collocators_as_json(cdb, node) : NULL);
577 SV *res = newSVpv(json ? json : "[]", 0);
578 free(json);
Marc Kupietz969cab92019-08-05 11:13:42 +0200579 return res;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200580}
581
582wordlist *getTargetWords(char *st1, int search_backw) {
583 wordlist *wl = malloc(sizeof(wordlist));
Marc Kupietz59865a92021-03-11 17:16:51 +0100584 char st[100][max_size];
Marc Kupietz969cab92019-08-05 11:13:42 +0200585 long a, b = 0, c = 0, cn = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200586
587 while (1) {
588 st[cn][b] = st1[c];
589 b++;
590 c++;
591 st[cn][b] = 0;
592 if (st1[c] == 0) break;
Marc Kupietzc0d41872021-02-25 16:33:22 +0100593 if (st1[c] == ' ' /*|| st1[c] == '-'*/) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200594 b = 0;
595 c++;
596 }
597 }
598 cn++;
599 for (a = 0; a < cn; a++) {
600 if (search_backw) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200601 for (b = words - 1; b >= (merge_words ? merge_words : 0) && strcmp(&vocab[b * max_w], st[a]) != 0; b--)
602 ;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200603 } else {
Marc Kupietz969cab92019-08-05 11:13:42 +0200604 for (b = 0; b < (merge_words ? merge_words : words) && strcmp(&vocab[b * max_w], st[a]) != 0; b++)
605 ;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200606 }
607 if (b == words) b = -1;
608 wl->wordi[a] = b;
609 if (b == -1) {
610 fprintf(stderr, "Out of dictionary word!\n");
611 cn--;
612 } else {
Marc Kupietz969cab92019-08-05 11:13:42 +0200613 fprintf(stderr, "Word: \"%s\" Position in vocabulary: %lld\n", &vocab[wl->wordi[a] * max_w], wl->wordi[a]);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200614 }
615 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200616 wl->length = cn;
617 return (wl);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200618}
619
Marc Kupietzcb43e492019-12-03 10:07:53 +0100620long getWordNumber(char *word) {
621 wordlist *wl = getTargetWords(word, 0);
Marc Kupietz04135302026-07-30 14:40:02 +0900622 long res = 0;
623 if (wl == NULL)
624 return(0);
Marc Kupietzcb43e492019-12-03 10:07:53 +0100625 if(wl->length > 0)
Marc Kupietz04135302026-07-30 14:40:02 +0900626 res = wl->wordi[0];
627 free(wl);
628 return(res);
Marc Kupietzcb43e492019-12-03 10:07:53 +0100629}
630
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200631float get_distance(long b, long c) {
632 long a;
633 float dist = 0;
634 for (a = 0; a < size; a++) dist += M[a + c * size] * M[a + b * size];
635 return dist;
636}
637
Marc Kupietz04135302026-07-30 14:40:02 +0900638/* The result is computed once and then kept in a static buffer for the
639 lifetime of the process. */
640SV *getBiggestMergedDifferences() {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200641 static char *result = NULL;
Marc Kupietz59865a92021-03-11 17:16:51 +0100642 float dist;
643 long long a, c;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200644 int N = 1000;
645
Marc Kupietz969cab92019-08-05 11:13:42 +0200646 if (merged_end == 0)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200647 result = "[]";
Marc Kupietz969cab92019-08-05 11:13:42 +0200648
649 if (result != NULL)
Marc Kupietz04135302026-07-30 14:40:02 +0900650 return newSVpv(result, 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200651
652 printf("Looking for biggest distances between main and merged vectors ...\n");
653 collocator *best;
654 best = malloc(N * sizeof(collocator));
655 memset(best, 0, N * sizeof(collocator));
656
Marc Kupietz969cab92019-08-05 11:13:42 +0200657 float worstbest = 1000000;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200658
659 for (a = 0; a < N; a++) best[a].activation = worstbest;
660
661 for (c = 0; c < 500000; c++) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200662 if (garbage && garbage[c]) continue;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200663 dist = 0;
Marc Kupietz969cab92019-08-05 11:13:42 +0200664 for (a = 0; a < size; a++) dist += M[a + c * size] * M[a + (c + merged_end) * size];
665 if (dist < worstbest) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200666 for (a = 0; a < N; a++) {
667 if (dist < best[a].activation) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200668 memmove(best + a + 1, best + a, (N - a - 1) * sizeof(collocator));
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200669 best[a].activation = dist;
670 best[a].wordi = c;
671 break;
672 }
673 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200674 worstbest = best[N - 1].activation;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200675 }
676 }
677
Marc Kupietz04135302026-07-30 14:40:02 +0900678 result = malloc(N * (max_w + 64));
Marc Kupietzbdd779a2024-08-05 10:02:29 +0200679 char *p = (char *) result;
Marc Kupietz969cab92019-08-05 11:13:42 +0200680 *p++ = '[';
681 *p = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200682 for (a = 0; a < N; a++) {
Marc Kupietz59865a92021-03-11 17:16:51 +0100683 p += sprintf(p, "{\"rank\":%lld,\"word\":\"%s\",\"dist\":%.3f},", a, &vocab[best[a].wordi * max_w], 1 - best[a].activation);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200684 }
685 *--p = ']';
Marc Kupietz04135302026-07-30 14:40:02 +0900686 free(best);
687 return newSVpv(result, 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200688}
689
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200690float cos_similarity(long b, long c) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200691 float dist = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200692 long a;
Marc Kupietz969cab92019-08-05 11:13:42 +0200693 for (a = 0; a < size; a++) dist += M[b * size + a] * M[c * size + a];
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200694 return dist;
695}
696
Marc Kupietz04135302026-07-30 14:40:02 +0900697SV *cos_similarity_as_json(char *w1, char *w2) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200698 wordlist *a, *b;
699 float res;
Marc Kupietz04135302026-07-30 14:40:02 +0900700 char json[32];
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200701 a = getTargetWords(w1, 0);
702 b = getTargetWords(w2, 0);
Marc Kupietz969cab92019-08-05 11:13:42 +0200703 if (a == NULL || b == NULL || a->length != 1 || b->length != 1)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200704 res = -1;
Marc Kupietz04135302026-07-30 14:40:02 +0900705 else {
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200706 res = cos_similarity(a->wordi[0], b->wordi[0]);
Marc Kupietz04135302026-07-30 14:40:02 +0900707 fprintf(stderr, "a: %lld b: %lld res:%f\n", a->wordi[0], b->wordi[0], res);
708 }
709 free(a);
710 free(b);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200711 sprintf(json, "%.5f", res);
Marc Kupietz04135302026-07-30 14:40:02 +0900712 return newSVpv(json, 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200713}
714
715void *_get_neighbours(void *arg) {
716 knnpars *pars = arg;
Marc Kupietz969cab92019-08-05 11:13:42 +0200717 int N = pars->N;
718 long from = pars->from;
719 unsigned long upto = pars->upto;
Marc Kupietz59865a92021-03-11 17:16:51 +0100720 char *sep;
Marc Kupietz969cab92019-08-05 11:13:42 +0200721 float dist, len, vec[max_size];
Marc Kupietz59865a92021-03-11 17:16:51 +0100722 long long a, b, c, cn, *bi;
Marc Kupietz969cab92019-08-05 11:13:42 +0200723 knn *nbs = NULL;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200724 wordlist *wl = pars->wl;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200725
Marc Kupietz969cab92019-08-05 11:13:42 +0200726 collocator *best = pars->best;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200727
Marc Kupietz969cab92019-08-05 11:13:42 +0200728 float worstbest = -1;
729
730 for (a = 0; a < N; a++) best[a].activation = 0;
731 a = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200732 bi = wl->wordi;
Marc Kupietz969cab92019-08-05 11:13:42 +0200733 cn = wl->length;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200734 sep = wl->sep;
Marc Kupietz969cab92019-08-05 11:13:42 +0200735 b = bi[0];
Marc Kupietz969cab92019-08-05 11:13:42 +0200736 if (b == -1) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200737 goto end;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200738 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200739 for (a = 0; a < size; a++) vec[a] = 0;
740 for (b = 0; b < cn; b++) {
741 if (bi[b] == -1) continue;
742 if (b > 0 && sep[b - 1] == '-')
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200743 for (a = 0; a < size; a++) vec[a] -= M[a + bi[b] * size];
744 else
745 for (a = 0; a < size; a++) vec[a] += M[a + bi[b] * size];
Marc Kupietz969cab92019-08-05 11:13:42 +0200746 }
747 len = 0;
748 for (a = 0; a < size; a++) len += vec[a] * vec[a];
749 len = sqrt(len);
750 for (a = 0; a < size; a++) vec[a] /= len;
751 for (a = 0; a < N; a++) best[a].activation = -1;
752 for (c = from; c < upto; c++) {
753 if (garbage && garbage[c]) continue;
754 a = 0;
755 // do not skip taget word
756 // for (b = 0; b < cn; b++) if (bi[b] == c) a = 1;
757 // if (a == 1) continue;
758 dist = 0;
759 for (a = 0; a < size; a++) dist += vec[a] * M[a + c * size];
760 if (dist > worstbest) {
761 for (a = 0; a < N; a++) {
762 if (dist > best[a].activation) {
763 memmove(best + a + 1, best + a, (N - a - 1) * sizeof(collocator));
764 best[a].activation = dist;
765 best[a].wordi = c;
766 break;
767 }
768 }
769 worstbest = best[N - 1].activation;
770 }
771 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200772
773end:
Marc Kupietz969cab92019-08-05 11:13:42 +0200774 pthread_exit(nbs);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200775}
776
Marc Kupietz969cab92019-08-05 11:13:42 +0200777int cmp_activation(const void *a, const void *b) {
778 float fb = ((collocator *)a)->activation;
779 float fa = ((collocator *)b)->activation;
780 return (fa > fb) - (fa < fb);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200781}
782
Marc Kupietz969cab92019-08-05 11:13:42 +0200783int cmp_probability(const void *a, const void *b) {
784 float fb = ((collocator *)a)->probability;
785 float fa = ((collocator *)b)->probability;
786 return (fa > fb) - (fa < fb);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200787}
788
Marc Kupietz04135302026-07-30 14:40:02 +0900789SV *getPosWiseW2VCollocators(char *word, long maxPerPos, long cutoff, float threshold, const char *format) {
Marc Kupietz59865a92021-03-11 17:16:51 +0100790 float *target_sums = NULL;
Marc Kupietzd6a163c2026-07-30 14:48:10 +0900791 float *window_sums = NULL;
Marc Kupietz04135302026-07-30 14:40:02 +0900792 long a, b, entries = 0;
Marc Kupietz969cab92019-08-05 11:13:42 +0200793 knn *syn_nbs[MAX_THREADS];
794 knnpars pars[MAX_THREADS];
Marc Kupietz04135302026-07-30 14:40:02 +0900795 pthread_t *pt = NULL;
796 wordlist *wl = NULL;
Marc Kupietz969cab92019-08-05 11:13:42 +0200797 int syn_threads = (M2 ? window * 2 : 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200798 int search_backw = 0;
Marc Kupietz04135302026-07-30 14:40:02 +0900799 char *result = NULL;
800 SV *res_sv;
801
802 for (a = 0; a < MAX_THREADS; a++) syn_nbs[a] = NULL;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200803
Marc Kupietz969cab92019-08-05 11:13:42 +0200804 if (cutoff < 1 || cutoff > words)
805 cutoff = words;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200806
807 wl = getTargetWords(word, search_backw);
Marc Kupietz04135302026-07-30 14:40:02 +0900808 if (wl == NULL || wl->length < 1 || wl->wordi[0] < 0 || syn_threads < 1) {
809 free(wl);
810 return newSVpv("", 0);
811 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200812
Marc Kupietz04135302026-07-30 14:40:02 +0900813 pt = (pthread_t *)malloc((num_threads + 1) * sizeof(pthread_t));
Marc Kupietzd6a163c2026-07-30 14:48:10 +0900814 window_sums = new_window_sums();
Marc Kupietz969cab92019-08-05 11:13:42 +0200815 a = posix_memalign((void **)&target_sums, 128, cutoff * sizeof(float));
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200816 memset(target_sums, 0, cutoff * sizeof(float));
817
818 printf("Starting %d threads\n", syn_threads);
819 fflush(stdout);
Marc Kupietz969cab92019-08-05 11:13:42 +0200820 for (a = 0; a < syn_threads; a++) {
821 pars[a].cutoff = cutoff;
822 pars[a].target_sums = target_sums;
823 pars[a].window_sums = window_sums;
824 pars[a].wl = wl;
825 pars[a].N = maxPerPos;
Marc Kupietz04135302026-07-30 14:40:02 +0900826 pars[a].best = NULL; /* getCollocators() allocates its own result array */
Marc Kupietz969cab92019-08-05 11:13:42 +0200827 pars[a].threshold = threshold;
828 pars[a].from = a;
829 pars[a].upto = a + 1;
830 pthread_create(&pt[a], NULL, getCollocators, (void *)&pars[a]);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200831 }
832 printf("Waiting for syn threads to join\n");
833 fflush(stdout);
Marc Kupietz969cab92019-08-05 11:13:42 +0200834 for (a = 0; a < syn_threads; a++) pthread_join(pt[a], (void *)&syn_nbs[a]);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200835 printf("Syn threads joint\n");
836 fflush(stdout);
Marc Kupietz04135302026-07-30 14:40:02 +0900837 result = malloc((maxPerPos > 0 ? maxPerPos : 1) * (max_w + 96) * syn_threads + 16);
Marc Kupietzbdd779a2024-08-05 10:02:29 +0200838 char *p = (char *) result;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200839 *p = 0;
Marc Kupietz0ab97392024-12-10 16:16:32 +0100840 if (strcmp(format, "tsv") == 0) {
841 for (a = syn_threads - 1; a >= 0; a--) {
Marc Kupietz04135302026-07-30 14:40:02 +0900842 if (syn_nbs[a] == NULL) continue;
843 for (b = 0; b < syn_nbs[a]->length; b++, entries++) {
Marc Kupietz0ab97392024-12-10 16:16:32 +0100844 p += sprintf(p, "%ld\t%s\t%f\n", syn_nbs[a]->best[b].position, &vocab[syn_nbs[a]->best[b].wordi * max_w], syn_nbs[a]->best[b].activation);
845 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200846 }
Marc Kupietz0ab97392024-12-10 16:16:32 +0100847 } else {
848 p += sprintf(p, "[");
849 for (a = syn_threads - 1; a >= 0; a--) {
Marc Kupietz04135302026-07-30 14:40:02 +0900850 if (syn_nbs[a] == NULL) continue;
851 for (b = 0; b < syn_nbs[a]->length; b++, entries++) {
Marc Kupietz0ab97392024-12-10 16:16:32 +0100852 p += sprintf(p, "{\"pos\": %ld, \"word\":\"%s\",\"activation\": %f},\n", syn_nbs[a]->best[b].position, &vocab[syn_nbs[a]->best[b].wordi * max_w], syn_nbs[a]->best[b].activation);
853 }
854 }
Marc Kupietz04135302026-07-30 14:40:02 +0900855 if (entries > 0)
856 p -= 2; /* drop the trailing ",\n" */
Marc Kupietz0ab97392024-12-10 16:16:32 +0100857 p += sprintf(p, "\n]");
Marc Kupietz969cab92019-08-05 11:13:42 +0200858 }
Marc Kupietz0ab97392024-12-10 16:16:32 +0100859
Marc Kupietz04135302026-07-30 14:40:02 +0900860 res_sv = newSVpv(result, 0);
861
862 free(result);
863 free(target_sums);
Marc Kupietzd6a163c2026-07-30 14:48:10 +0900864 free(window_sums);
Marc Kupietz04135302026-07-30 14:40:02 +0900865 free(pt);
866 free(wl);
867 for (a = 0; a < syn_threads; a++) free_knn(syn_nbs[a]);
868
869 return res_sv;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200870}
871
Marc Kupietz04135302026-07-30 14:40:02 +0900872SV *getPosWiseW2VCollocatorsAsTsv(char *word, long maxPerPos, long cutoff, float threshold) {
Marc Kupietz0ab97392024-12-10 16:16:32 +0100873 return getPosWiseW2VCollocators(word, maxPerPos, cutoff, threshold, "tsv");
874}
875
Marc Kupietz04135302026-07-30 14:40:02 +0900876SV *getPosWiseW2VCollocatorsAsJson(char *word, long maxPerPos, long cutoff, float threshold) {
Marc Kupietz0ab97392024-12-10 16:16:32 +0100877 return getPosWiseW2VCollocators(word, maxPerPos, cutoff, threshold, "json");
878}
879
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200880SV *get_neighbours(char *st1, int N, int sort_by, int search_backw, long cutoff, int dedupe, int no_similar_profiles) {
881 HV *result = newHV();
Marc Kupietz59865a92021-03-11 17:16:51 +0100882 float *target_sums = NULL;
Marc Kupietzd6a163c2026-07-30 14:48:10 +0900883 float *window_sums = NULL;
Marc Kupietz969cab92019-08-05 11:13:42 +0200884 long a, b, c, d, slice;
885 knn *para_nbs[MAX_THREADS];
886 knn *syn_nbs[MAX_THREADS];
887 knnpars pars[MAX_THREADS];
888 pthread_t *pt = (pthread_t *)malloc((num_threads + 1) * sizeof(pthread_t));
Marc Kupietz04135302026-07-30 14:40:02 +0900889 wordlist *wl = NULL;
Marc Kupietz969cab92019-08-05 11:13:42 +0200890 int syn_threads = (M2 ? window * 2 : 0);
891 int para_threads = (no_similar_profiles ? 0 : num_threads - syn_threads);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200892
Marc Kupietz04135302026-07-30 14:40:02 +0900893 for (a = 0; a < MAX_THREADS; a++) para_nbs[a] = syn_nbs[a] = NULL;
894
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200895 collocator *best = NULL;
Marc Kupietz969cab92019-08-05 11:13:42 +0200896 posix_memalign((void **)&best, 128, 10 * (N >= 200 ? N : 200) * sizeof(collocator));
897 memset(best, 0, (N >= 200 ? N : 200) * sizeof(collocator));
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200898
Marc Kupietz969cab92019-08-05 11:13:42 +0200899 if (N > MAX_NEIGHBOURS) N = MAX_NEIGHBOURS;
900
901 if (cutoff < 1 || cutoff > words)
902 cutoff = words;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200903
904 wl = getTargetWords(st1, search_backw);
Marc Kupietz969cab92019-08-05 11:13:42 +0200905 if (wl == NULL || wl->length < 1)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200906 goto end;
907
Marc Kupietz04135302026-07-30 14:40:02 +0900908 slice = (para_threads > 0 ? cutoff / para_threads : cutoff);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200909
Marc Kupietz969cab92019-08-05 11:13:42 +0200910 a = posix_memalign((void **)&target_sums, 128, cutoff * sizeof(float));
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200911 memset(target_sums, 0, cutoff * sizeof(float));
912
Marc Kupietzc0d41872021-02-25 16:33:22 +0100913 printf("Starting %d threads for paradigmatic search\n", para_threads);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200914 fflush(stdout);
Marc Kupietz969cab92019-08-05 11:13:42 +0200915 for (a = 0; a < para_threads; a++) {
916 pars[a].cutoff = cutoff;
917 pars[a].token = st1;
918 pars[a].wl = wl;
919 pars[a].N = N;
920 pars[a].best = &best[N * a];
921 if (merge_words == 0 || search_backw == 0) {
922 pars[a].from = a * slice;
923 pars[a].upto = ((a + 1) * slice > cutoff ? cutoff : (a + 1) * slice);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200924 } else {
925 pars[a].from = merge_words + a * slice;
Marc Kupietz969cab92019-08-05 11:13:42 +0200926 pars[a].upto = merge_words + ((a + 1) * slice > cutoff ? cutoff : (a + 1) * slice);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200927 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200928 printf("From: %ld, Upto: %ld\n", pars[a].from, pars[a].upto);
929 pthread_create(&pt[a], NULL, _get_neighbours, (void *)&pars[a]);
930 }
931 if (M2) {
Marc Kupietzd6a163c2026-07-30 14:48:10 +0900932 window_sums = new_window_sums();
Marc Kupietz969cab92019-08-05 11:13:42 +0200933 for (a = 0; a < syn_threads; a++) {
934 pars[a + para_threads].cutoff = cutoff;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200935 pars[a + para_threads].target_sums = target_sums;
936 pars[a + para_threads].window_sums = window_sums;
937 pars[a + para_threads].wl = wl;
938 pars[a + para_threads].N = N;
939 pars[a + para_threads].threshold = MIN_RESP;
940 pars[a + para_threads].from = a;
Marc Kupietz969cab92019-08-05 11:13:42 +0200941 pars[a + para_threads].upto = a + 1;
942 pthread_create(&pt[a + para_threads], NULL, getCollocators, (void *)&pars[a + para_threads]);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200943 }
944 }
945 printf("Waiting for para threads to join\n");
946 fflush(stdout);
Marc Kupietz969cab92019-08-05 11:13:42 +0200947 for (a = 0; a < para_threads; a++) pthread_join(pt[a], (void *)&para_nbs[a]);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200948 printf("Para threads joint\n");
949 fflush(stdout);
950
Marc Kupietz969cab92019-08-05 11:13:42 +0200951 /* if(!syn_nbs[0]) */
952 /* goto end; */
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200953
Marc Kupietz969cab92019-08-05 11:13:42 +0200954 qsort(best, N * para_threads, sizeof(collocator), cmp_activation);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200955
956 long long chosen[MAX_NEIGHBOURS];
Marc Kupietz59865a92021-03-11 17:16:51 +0100957 printf("N: %d\n", N);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200958
Marc Kupietz969cab92019-08-05 11:13:42 +0200959 AV *array = newAV();
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200960 int i, j;
Marc Kupietz969cab92019-08-05 11:13:42 +0200961 int l1_words = 0, l2_words = 0;
962
963 for (a = 0, i = 0; i < N && a < N * para_threads; a++) {
964 int filtered = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200965 long long c = best[a].wordi;
966 if ((merge_words && dedupe && i > 1) || (!merge_words && dedupe && i > 0)) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200967 for (j = 0; j < i && !filtered; j++)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200968 if (strcasestr(&vocab[c * max_w], &vocab[chosen[j] * max_w]) ||
969 strcasestr(&vocab[chosen[j] * max_w], &vocab[c * max_w])) {
Marc Kupietz969cab92019-08-05 11:13:42 +0200970 printf("filtering %s %s\n", &vocab[chosen[j] * max_w], &vocab[c * max_w]);
971 filtered = 1;
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200972 }
Marc Kupietz969cab92019-08-05 11:13:42 +0200973 if (filtered)
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200974 continue;
975 }
976
Marc Kupietz969cab92019-08-05 11:13:42 +0200977 if (0 && merge_words > 0) {
978 if (c >= merge_words) {
979 if (l1_words > N / 2)
980 continue;
981 else
982 l1_words++;
983 } else {
984 if (l2_words > N / 2)
985 continue;
986 else
987 l2_words++;
988 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200989 }
990
Marc Kupietz969cab92019-08-05 11:13:42 +0200991 // printf("%s l1:%d l2:%d i:%d a:%ld\n", &vocab[c * max_w], l1_words, l2_words, i, a);
992 // fflush(stdout);
993 HV *hash = newHV();
994 SV *word = newSVpvf(&vocab[c * max_w], 0);
995 chosen[i] = c;
996 if (latin_enc == 0) SvUTF8_on(word);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200997 fflush(stdout);
Marc Kupietz969cab92019-08-05 11:13:42 +0200998 hv_store(hash, "word", strlen("word"), word, 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +0200999 hv_store(hash, "dist", strlen("dist"), newSVnv(best[a].activation), 0);
1000 hv_store(hash, "rank", strlen("rank"), newSVuv(best[a].wordi), 0);
1001 AV *vector = newAV();
1002 for (b = 0; b < size; b++) {
1003 av_push(vector, newSVnv(M[b + best[a].wordi * size]));
1004 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001005 hv_store(hash, "vector", strlen("vector"), newRV_noinc((SV *)vector), 0);
1006 av_push(array, newRV_noinc((SV *)hash));
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001007 i++;
1008 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001009 hv_store(result, "paradigmatic", strlen("paradigmatic"), newRV_noinc((SV *)array), 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001010
Marc Kupietz969cab92019-08-05 11:13:42 +02001011 for (b = 0; b < MAX_NEIGHBOURS; b++) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001012 best[b].wordi = -1L;
1013 best[b].activation = 0;
1014 best[b].probability = 0;
1015 best[b].position = 0;
1016 best[b].activation_sum = 0;
Marc Kupietz969cab92019-08-05 11:13:42 +02001017 memset(best[b].heat, 0, sizeof(float) * 16);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001018 }
1019
Marc Kupietz969cab92019-08-05 11:13:42 +02001020 float total_activation = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001021
1022 if (M2) {
1023 printf("Waiting for syn threads to join\n");
1024 fflush(stdout);
Marc Kupietz969cab92019-08-05 11:13:42 +02001025 for (a = 0; a < syn_threads; a++) pthread_join(pt[a + para_threads], (void *)&syn_nbs[a]);
1026 for (a = 0; a <= syn_threads; a++) {
1027 if (a == window) continue;
1028 total_activation += window_sums[a];
Marc Kupietz59865a92021-03-11 17:16:51 +01001029 printf("window pos: %ld, sum: %f\n", a, window_sums[a]);
Marc Kupietz969cab92019-08-05 11:13:42 +02001030 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001031 printf("syn threads joint\n");
1032 fflush(stdout);
1033
Marc Kupietz969cab92019-08-05 11:13:42 +02001034 for (b = 0; b < syn_nbs[0]->length; b++) {
1035 memcpy(best + b, &syn_nbs[0]->best[b], sizeof(collocator));
1036 best[b].position = -1; // syn_nbs[0]->pos[b];
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001037 best[b].activation_sum = target_sums[syn_nbs[0]->best[b].wordi];
Marc Kupietz969cab92019-08-05 11:13:42 +02001038 best[b].max_activation = 0.0;
1039 best[b].average = 0.0;
1040 best[b].probability = 0.0;
1041 best[b].cprobability = syn_nbs[0]->best[b].cprobability;
1042 memset(best[b].heat, 0, sizeof(float) * 16);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001043 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001044
1045 float best_window_sum[MAX_NEIGHBOURS];
Marc Kupietz59865a92021-03-11 17:16:51 +01001046 int found_index = 0, i = 0, w;
Marc Kupietz969cab92019-08-05 11:13:42 +02001047 for (a = 0; a < syn_threads; a++) {
1048 for (b = 0; b < syn_nbs[a]->length; b++) {
1049 for (i = 0; i < found_index; i++)
1050 if (best[i].wordi == syn_nbs[a]->best[b].wordi)
1051 break;
1052 if (i >= found_index) {
1053 best[found_index].max_activation = 0.0;
1054 best[found_index].average = 0.0;
1055 best[found_index].probability = 0.0;
1056 memset(best[found_index].heat, 0, sizeof(float) * 16);
1057 best[found_index].cprobability = syn_nbs[a]->best[b].cprobability;
1058 best[found_index].activation_sum = target_sums[syn_nbs[a]->best[b].wordi]; // syn_nbs[a]->best[b].activation_sum;
1059 best[found_index++].wordi = syn_nbs[a]->best[b].wordi;
1060 // printf("found: %s\n", &vocab[syn_nbs[a]->index[b] * max_w]);
1061 }
1062 }
1063 }
1064 sort_by = 0; // ALWAYS AUTO-FOCUS
1065 if (sort_by != 1 && sort_by != 2) { // sort by auto focus mean
1066 printf("window: %d - syn_threads: %d, %d\n", window, syn_threads, (1 << syn_threads) - 1);
1067 int wpos;
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001068 int bits_set = 0;
Marc Kupietz969cab92019-08-05 11:13:42 +02001069 for (i = 0; i < found_index; i++) {
1070 best[i].activation = best[i].probability = best[i].average = best[i].cprobability_sum = 0;
1071 for (w = 1; w < (1 << syn_threads); w++) { // loop through all possible windows
1072 float word_window_sum = 0, word_window_average = 0, word_cprobability_sum = 0, word_activation_sum = 0, total_window_sum = 0;
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001073 bits_set = 0;
Marc Kupietz969cab92019-08-05 11:13:42 +02001074 for (a = 0; a < syn_threads; a++) {
1075 if ((1 << a) & w) {
1076 wpos = (a >= window ? a + 1 : a);
1077 total_window_sum += window_sums[wpos];
1078 }
1079 }
1080 // printf("%d window-sum %f\n", w, total_window_sum);
1081 for (a = 0; a < syn_threads; a++) {
1082 if ((1 << a) & w) {
1083 wpos = (a >= window ? a + 1 : a);
1084 bits_set++;
1085 for (b = 0; b < syn_nbs[a]->length; b++)
1086 if (best[i].wordi == syn_nbs[a]->best[b].wordi) {
1087 // float acti = syn_nbs[a]->best[b].activation / total_window_sum;
1088 // word_window_sum += syn_nbs[a]->dist[b] * syn_nbs[a]->norm[b]; // / window_sums[wpos]; // syn_nbs[a]->norm[b];
1089 // word_window_sum += syn_nbs[a]->norm[b]; // / window_sums[wpos]; // syn_nbs[a]->norm[b];
1090 // word_window_sum = (word_window_sum + syn_nbs[a]->norm[b]) - (word_window_sum * syn_nbs[a]->norm[b]); // syn_nbs[a]->norm[b];
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001091
Marc Kupietz969cab92019-08-05 11:13:42 +02001092 word_window_sum += syn_nbs[a]->best[b].activation; // / window_sums[wpos]; // syn_nbs[a]->norm[b];
1093 // word_window_sum += acti - (word_window_sum * acti); syn_nbs[a]->best[b].activation; // / window_sums[wpos]; // syn_nbs[a]->norm[b];
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001094
Marc Kupietz969cab92019-08-05 11:13:42 +02001095 word_window_average += syn_nbs[a]->best[b].activation; // - word_window_average * syn_nbs[a]->best[b].activation; // conormalied activation sum
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001096 word_cprobability_sum += syn_nbs[a]->best[b].cprobability - word_cprobability_sum * syn_nbs[a]->best[b].cprobability; // conormalied column probability sum
Marc Kupietz969cab92019-08-05 11:13:42 +02001097 word_activation_sum += syn_nbs[a]->best[b].activation;
1098 if (syn_nbs[a]->best[b].activation > best[i].max_activation)
1099 best[i].max_activation = syn_nbs[a]->best[b].activation;
1100 if (syn_nbs[a]->best[b].activation > best[i].heat[wpos])
1101 best[i].heat[wpos] = syn_nbs[a]->best[b].activation;
1102 }
1103 }
1104 }
1105 if (bits_set) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001106 word_window_average /= bits_set;
Marc Kupietz969cab92019-08-05 11:13:42 +02001107 // word_activation_sum /= bits_set;
1108 // word_window_sum /= bits_set;
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001109 }
1110
Marc Kupietz969cab92019-08-05 11:13:42 +02001111 word_window_sum /= total_window_sum;
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001112
Marc Kupietz969cab92019-08-05 11:13:42 +02001113 if (word_window_sum > best[i].probability) {
1114 // best[i].position = w;
1115 best[i].probability = word_window_sum;
1116 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001117
Marc Kupietz969cab92019-08-05 11:13:42 +02001118 if (word_cprobability_sum > best[i].cprobability_sum) {
1119 best[i].position = w;
1120 best[i].cprobability_sum = word_cprobability_sum;
1121 }
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001122
Marc Kupietz969cab92019-08-05 11:13:42 +02001123 best[i].average = word_window_average;
1124 // best[i].activation = word_activation_sum;
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001125 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001126 }
1127 qsort(best, found_index, sizeof(collocator), cmp_probability);
1128 // for(i=0; i < found_index; i++) {
1129 // printf("found: %s - sum: %f - window: %d\n", &vocab[best[i].wordi * max_w], best[i].activation, best[i].position);
1130 // }
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001131
Marc Kupietz969cab92019-08-05 11:13:42 +02001132 } else if (sort_by == 1) { // responsiveness any window position
1133 int wpos;
1134 for (i = 0; i < found_index; i++) {
1135 float word_window_sum = 0, word_activation_sum = 0, total_window_sum = 0;
1136 for (a = 0; a < syn_threads; a++) {
1137 wpos = (a >= window ? a + 1 : a);
1138 for (b = 0; b < syn_nbs[a]->length; b++)
1139 if (best[i].wordi == syn_nbs[a]->best[b].wordi) {
1140 best[i].probability += syn_nbs[a]->best[b].probability;
1141 if (syn_nbs[a]->best[b].activation > 0.25)
1142 best[i].position |= 1 << wpos;
1143 if (syn_nbs[a]->best[b].activation > best[i].activation) {
1144 best[i].activation = syn_nbs[a]->best[b].activation;
1145 }
1146 }
1147 }
1148 }
1149 qsort(best, found_index, sizeof(collocator), cmp_activation);
1150 } else if (sort_by == 2) { // single window position
1151 for (a = 1; a < syn_threads; a++) {
1152 for (b = 0; b < syn_nbs[a]->length; b++) {
1153 for (c = 0; c < MAX_NEIGHBOURS; c++) {
1154 if (syn_nbs[a]->best[b].activation > best[c].activation) {
1155 for (d = MAX_NEIGHBOURS - 1; d > c; d--) {
1156 memmove(best + d, best + d - 1, sizeof(collocator));
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001157 }
1158 memcpy(best + c, &syn_nbs[a]->best[b], sizeof(collocator));
Marc Kupietz969cab92019-08-05 11:13:42 +02001159 best[c].position = 1 << (-syn_nbs[a]->best[b].position + window - (syn_nbs[a]->best[b].position < 0 ? 1 : 0));
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001160 break;
1161 }
1162 }
1163 }
1164 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001165 } else { // sort by mean p
1166 for (a = 1; a < syn_threads; a++) {
1167 for (b = 0; b < syn_nbs[a]->length; b++) {
1168 for (c = 0; c < MAX_NEIGHBOURS; c++) {
1169 if (target_sums[syn_nbs[a]->best[b].wordi] > best[c].activation_sum) {
1170 for (d = MAX_NEIGHBOURS - 1; d > c; d--) {
1171 memmove(best + d, best + d - 1, sizeof(collocator));
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001172 }
1173 memcpy(best + c, &syn_nbs[a]->best[b], sizeof(collocator));
Marc Kupietz969cab92019-08-05 11:13:42 +02001174 best[c].position = (1 << 2 * window) - 1; // syn_nbs[a]->pos[b];
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001175 best[c].activation_sum = target_sums[syn_nbs[a]->best[b].wordi];
1176 break;
1177 }
1178 }
1179 }
1180 }
1181 }
1182 array = newAV();
Marc Kupietz969cab92019-08-05 11:13:42 +02001183 for (a = 0, i = 0; a < MAX_NEIGHBOURS && best[a].wordi >= 0; a++) {
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001184 long long c = best[a].wordi;
Marc Kupietz969cab92019-08-05 11:13:42 +02001185 /*
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001186 if (dedupe) {
1187 int filtered=0;
1188 for (j=0; j<i; j++)
1189 if (strcasestr(&vocab[c * max_w], chosen[j]) ||
1190 strcasestr(chosen[j], &vocab[c * max_w])) {
1191 printf("filtering %s %s\n", chosen[j], &vocab[c * max_w]);
1192 filtered = 1;
1193 }
1194 if(filtered)
1195 continue;
1196 }
1197*/
Marc Kupietz969cab92019-08-05 11:13:42 +02001198 chosen[i++] = c;
1199 HV *hash = newHV();
1200 SV *word = newSVpvf(&vocab[best[a].wordi * max_w], 0);
1201 AV *heat = newAV();
1202 if (latin_enc == 0) SvUTF8_on(word);
1203 hv_store(hash, "word", strlen("word"), word, 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001204 hv_store(hash, "rank", strlen("rank"), newSVuv(best[a].wordi), 0);
1205 hv_store(hash, "average", strlen("average"), newSVnv(best[a].average), 0);
1206 hv_store(hash, "prob", strlen("prob"), newSVnv(best[a].probability), 0);
1207 hv_store(hash, "cprob", strlen("cprob"), newSVnv(best[a].cprobability_sum), 0);
Marc Kupietz969cab92019-08-05 11:13:42 +02001208 hv_store(hash, "max", strlen("max"), newSVnv(best[a].max_activation), 0); // newSVnv(target_sums[best[a].wordi]), 0);
1209 hv_store(hash, "overall", strlen("overall"), newSVnv(best[a].activation_sum / total_activation), 0); // newSVnv(target_sums[best[a].wordi]), 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001210 hv_store(hash, "pos", strlen("pos"), newSVnv(best[a].position), 0);
Marc Kupietz969cab92019-08-05 11:13:42 +02001211 best[a].heat[5] = 0;
1212 for (i = 10; i >= 0; i--) av_push(heat, newSVnv(best[a].heat[i]));
1213 hv_store(hash, "heat", strlen("heat"), newRV_noinc((SV *)heat), 0);
1214 av_push(array, newRV_noinc((SV *)hash));
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001215 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001216 hv_store(result, "syntagmatic", strlen("syntagmatic"), newRV_noinc((SV *)array), 0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001217 }
1218end:
Marc Kupietz969cab92019-08-05 11:13:42 +02001219 free(best);
Marc Kupietz04135302026-07-30 14:40:02 +09001220 free(target_sums);
Marc Kupietzd6a163c2026-07-30 14:48:10 +09001221 free(window_sums);
Marc Kupietz04135302026-07-30 14:40:02 +09001222 free(pt);
1223 free(wl);
1224 for (a = 0; a < MAX_THREADS; a++) {
1225 free_knn(para_nbs[a]);
1226 free_knn(syn_nbs[a]);
1227 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001228 return newRV_noinc((SV *)result);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001229}
1230
1231int dump_vecs(char *fname) {
Marc Kupietz969cab92019-08-05 11:13:42 +02001232 long i, j;
1233 FILE *f;
1234 /* if(words>100000)
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001235 words=100000;
1236*/
Marc Kupietz969cab92019-08-05 11:13:42 +02001237 if ((f = fopen(fname, "w")) == NULL) {
1238 fprintf(stderr, "cannot open %s for writing\n", fname);
1239 return (-1);
1240 }
1241 fprintf(f, "%lld %lld\n", words, size);
1242 for (i = 0; i < words; i++) {
1243 fprintf(f, "%s ", &vocab[i * max_w]);
1244 for (j = 0; j < size - 1; j++)
1245 fprintf(f, "%f ", M[i * size + j]);
1246 fprintf(f, "%f\n", M[i * size + j]);
1247 }
1248 fclose(f);
1249 return (0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001250}
1251
1252int dump_for_numpy(char *fname) {
Marc Kupietz969cab92019-08-05 11:13:42 +02001253 long i, j;
1254 FILE *f;
Marc Kupietzc0d41872021-02-25 16:33:22 +01001255 int max = words; // 300000;
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001256
Marc Kupietz969cab92019-08-05 11:13:42 +02001257 if ((f = fopen(fname, "w")) == NULL) {
1258 fprintf(stderr, "cannot open %s for writing\n", fname);
1259 return (-1);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001260 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001261 for (i = 0; i < max; i++) {
1262 for (j = 0; j < size - 1; j++)
1263 fprintf(f, "%f\t", M[i * size + j]);
1264 fprintf(f, "%f\n", M[i * size + j]);
1265 printf("%s\r\n", &vocab[i * max_w]);
1266 }
1267 if (merged_end > 0) {
1268 for (i = 0; i < max; i++) {
1269 for (j = 0; j < size - 1; j++)
1270 fprintf(f, "%f\t", M[(merged_end + i) * size + j]);
1271 fprintf(f, "%f\n", M[(merged_end + i) * size + j]);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001272 printf("_%s\r\n", &vocab[i * max_w]);
1273 }
Marc Kupietz969cab92019-08-05 11:13:42 +02001274 }
1275 fclose(f);
1276 return (0);
Marc Kupietzf11d20c2019-08-02 15:42:04 +02001277}
Marc Kupietz043db152023-11-05 17:47:53 +01001278
1279unsigned long getVocabSize() {
1280 return (unsigned long) words;
1281}