wapiti 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.simplecov +3 -0
  3. data/Gemfile +25 -2
  4. data/HISTORY.md +5 -1
  5. data/LICENSE +14 -13
  6. data/README.md +9 -16
  7. data/Rakefile +38 -8
  8. data/ext/wapiti/bcd.c +126 -124
  9. data/ext/wapiti/decoder.c +203 -124
  10. data/ext/wapiti/decoder.h +6 -4
  11. data/ext/wapiti/extconf.rb +2 -2
  12. data/ext/wapiti/gradient.c +491 -320
  13. data/ext/wapiti/gradient.h +52 -34
  14. data/ext/wapiti/lbfgs.c +74 -33
  15. data/ext/wapiti/model.c +47 -37
  16. data/ext/wapiti/model.h +22 -20
  17. data/ext/wapiti/native.c +850 -839
  18. data/ext/wapiti/native.h +1 -1
  19. data/ext/wapiti/options.c +52 -20
  20. data/ext/wapiti/options.h +37 -30
  21. data/ext/wapiti/pattern.c +35 -33
  22. data/ext/wapiti/pattern.h +12 -11
  23. data/ext/wapiti/progress.c +14 -13
  24. data/ext/wapiti/progress.h +3 -2
  25. data/ext/wapiti/quark.c +14 -16
  26. data/ext/wapiti/quark.h +6 -5
  27. data/ext/wapiti/reader.c +83 -69
  28. data/ext/wapiti/reader.h +11 -9
  29. data/ext/wapiti/rprop.c +84 -43
  30. data/ext/wapiti/sequence.h +18 -16
  31. data/ext/wapiti/sgdl1.c +45 -43
  32. data/ext/wapiti/thread.c +19 -17
  33. data/ext/wapiti/thread.h +5 -4
  34. data/ext/wapiti/tools.c +7 -7
  35. data/ext/wapiti/tools.h +3 -4
  36. data/ext/wapiti/trainers.h +1 -1
  37. data/ext/wapiti/vmath.c +40 -38
  38. data/ext/wapiti/vmath.h +12 -11
  39. data/ext/wapiti/wapiti.c +159 -37
  40. data/ext/wapiti/wapiti.h +18 -4
  41. data/lib/wapiti.rb +15 -15
  42. data/lib/wapiti/errors.rb +15 -15
  43. data/lib/wapiti/model.rb +92 -84
  44. data/lib/wapiti/options.rb +123 -124
  45. data/lib/wapiti/utility.rb +14 -14
  46. data/lib/wapiti/version.rb +2 -2
  47. data/spec/spec_helper.rb +29 -9
  48. data/spec/wapiti/model_spec.rb +230 -194
  49. data/spec/wapiti/native_spec.rb +7 -8
  50. data/spec/wapiti/options_spec.rb +184 -174
  51. data/wapiti.gemspec +22 -8
  52. metadata +38 -42
  53. data/.gitignore +0 -5
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Wapiti - A linear-chain CRF tool
3
3
  *
4
- * Copyright (c) 2009-2011 CNRS
4
+ * Copyright (c) 2009-2013 CNRS
5
5
  * All rights reserved.
6
6
  *
7
7
  * Redistribution and use in source and binary forms, with or without
@@ -32,50 +32,68 @@
32
32
  #include "model.h"
33
33
  #include "sequence.h"
34
34
 
35
- /* grd_t:
35
+ /* grd_st_t:
36
36
  * State tracker for the gradient computation. To compute the gradient we need
37
37
  * to perform several steps and communicate between them a lot of intermediate
38
- * values, all these temporary are store in this object.
38
+ * values, all these temporary are stored in this object.
39
39
  * A tracker can be used to compute sequence of length <len> at most, before
40
- * using it you must call grd_check to ensure that the tracker is big enough
40
+ * using it you must call grd_stcheck to ensure that the tracker is big enough
41
41
  * for your sequence.
42
+ * This tracker is used to perform single sample gradient computations or
43
+ * partial gradient computation in online algorithms and for decoding with
44
+ * posteriors.
42
45
  */
