Private info (buf) moved from struct rset_control to struct rset.
[idzebra-moved-to-github.git] / rset / rsrel.c
1 /*
2  * Copyright (C) 1994-1995, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: rsrel.c,v $
7  * Revision 1.7  1995-10-12 12:41:57  adam
8  * Private info (buf) moved from struct rset_control to struct rset.
9  * Bug fixes in relevance.
10  *
11  * Revision 1.6  1995/10/10  14:00:04  adam
12  * Function rset_open changed its wflag parameter to general flags.
13  *
14  * Revision 1.5  1995/10/06  14:38:06  adam
15  * New result set method: r_score.
16  * Local no (sysno) and score is transferred to retrieveCtrl.
17  *
18  * Revision 1.4  1995/09/14  07:48:56  adam
19  * Other score calculation.
20  *
21  * Revision 1.3  1995/09/11  15:23:40  adam
22  * More work on relevance search.
23  *
24  * Revision 1.2  1995/09/11  13:09:41  adam
25  * More work on relevance feedback.
26  *
27  * Revision 1.1  1995/09/08  14:52:42  adam
28  * Work on relevance feedback.
29  *
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <math.h>
35 #include <assert.h>
36
37 #include <isam.h>
38 #include <rsrel.h>
39 #include <alexutil.h>
40
41 static void *r_create(const struct rset_control *sel, void *parms);
42 static RSFD r_open (RSET ct, int flag);
43 static void r_close (RSFD rfd);
44 static void r_delete (RSET ct);
45 static void r_rewind (RSFD rfd);
46 static int r_count (RSET ct);
47 static int r_read (RSFD rfd, void *buf);
48 static int r_write (RSFD rfd, const void *buf);
49 static int r_score (RSFD rfd, int *score);
50
51 static const rset_control control = 
52 {
53     "relevance set type",
54     r_create,
55     r_open,
56     r_close,
57     r_delete,
58     r_rewind,
59     r_count,
60     r_read,
61     r_write,
62     r_score
63 };
64
65 const rset_control *rset_kind_relevance = &control;
66
67 struct rset_rel_info {
68     int     key_size;
69     int     max_rec;
70     int     no_rec;
71     int     (*cmp)(const void *p1, const void *p2);
72     char    *key_buf;                   /* key buffer */
73     float   *score_buf;                 /* score buffer */
74     int     *sort_idx;                  /* score sorted index */
75     int     *sysno_idx;                /* sysno sorted index (ring buffer) */
76     struct rset_rel_rfd *rfd_list;
77 };
78
79 struct rset_rel_rfd {
80     int     last_read_pos;
81     int     position;
82     int     flag;
83     struct rset_rel_rfd *next;
84     struct rset_rel_info *info;
85 };
86
87 static void add_rec (struct rset_rel_info *info, double score, void *key)
88 {
89     int idx, i, j;
90
91     for (i = 0; i<info->no_rec; i++)
92     {
93         idx = info->sort_idx[i];
94         if (score <= info->score_buf[idx])
95             break;
96     }
97     if (info->no_rec < info->max_rec)
98     {                                        /* there is room for this entry */
99         for (j = info->no_rec; j > i; --j)
100             info->sort_idx[j] = info->sort_idx[j-1];
101         idx = info->sort_idx[j] = info->no_rec;
102         ++(info->no_rec);
103     }
104     else if (i == 0)
105         return;                              /* score too low */
106     else
107     {
108         idx = info->sort_idx[0];             /* remove this entry */
109
110         --i;
111         for (j = 0; j < i; ++j)              /* make room */
112             info->sort_idx[j] = info->sort_idx[j+1];
113         info->sort_idx[j] = idx;             /* allocate sort entry */
114     }
115     memcpy (info->key_buf + idx*info->key_size, key, info->key_size);
116     info->score_buf[idx] = score;
117 }
118
119
120 static struct rset_rel_info *qsort_info;
121
122 static int qcomp (const void *p1, const void *p2)
123 {
124     int i1 = *(int*) p1;
125     int i2 = *(int*) p2;
126
127     return qsort_info->cmp (qsort_info->key_buf + i1*qsort_info->key_size,
128                             qsort_info->key_buf + i2*qsort_info->key_size);
129 }
130
131 static void relevance (struct rset_rel_info *info, rset_relevance_parms *parms)
132 {
133     char **isam_buf;
134     char *isam_tmp_buf;
135     int  *isam_r;
136     int  *max_tf;
137     ISPT *isam_pt;
138     double *wgt;
139     int i;
140
141     logf (LOG_DEBUG, "relevance");
142     isam_buf = xmalloc (parms->no_isam_positions * sizeof(*isam_buf));
143     isam_r = xmalloc (sizeof (*isam_r) * parms->no_isam_positions);
144     isam_pt = xmalloc (sizeof (*isam_pt) * parms->no_isam_positions);
145     isam_tmp_buf = xmalloc (info->key_size);
146     max_tf = xmalloc (sizeof (*max_tf) * parms->no_isam_positions);
147     wgt = xmalloc (sizeof (*wgt) * parms->no_isam_positions);
148
149     for (i = 0; i<parms->no_isam_positions; i++)
150     {
151         isam_buf[i] = xmalloc (info->key_size);
152         isam_pt[i] = is_position (parms->is, parms->isam_positions[i]);
153         max_tf [i] = is_numkeys (isam_pt[i]);
154         isam_r[i] = is_readkey (isam_pt[i], isam_buf[i]);
155         logf (LOG_DEBUG, "max tf %d = %d", i, max_tf[i]);
156     }
157     while (1)
158     {
159         int min = -1, i;
160         double score;
161
162         /* find min with lowest sysno */
163         for (i = 0; i<parms->no_isam_positions; i++)
164             if (isam_r[i] && 
165                (min < 0 || (*parms->cmp)(isam_buf[i], isam_buf[min]) < 1))
166                 min = i;
167         if (min < 0)
168             break;
169         memcpy (isam_tmp_buf, isam_buf[min], info->key_size);
170         /* calculate for all with those sysno */
171         for (i = 0; i<parms->no_isam_positions; i++)
172         {
173             int r;
174             
175             if (isam_r[i])
176                 r = (*parms->cmp)(isam_buf[i], isam_tmp_buf);
177             else 
178                 r = 2;
179             if (r > 1 || r < -1)
180                 wgt[i] = 0.0;
181             else
182             {
183                 int tf = 0;
184                 do
185                 {
186                     tf++;
187                     isam_r[i] = is_readkey (isam_pt[i], isam_buf[i]);
188                 } while (isam_r[i] && 
189                          (*parms->cmp)(isam_buf[i], isam_tmp_buf) <= 1);
190                 wgt[i] = 0.1+tf*0.9/max_tf[i];
191             }
192         }
193         /* calculate relevance value */
194         score = 0.0;
195         for (i = 0; i<parms->no_isam_positions; i++)
196             score += wgt[i];
197         /* if value is in the top score, then save it - don't emit yet */
198         add_rec (info, score, isam_tmp_buf);
199     }
200     for (i = 0; i<info->no_rec; i++)
201         info->sysno_idx[i] = i;
202     qsort_info = info;
203     qsort (info->sysno_idx, info->no_rec, sizeof(*info->sysno_idx), qcomp);
204     for (i = 0; i<parms->no_isam_positions; i++)
205     {
206         is_pt_free (isam_pt[i]);
207         xfree (isam_buf[i]);
208     }
209     xfree (max_tf);
210     xfree (isam_tmp_buf);
211     xfree (isam_buf);
212     xfree (isam_r);
213     xfree (isam_pt);
214     xfree (wgt);
215 }
216
217 static void *r_create (const struct rset_control *sel, void *parms)
218 {
219     rset_relevance_parms *r_parms = parms;
220     struct rset_rel_info *info;
221
222     info = xmalloc (sizeof(struct rset_rel_info));
223     info->key_size = r_parms->key_size;
224     assert (info->key_size > 1);
225     info->max_rec = r_parms->max_rec;
226     assert (info->max_rec > 1);
227     info->cmp = r_parms->cmp;
228
229     info->key_buf = xmalloc (info->key_size * info->max_rec);
230     info->score_buf = xmalloc (sizeof(*info->score_buf) * info->max_rec);
231     info->sort_idx = xmalloc (sizeof(*info->sort_idx) * info->max_rec);
232     info->sysno_idx = xmalloc (sizeof(*info->sysno_idx) * info->max_rec);
233     info->no_rec = 0;
234     info->rfd_list = NULL;
235
236     relevance (info, r_parms);
237     return info;
238 }
239
240 static RSFD r_open (RSET ct, int flag)
241 {
242     struct rset_rel_rfd *rfd;
243     struct rset_rel_info *info = ct->buf;
244
245     if (flag & RSETF_WRITE)
246     {
247         logf (LOG_FATAL, "relevance set type is read-only");
248         return NULL;
249     }
250     rfd = xmalloc (sizeof(*rfd));
251     rfd->flag = flag;
252     rfd->next = info->rfd_list;
253     rfd->info = info;
254     info->rfd_list = rfd;
255     r_rewind (rfd);
256     return rfd;
257 }
258
259 static void r_close (RSFD rfd)
260 {
261     struct rset_rel_info *info = ((struct rset_rel_rfd*)rfd)->info;
262     struct rset_rel_rfd **rfdp;
263     
264     for (rfdp = &info->rfd_list; *rfdp; rfdp = &(*rfdp)->next)
265         if (*rfdp == rfd)
266         {
267             *rfdp = (*rfdp)->next;
268             free (rfd);
269             return;
270         }
271     logf (LOG_FATAL, "r_close but no rfd match!");
272     assert (0);
273 }
274
275 static void r_delete (RSET ct)
276 {
277     struct rset_rel_info *info = ct->buf;
278
279     assert (info->rfd_list == NULL);
280     xfree (info->key_buf);
281     xfree (info->score_buf);
282     xfree (info->sort_idx);
283     xfree (info->sysno_idx);
284     xfree (info);
285     xfree (ct);
286 }
287
288 static void r_rewind (RSFD rfd)
289 {
290     struct rset_rel_rfd *p = rfd;
291     struct rset_rel_info *info = p->info;
292
293     if (p->flag & RSETF_SORT_RANK)
294         p->position = info->no_rec;
295     else
296         p->position = 0;
297 }
298
299 static int r_count (RSET ct)
300 {
301     struct rset_rel_info *info = ct->buf;
302
303     return info->no_rec;
304 }
305
306 static int r_read (RSFD rfd, void *buf)
307 {
308     struct rset_rel_rfd *p = rfd;
309     struct rset_rel_info *info = p->info;
310
311     if (p->flag & RSETF_SORT_RANK)
312     {
313         if (p->position <= 0)
314             return 0;
315         --(p->position);
316         p->last_read_pos = info->sort_idx[p->position];
317     }
318     else
319     {
320         if (p->position == info->no_rec)
321             return 0;
322         p->last_read_pos = info->sysno_idx[p->position];
323         ++(p->position);
324     }
325     memcpy ((char*) buf,
326             info->key_buf + info->key_size * p->last_read_pos,
327             info->key_size);
328     return 1;
329 }
330
331 static int r_score (RSFD rfd, int *score)
332 {
333     struct rset_rel_rfd *p = rfd;
334     struct rset_rel_info *info = p->info;
335
336     *score = (int) (1000*info->score_buf[p->last_read_pos]);
337     return 1;
338 }
339
340 static int r_write (RSFD rfd, const void *buf)
341 {
342     logf (LOG_FATAL, "relevance set type is read-only");
343     return -1;
344 }