617c7ac72bb15ba646c2e9b7926188bcaa40bc04
[pspp-builds.git] / src / math / extrema.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2008 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18 #include "extrema.h"
19 #include <xalloc.h>
20 #include <data/case.h>
21 #include <data/val-type.h>
22 #include <libpspp/compiler.h>
23 #include <libpspp/ll.h>
24 #include <stdlib.h>
25
26 struct extrema
27 {
28   size_t capacity;
29   size_t n;
30   struct ll_list list;
31
32   ll_compare_func *cmp_func;
33 };
34
35
36 static int
37 cmp_descending (const struct ll *a_, const struct ll *b_, void *aux UNUSED)
38 {
39   const struct extremum *a = ll_data (a_, struct extremum, ll);
40   const struct extremum *b = ll_data (b_, struct extremum, ll);
41
42   if ( a->value > b->value) return -1;
43
44   return (a->value < b->value);
45 }
46
47 static int
48 cmp_ascending (const struct ll *a_, const struct ll *b_, void *aux UNUSED)
49 {
50   const struct extremum *a = ll_data (a_, struct extremum, ll);
51   const struct extremum *b = ll_data (b_, struct extremum, ll);
52
53   if ( a->value < b->value) return -1;
54
55   return (a->value > b->value);
56 }
57
58
59 struct extrema *
60 extrema_create (size_t n, enum extreme_end end)
61 {
62   struct extrema *extrema = xzalloc (sizeof *extrema);
63   extrema->capacity = n;
64
65   if ( end == EXTREME_MAXIMA )
66     extrema->cmp_func = cmp_descending;
67   else
68     extrema->cmp_func = cmp_ascending;
69
70   ll_init (&extrema->list);
71
72   return extrema;
73 }
74
75 void
76 extrema_destroy (struct extrema *extrema)
77 {
78   struct ll *ll = ll_head (&extrema->list);
79
80   while (ll != ll_null (&extrema->list))
81     {
82       struct extremum *e = ll_data (ll, struct extremum, ll);
83
84       ll = ll_next (ll);
85       free (e);
86     }
87
88   free (extrema);
89 }
90
91
92 void
93 extrema_add (struct extrema *extrema, double val,
94              double weight,
95              casenumber location)
96 {
97   struct extremum *e = xzalloc (sizeof *e) ;
98   e->value = val;
99   e->location = location;
100   e->weight = weight;
101
102   if ( val == SYSMIS)
103     {
104       free (e);
105       return;
106     }
107
108   ll_insert_ordered (ll_head (&extrema->list), ll_null (&extrema->list),
109                        &e->ll,  extrema->cmp_func, NULL);
110
111   if ( extrema->n++ > extrema->capacity)
112     {
113       struct ll *tail = ll_tail (&extrema->list);
114       struct extremum *et = ll_data (tail, struct extremum, ll);
115
116       ll_remove (tail);
117
118       free (et);
119     }
120 }
121
122
123 const struct ll_list *
124 extrema_list (const struct extrema *ex)
125 {
126   return &ex->list;
127 }
128
129
130 bool
131 extrema_top (const struct extrema *ex, double *v)
132 {
133   const struct extremum  *top;
134
135   if ( ll_is_empty (&ex->list))
136     return false;
137
138   top = (const struct extremum *)
139     ll_data (ll_head(&ex->list), struct extremum, ll);
140
141   *v = top->value;
142
143   return true;
144 }