43
- typedef struct grd_s grd_t;
44
- struct grd_s {
45
- mdl_t *mdl;
46
- int len; // =T max length of sequence
47
- double *g; // [F] vector where to put gradient updates
48
- double lloss; // loss value for the sequence
49
- double *psi; // [T][Y][Y] the transitions scores
50
- double *psiuni; // [T][Y] | Same as psi in sparse format
51
- size_t *psiyp; // [T][Y][Y] |
52
- size_t *psiidx; // [T][Y] |
53
- size_t *psioff; // [T]
54
- double *alpha; // [T][Y] forward scores
55
- double *beta; // [T][Y] backward scores
56
- double *scale; // [T] scaling factors of forward scores
57
- double *unorm; // [T] normalization factors for unigrams
58
- double *bnorm; // [T] normalization factors for bigrams
59
- int first; // first position where gradient is needed
60
- int last; // last position where gradient is needed
46
+ typedef struct grd_st_s grd_st_t;
47
+ struct grd_st_s {
48
+ mdl_t *mdl;
49
+ uint32_t len; // =T max length of sequence
50
+ double *g; // [F] vector where to put gradient updates
51
+ double lloss; // loss value for the sequence
52
+ double *psi; // [T][Y][Y] the transitions scores
53
+ double *psiuni; // [T][Y] | Same as psi in sparse format
54
+ uint32_t *psiyp; // [T][Y][Y] |
55
+ uint32_t *psiidx; // [T][Y] |
56
+ uint32_t *psioff; // [T]
57
+ double *alpha; // [T][Y] forward scores
58
+ double *beta; // [T][Y] backward scores
59
+ double *scale; // [T] scaling factors of forward scores
60
+ double *unorm; // [T] normalization factors for unigrams
61
+ double *bnorm; // [T] normalization factors for bigrams
62
+ uint32_t first; // first position where gradient is needed
63
+ uint32_t last; // last position where gradient is needed
61
64
  };
62
65
 
63
- grd_t *grd_new(mdl_t *mdl, double *g);
64
- void grd_free(grd_t *grd);
65
- void grd_check(grd_t *grd, int len);
66
+ grd_st_t *grd_stnew(mdl_t *mdl, double *g);
67
+ void grd_stfree(grd_st_t *grd_st);
68
+ void grd_stcheck(grd_st_t *grd_st, uint32_t len);
69
+
70
+ void grd_fldopsi(grd_st_t *grd_st, const seq_t *seq);
71
+ void grd_flfwdbwd(grd_st_t *grd_st, const seq_t *seq);
72
+ void grd_flupgrad(grd_st_t *grd_st, const seq_t *seq);
73
+
74
+ void grd_spdopsi(grd_st_t *grd_st, const seq_t *seq);
75
+ void grd_spfwdbwd(grd_st_t *grd_st, const seq_t *seq);
76
+ void grd_spupgrad(grd_st_t *grd_st, const seq_t *seq);
66
77
 
67
- void grd_fldopsi(grd_t *grd, const seq_t *seq);
68
- void grd_flfwdbwd(grd_t *grd, const seq_t *seq);
69
- void grd_flupgrad(grd_t *grd, const seq_t *seq);
78
+ void grd_logloss(grd_st_t *grd_st, const seq_t *seq);
70
79
 
71
- void grd_spdopsi(grd_t *grd, const seq_t *seq);
72
- void grd_spfwdbwd(grd_t *grd, const seq_t *seq);
73
- void grd_spupgrad(grd_t *grd, const seq_t *seq);
80
+ void grd_dospl(grd_st_t *grd_st, const seq_t *seq);
74
81
 
75
- void grd_logloss(grd_t *grd, const seq_t *seq);
82
+ /* grd_t:
83
+ * Multi-threaded full dataset gradient computer. This is used to compute the
84
+ * gradient by algorithm working on the full dataset at each iterations. It
85
+ * efficiently compute it using the fact it is additive to use as many threads
86
+ * as allowed.
87
+ */
88
+ typedef struct grd_s grd_t;
89
+ struct grd_s {
90
+ mdl_t *mdl;
91
+ grd_st_t **grd_st;
92
+ };
76
93
 
77
- void grd_dospl(grd_t *grd, const seq_t *seq);
78
- double grd_gradient(mdl_t *mdl, double *g, grd_t *grds[]);
94
+ grd_t *grd_new(mdl_t *mdl, double *g);
95
+ void grd_free(grd_t *grd);
96
+ double grd_gradient(grd_t *grd);
79
97
 
80
98
  #endif
81
99
 
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Wapiti - A linear-chain CRF tool
3
3
  *
4
- * Copyright (c) 2009-2011 CNRS
4
+ * Copyright (c) 2009-2013 CNRS
5
5
  * All rights reserved.
6
6
  *
7
7
  * Redistribution and use in source and binary forms, with or without
@@ -24,9 +24,12 @@
24
24
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
25
  * POSSIBILITY OF SUCH DAMAGE.
26
26
  */
27
+ #include <inttypes.h>
27
28
  #include <math.h>
28
29
  #include <stdbool.h>
29
30
  #include <stddef.h>
31
+ #include <stdint.h>
32
+ #include <stdio.h>
30
33
  #include <stdlib.h>
31
34
  #include <string.h>
32
35
 
@@ -58,12 +61,11 @@
58
61
  ******************************************************************************/
59
62
 
60
63
  void trn_lbfgs(mdl_t *mdl) {
61
- const size_t F = mdl->nftr;
62
- const int K = mdl->opt->maxiter;
63
- const int C = mdl->opt->objwin;
64
- const int M = mdl->opt->lbfgs.histsz;
65
- const size_t W = mdl->opt->nthread;
66
- const bool l1 = mdl->opt->rho1 != 0.0;
64
+ const uint64_t F = mdl->nftr;
65
+ const uint32_t K = mdl->opt->maxiter;
66
+ const uint32_t C = mdl->opt->objwin;
67
+ const uint32_t M = mdl->opt->lbfgs.histsz;
68
+ const bool l1 = mdl->opt->rho1 != 0.0;
67
69
  double *x, *xp; // Current and previous value of the variables
68
70
  double *g, *gp; // Current and previous value of the gradient
69
71
  double *pg; // The pseudo-gradient (only for owl-qn)
@@ -72,7 +74,6 @@ void trn_lbfgs(mdl_t *mdl) {
72
74
  double *y[M]; // History value y_k = Δ(g,pg)
73
75
  double p[M]; // ρ_k
74
76
  double fh[C]; // f(x) history
75
- grd_t *grds[W];
76
77
  // Initialization: Here, we have to allocate memory on the heap as we
77
78
  // cannot request so much memory on the stack as this will have a too
78
79
  // big impact on performance and will be refused by the system on non-
@@ -80,22 +81,50 @@ void trn_lbfgs(mdl_t *mdl) {
80
81
  x = mdl->theta;
81
82
  xp = xvm_new(F); g = xvm_new(F);
82
83
  gp = xvm_new(F); d = xvm_new(F);
83
- for (int m = 0; m < M; m++) {
84
+ for (uint32_t m = 0; m < M; m++) {
84
85
  s[m] = xvm_new(F);
85
86
  y[m] = xvm_new(F);
86
87
  }
87
88
  pg = l1 ? xvm_new(F) : NULL;
88
- grds[0] = grd_new(mdl, g);
89
- for (size_t w = 1; w < W; w++)
90
- grds[w] = grd_new(mdl, xvm_new(F));
89
+ grd_t *grd = grd_new(mdl, g);
90
+ // Restore a saved state if user specified one.
91
+ if (mdl->opt->rstate != NULL) {
92
+ const char *err = "invalid state file";
93
+ FILE *file = fopen(mdl->opt->rstate, "r");
94
+ if (file == NULL)
95
+ fatal("failed to open input state file");
96
+ int type, histsz;
97
+ uint64_t nftr;
98
+ if (fscanf(file, "#state#%d#%d#%"SCNu64"\n", &type, &histsz,
99
+ &nftr) != 3)
100
+ fatal("0 %s", err);
101
+ if (type != 0 || histsz != (int)M)
102
+ fatal("state is not compatible");
103
+ for (uint64_t i = 0; i < nftr; i++) {
104
+ uint64_t f;
105
+ if (fscanf(file, "%"PRIu64, &f) != 1)
106
+ fatal("1 %s", err);
107
+ if (fscanf(file, "%la %la", &xp[f], &gp[f]) != 2)
108
+ fatal("2 %s", err);
109
+ for (uint32_t m = 0; m < M; m++) {
110
+ if (fscanf(file, "%la", &s[m][f]) != 1)
111
+ fatal("3 %s", err);
112
+ if (fscanf(file, "%la", &y[m][f]) != 1)
113
+ fatal("4 %s", err);
114
+ }
115
+ }
116
+ for (uint32_t m = 0; m < M; m++)
117
+ p[m] = 1.0 / xvm_dot(y[m], s[m], F);
118
+ fclose(file);
119
+ }
91
120
  // Minimization: This is the heart of the function. (a big heart...) We
92
121
  // will perform iterations until one these conditions is reached
93
122
  // - the maximum iteration count is reached
94
123
  // - we have converged (upto numerical precision)
95
124
  // - the report function return false
96
125
  // - an error happen somewhere
97
- double fx = grd_gradient(mdl, g, grds);
98
- for (int k = 0; !uit_stop && k < K; k++) {
126
+ double fx = grd_gradient(grd);
127
+ for (uint32_t k = 0; !uit_stop && k < K; k++) {
99
128
  // We first compute the pseudo-gradient of f for owl-qn. It is
100
129
  // defined in [3, pp 335(4)]
101
130
  // | ∂_i^- f(x) if ∂_i^- f(x) > 0
@@ -106,7 +135,7 @@ void trn_lbfgs(mdl_t *mdl) {
106
135
  // | ±C if x_i = 0
107
136
  if (l1) {
108
137
  const double rho1 = mdl->opt->rho1;
109
- for (unsigned f = 0; f < F; f++) {
138
+ for (uint64_t f = 0; f < F; f++) {
110
139
  if (x[f] < 0.0)
111
140
  pg[f] = g[f] - rho1;
112
141
  else if (x[f] > 0.0)
@@ -130,13 +159,13 @@ void trn_lbfgs(mdl_t *mdl) {
130
159
  // gradient instead of the true one.
131
160
  xvm_neg(d, l1 ? pg : g, F);
132
161
  if (k != 0) {
133
- const int km = k % M;
134
- const int bnd = (k <= M) ? k : M;
162
+ const uint32_t km = k % M;
163
+ const uint32_t bnd = (k <= M) ? k : M;
135
164
  double alpha[M], beta;
136
165
  // α_i = ρ_j s_j^T q_{i+1}
137
166
  // q_i = q_{i+1} - α_i y_i
138
- for (int i = bnd; i > 0; i--) {
139
- const int j = (k - i + M + 1) % M;
167
+ for (uint32_t i = bnd; i > 0; i--) {
168
+ const uint32_t j = (M + 1 + k - i) % M;
140
169
  alpha[i - 1] = p[j] * xvm_dot(s[j], d, F);
141
170
  xvm_axpy(d, -alpha[i - 1], y[j], d, F);
142
171
  }
@@ -147,12 +176,12 @@ void trn_lbfgs(mdl_t *mdl) {
147
176
  // = I * 1 / ρ_k ||y_k||²
148
177
  const double y2 = xvm_dot(y[km], y[km], F);
149
178
  const double v = 1.0 / (p[km] * y2);
150
- for (size_t f = 0; f < F; f++)
179
+ for (uint64_t f = 0; f < F; f++)
151
180
  d[f] *= v;
152
181
  // β_j = ρ_j y_j^T r_i
153
182
  // r_{i+1} = r_i + s_j (α_i - β_i)
154
- for (int i = 0; i < bnd; i++) {
155
- const int j = (k - i + M) % M;
183
+ for (uint32_t i = 0; i < bnd; i++) {
184
+ const uint32_t j = (M + k - i) % M;
156
185
  beta = p[j] * xvm_dot(y[j], d, F);
157
186
  xvm_axpy(d, alpha[i] - beta, s[j], d, F);
158
187
  }
@@ -163,7 +192,7 @@ void trn_lbfgs(mdl_t *mdl) {
163
192
  // d^k = π(d^k ; v^k)
164
193
  // = π(d^k ; -◇f(x^k))
165
194
  if (l1)
166
- for (size_t f = 0; f < F; f++)
195
+ for (uint64_t f = 0; f < F; f++)
167
196
  if (d[f] * pg[f] >= 0.0)
168
197
  d[f] = 0.0;
169
198
  // 2nd step: we perform a linesearch in the computed direction,
@@ -184,7 +213,7 @@ void trn_lbfgs(mdl_t *mdl) {
184
213
  double gd = l1 ? 0.0 : xvm_dot(g, d, F); // gd = g_k^T d_k
185
214
  double fi = fx;
186
215
  bool err = false;
187
- for (int ls = 1; !uit_stop; ls++, stp *= sc) {
216
+ for (uint32_t ls = 1; !uit_stop; ls++, stp *= sc) {
188
217
  // We compute the new point using the current step and
189
218
  // search direction
190
219
  xvm_axpy(x, stp, d, xp, F);
@@ -192,7 +221,7 @@ void trn_lbfgs(mdl_t *mdl) {
192
221
  // current orthant [3, pp 35]
193
222
  // x^{k+1} = π(x^k + αp^k ; ξ)
194
223
  if (l1) {
195
- for (size_t f = 0; f < F; f++) {
224
+ for (uint64_t f = 0; f < F; f++) {
196
225
  double or = xp[f];
197
226
  if (or == 0.0)
198
227
  or = -pg[f];
@@ -202,7 +231,7 @@ void trn_lbfgs(mdl_t *mdl) {
202
231
  }
203
232
  // And we ask for the value of the objective function
204
233
  // and its gradient.
205
- fx = grd_gradient(mdl, g, grds);
234
+ fx = grd_gradient(grd);
206
235
  // Now we check if the step satisfy the conditions. For
207
236
  // l-bfgs, we check the classical decrease and curvature
208
237
  // known as the Wolfe conditions [2, pp 506]
@@ -221,7 +250,7 @@ void trn_lbfgs(mdl_t *mdl) {
221
250
  break;
222
251
  } else {
223
252
  double vp = 0.0;
224
- for (size_t f = 0; f < F; f++)
253
+ for (uint64_t f = 0; f < F; f++)
225
254
  vp += (x[f] - xp[f]) * d[f];
226
255
  if (fx < fi + vp * 1e-4)
227
256
  break;
@@ -249,7 +278,7 @@ void trn_lbfgs(mdl_t *mdl) {
249
278
  // s_k = x_{k+1} - x_k
250
279
  // y_k = g_{k+1} - g_k
251
280
  // ρ_k = 1 / y_k^T s_k
252
- const int kn = (k + 1) % M;
281
+ const uint32_t kn = (k + 1) % M;
253
282
  xvm_sub(s[kn], x, xp, F);
254
283
  xvm_sub(y[kn], g, gp, F);
255
284
  p[kn] = 1.0 / xvm_dot(y[kn], s[kn], F);
@@ -277,18 +306,30 @@ void trn_lbfgs(mdl_t *mdl) {
277
306
  break;
278
307
  }
279
308
  }
309
+ // Save the optimizer state if requested by the user
310
+ if (mdl->opt->sstate != NULL) {
311
+ FILE *file = fopen(mdl->opt->sstate, "w");
312
+ if (file == NULL)
313
+ fatal("failed to open output state file");
314
+ fprintf(file, "#state#0#%"PRIu32"#%"PRIu64"\n", M, F);
315
+ for (uint64_t f = 0; f < F; f++) {
316
+ fprintf(file, "%"PRIu64, f);
317
+ fprintf(file, " %la %la", xp[f], gp[f]);
318
+ for (uint32_t m = 0; m < M; m++)
319
+ fprintf(file, " %la %la", s[m][f], y[m][f]);
320
+ fprintf(file, "\n");
321
+ }
322
+ fclose(file);
323
+ }
280
324
  // Cleanup: We free all the vectors we have allocated.
281
325
  xvm_free(xp); xvm_free(g);
282
326
  xvm_free(gp); xvm_free(d);
283
- for (int m = 0; m < M; m++) {
327
+ for (uint32_t m = 0; m < M; m++) {
284
328
  xvm_free(s[m]);
285
329
  xvm_free(y[m]);
286
330
  }
287
331
  if (l1)
288
332
  xvm_free(pg);
289
- for (size_t w = 1; w < W; w++)
290
- xvm_free(grds[w]->g);
291
- for (size_t w = 0; w < W; w++)
292
- grd_free(grds[w]);
333
+ grd_free(grd);
293
334
  }
294
335
 
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Wapiti - A linear-chain CRF tool
3
3
  *
4
- * Copyright (c) 2009-2011 CNRS
4
+ * Copyright (c) 2009-2013 CNRS
5
5
  * All rights reserved.
6
6
  *
7
7
  * Redistribution and use in source and binary forms, with or without
@@ -24,8 +24,10 @@
24
24
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
25
  * POSSIBILITY OF SUCH DAMAGE.
26
26
  */
27
+ #include <inttypes.h>
27
28
  #include <stdbool.h>
28
29
  #include <stddef.h>
30
+ #include <stdint.h>
29
31
  #include <stdlib.h>
30
32
  #include <stdio.h>
31
33
  #include <string.h>
@@ -120,8 +122,8 @@ void mdl_free(mdl_t *mdl) {
120
122
  * This reduce the risk of mistakes.
121
123
  */
122
124
  void mdl_sync(mdl_t *mdl) {
123
- const size_t Y = qrk_count(mdl->reader->lbl);
124
- const size_t O = qrk_count(mdl->reader->obs);
125
+ const uint32_t Y = qrk_count(mdl->reader->lbl);
126
+ const uint64_t O = qrk_count(mdl->reader->obs);
125
127
  // If model is already synchronized, do nothing and just return
126
128
  if (mdl->nlbl == Y && mdl->nobs == O)
127
129
  return;
@@ -131,8 +133,8 @@ void mdl_sync(mdl_t *mdl) {
131
133
  // case we also display a warning as this is probably not expected by
132
134
  // the user. If only new observations was added, we will try to expand
133
135
  // the model.
134
- size_t oldF = mdl->nftr;
135
- size_t oldO = mdl->nobs;
136
+ uint64_t oldF = mdl->nftr;
137
+ uint64_t oldO = mdl->nobs;
136
138
  if (mdl->nlbl != Y && mdl->nlbl != 0) {
137
139
  warning("labels count changed, discarding the model");
138
140
  free(mdl->kind); mdl->kind = NULL;
@@ -148,16 +150,16 @@ void mdl_sync(mdl_t *mdl) {
148
150
  mdl->nobs = O;
149
151
  // Allocate the observations datastructure. If the model is empty or
150
152
  // discarded, a new one iscreated, else the old one is expanded.
151
- char *kind = wapiti_xrealloc(mdl->kind, sizeof(char ) * O);
152
- size_t *uoff = wapiti_xrealloc(mdl->uoff, sizeof(size_t) * O);
153
- size_t *boff = wapiti_xrealloc(mdl->boff, sizeof(size_t) * O);
153
+ char *kind = wapiti_xrealloc(mdl->kind, sizeof(char ) * O);
154
+ uint64_t *uoff = wapiti_xrealloc(mdl->uoff, sizeof(uint64_t) * O);
155
+ uint64_t *boff = wapiti_xrealloc(mdl->boff, sizeof(uint64_t) * O);
154
156
  mdl->kind = kind;
155
157
  mdl->uoff = uoff;
156
158
  mdl->boff = boff;
157
159
  // Now, we can setup the features. For each new observations we fill the
158
160
  // kind and offsets arrays and count total number of features as well.
159
- size_t F = oldF;
160
- for (size_t o = oldO; o < O; o++) {
161
+ uint64_t F = oldF;
162
+ for (uint64_t o = oldO; o < O; o++) {
161
163
  const char *obs = qrk_id2str(mdl->reader->obs, o);
162
164
  switch (obs[0]) {
163
165
  case 'u': kind[o] = 1; break;
@@ -176,14 +178,14 @@ void mdl_sync(mdl_t *mdl) {
176
178
  // have to allocate a new vector and copy old values ourself.
177
179
  if (oldF != 0) {
178
180
  double *new = xvm_new(F);
179
- for (size_t f = 0; f < oldF; f++)
181
+ for (uint64_t f = 0; f < oldF; f++)
180
182
  new[f] = mdl->theta[f];
181
183
  xvm_free(mdl->theta);
182
184
  mdl->theta = new;
183
185
  } else {
184
186
  mdl->theta = xvm_new(F);
185
187
  }
186
- for (size_t f = oldF; f < F; f++)
188
+ for (uint64_t f = oldF; f < F; f++)
187
189
  mdl->theta[f] = 0.0;
188
190
  // And lock the databases
189
191
  qrk_lock(mdl->reader->lbl, true);
@@ -197,7 +199,7 @@ void mdl_sync(mdl_t *mdl) {
197
199
  * and labeling.
198
200
  */
199
201
  void mdl_compact(mdl_t *mdl) {
200
- const size_t Y = mdl->nlbl;
202
+ const uint32_t Y = mdl->nlbl;
201
203
  // We first build the new observation list with only observations which
202
204
  // lead to at least one active feature. At the same time we build the
203
205
  // translation table which map the new observations index to the old
@@ -205,29 +207,29 @@ void mdl_compact(mdl_t *mdl) {
205
207
  info(" - Scan the model\n");
206
208
  qrk_t *old_obs = mdl->reader->obs;
207
209
  qrk_t *new_obs = qrk_new();
208
- size_t *trans = wapiti_xmalloc(sizeof(size_t) * mdl->nobs);
209
- for (size_t oldo = 0; oldo < mdl->nobs; oldo++) {
210
+ uint64_t *trans = wapiti_xmalloc(sizeof(uint64_t) * mdl->nobs);
211
+ for (uint64_t oldo = 0; oldo < mdl->nobs; oldo++) {
210
212
  bool active = false;
211
213
  if (mdl->kind[oldo] & 1)
212
- for (size_t y = 0; y < Y; y++)
214
+ for (uint32_t y = 0; y < Y; y++)
213
215
  if (mdl->theta[mdl->uoff[oldo] + y] != 0.0)
214
216
  active = true;
215
217
  if (mdl->kind[oldo] & 2)
216
- for (size_t d = 0; d < Y * Y; d++)
218
+ for (uint32_t d = 0; d < Y * Y; d++)
217
219
  if (mdl->theta[mdl->boff[oldo] + d] != 0.0)
218
220
  active = true;
219
221
  if (!active)
220
222
  continue;
221
- const char *str = qrk_id2str(old_obs, oldo);
222
- const size_t newo = qrk_str2id(new_obs, str);
223
+ const char *str = qrk_id2str(old_obs, oldo);
224
+ const uint64_t newo = qrk_str2id(new_obs, str);
223
225
  trans[newo] = oldo;
224
226
  }
225
227
  mdl->reader->obs = new_obs;
226
228
  // Now we save the old model features informations and build a new one
227
229
  // corresponding to the compacted model.
228
- size_t *old_uoff = mdl->uoff; mdl->uoff = NULL;
229
- size_t *old_boff = mdl->boff; mdl->boff = NULL;
230
- double *old_theta = mdl->theta; mdl->theta = NULL;
230
+ uint64_t *old_uoff = mdl->uoff; mdl->uoff = NULL;
231
+ uint64_t *old_boff = mdl->boff; mdl->boff = NULL;
232
+ double *old_theta = mdl->theta; mdl->theta = NULL;
231
233
  free(mdl->kind);
232
234
  mdl->kind = NULL;
233
235
  mdl->nlbl = mdl->nobs = mdl->nftr = 0;
@@ -235,18 +237,18 @@ void mdl_compact(mdl_t *mdl) {
235
237
  // The model is now ready, so we copy in it the features weights from
236
238
  // the old model for observations we have kept.
237
239
  info(" - Compact it\n");
238
- for (size_t newo = 0; newo < mdl->nobs; newo++) {
239
- const size_t oldo = trans[newo];
240
+ for (uint64_t newo = 0; newo < mdl->nobs; newo++) {
241
+ const uint64_t oldo = trans[newo];
240
242
  if (mdl->kind[newo] & 1) {
241
243
  double *src = old_theta + old_uoff[oldo];
242
244
  double *dst = mdl->theta + mdl->uoff[newo];
243
- for (size_t y = 0; y < Y; y++)
245
+ for (uint32_t y = 0; y < Y; y++)
244
246
  dst[y] = src[y];
245
247
  }
246
248
  if (mdl->kind[newo] & 2) {
247
249
  double *src = old_theta + old_boff[oldo];
248
250
  double *dst = mdl->theta + mdl->boff[newo];
249
- for (size_t d = 0; d < Y * Y; d++)
251
+ for (uint32_t d = 0; d < Y * Y; d++)
250
252
  dst[d] = src[d];
251
253
  }
252
254
  }
@@ -262,15 +264,15 @@ void mdl_compact(mdl_t *mdl) {
262
264
  * Save a model to be restored later in a platform independant way.
263
265
  */
264
266
  void mdl_save(mdl_t *mdl, FILE *file) {
265
- size_t nact = 0;
266
- for (size_t f = 0; f < mdl->nftr; f++)
267
+ uint64_t nact = 0;
268
+ for (uint64_t f = 0; f < mdl->nftr; f++)
267
269
  if (mdl->theta[f] != 0.0)
268
270
  nact++;
269
- fprintf(file, "#mdl#%zu\n", nact);
271
+ fprintf(file, "#mdl#%d#%"PRIu64"\n", mdl->type, nact);
270
272
  rdr_save(mdl->reader, file);
271
- for (size_t f = 0; f < mdl->nftr; f++)
273
+ for (uint64_t f = 0; f < mdl->nftr; f++)
272
274
  if (mdl->theta[f] != 0.0)
273
- fprintf(file, "%zu=%la\n", f, mdl->theta[f]);
275
+ fprintf(file, "%"PRIu64"=%la\n", f, mdl->theta[f]);
274
276
  }
275
277
 
276
278
  /* mdl_load:
@@ -280,15 +282,23 @@ void mdl_save(mdl_t *mdl, FILE *file) {
280
282
  */
281
283
  void mdl_load(mdl_t *mdl, FILE *file) {
282
284
  const char *err = "invalid model format";
283
- size_t nact = 0;
284
- if (fscanf(file, "#mdl#%zu\n", &nact) != 1)
285
- fatal(err);
285
+ uint64_t nact = 0;
286
+ int type;
287
+ if (fscanf(file, "#mdl#%d#%"SCNu64"\n", &type, &nact) == 2) {
288
+ mdl->type = type;
289
+ } else {
290
+ rewind(file);
291
+ if (fscanf(file, "#mdl#%"SCNu64"\n", &nact) == 1)
292
+ mdl->type = 0;
293
+ else
294
+ fatal(err);
295
+ }
286
296
  rdr_load(mdl->reader, file);
287
297
  mdl_sync(mdl);
288
- for (size_t i = 0; i < nact; i++) {
289
- size_t f;
298
+ for (uint64_t i = 0; i < nact; i++) {
299
+ uint64_t f;
290
300
  double v;
291
- if (fscanf(file, "%zu=%la\n", &f, &v) != 2)
301
+ if (fscanf(file, "%"SCNu64"=%la\n", &f, &v) != 2)
292
302
  fatal(err);
293
303
  mdl->theta[f] = v;
294
304
  }