| … | … | @@ -2,6 +2,7 @@ |
| 2 | 2 | // Reuses the planted grammar, exchange clusterer and Eisner parser of ../across-cluster/ac.c unchanged. |
| 3 | 3 | // |
| 4 | 4 | // jt <seed> [--tiers 3000,10000,30000] [--heldout N] [--K 30] [--shuffle] [--explain file] [--log file] [--v1] |
| 5 | // [--v2 word|dj] PREREG-v2 arms (implies the v1 pipeline); adds JT-<arm>-COLL rows |
| 5 | 6 | // --v1 runs the PREREG-v1 learner (layer 0 from word-pair PMI, classes by exchange over attended pairs). |
| 6 | 7 | // C <seed> <tier> <K> <method> <checkpoint> <vmeasure> <m1acc> <senseacc> v1 continuous checkpoints |
| 7 | 8 | // Output rows (stdout): |
| … | … | @@ -18,7 +19,41 @@ |
| 18 | 19 | #define ITERS 10 |
| 19 | 20 | #define BATCH 1000 |
| 20 | 21 | |
| 22 | #define BETA 10.0 |
| 23 | |
| 21 | 24 | static int KJ = 30; |
| 25 | static int MODE = 0; // 0 v1 (class profiles), 1 V2-WORD (neighbour words), 2 V2-DJ (disjuncts); PREREG-v2.md |
| 26 | |
| 27 | static uint64_t fnv_bytes (uint64_t h, const void *p, size_t n); |
| 28 | |
| 29 | // Disjunct table: key = disjunct hash (never 0), row = KJ soft counts. |
| 30 | typedef struct { size_t cap, n; uint64_t *key; double *cnt; } djtab_t; |
| 31 | |
| 32 | static void dj_init (djtab_t *t, size_t cap) { t->cap = cap; t->n = 0; t->key = calloc(cap, sizeof(uint64_t)); t->cnt = calloc(cap * KJ, sizeof(double)); } |
| 33 | static void dj_free (djtab_t *t) { free(t->key); free(t->cnt); } |
| 34 | static double *dj_row (const djtab_t *t, uint64_t k) { |
| 35 | for (size_t i = k & (t->cap - 1);; i = (i + 1) & (t->cap - 1)) { |
| 36 | if (t->key[i] == k) return t->cnt + i * KJ; |
| 37 | if (!t->key[i]) return NULL; |
| 38 | } |
| 39 | } |
| 40 | static double *dj_add (djtab_t *t, uint64_t k) { |
| 41 | double *r = dj_row(t, k); |
| 42 | if (r) return r; |
| 43 | if (2 * (t->n + 1) > t->cap) { |
| 44 | djtab_t g; dj_init(&g, 2 * t->cap); |
| 45 | for (size_t i = 0; i < t->cap; i++) if (t->key[i]) { |
| 46 | size_t j = t->key[i] & (g.cap - 1); |
| 47 | while (g.key[j]) j = (j + 1) & (g.cap - 1); |
| 48 | g.key[j] = t->key[i]; memcpy(g.cnt + j * KJ, t->cnt + i * KJ, sizeof(double) * KJ); |
| 49 | } |
| 50 | g.n = t->n; dj_free(t); *t = g; |
| 51 | } |
| 52 | size_t i = k & (t->cap - 1); |
| 53 | while (t->key[i]) i = (i + 1) & (t->cap - 1); |
| 54 | t->key[i] = k; t->n++; |
| 55 | return t->cnt + i * KJ; |
| 56 | } |
| 22 | 57 | |
| 23 | 58 | // ---------------------------------------------------------------- parameters (all counts) |
| 24 | 59 | |
| … | … | @@ -26,26 +61,38 @@ typedef struct { |
| 26 | 61 | double *pi; // V x KJ : soft count of class z on word w |
| 27 | 62 | double *phL, *phR; // KJ x KJ : soft count of left/right neighbour class y around class z |
| 28 | 63 | double *N; // KJ x KJ : soft count of class pair (left x, right y) within the window |
| 64 | double *psiL, *psiR; // KJ x V : soft count of attended left/right neighbour word around class z (V2-WORD) |
| 65 | djtab_t dj; // disjunct x KJ soft counts (V2-DJ) |
| 29 | 66 | } counts_t; |
| 30 | 67 | |
| 31 | | typedef struct { double *lpi, *lphL, *lphR, *pmi; } params_t; // logs / PMI+ derived from counts |
| 68 | typedef struct { // logs / PMI+ derived from counts |
| 69 | double *lpi, *lphL, *lphR, *pmi; |
| 70 | double *lpsiL, *lpsiR; int *wseen; // V2-WORD |
| 71 | djtab_t dj; double djn[64]; // V2-DJ: copy of the counts and per-class totals |
| 72 | } params_t; |
| 32 | 73 | |
| 33 | 74 | static void counts_alloc (counts_t *c) { |
| 34 | 75 | c->pi = calloc((size_t) V * KJ, sizeof(double)); |
| 35 | 76 | c->phL = calloc((size_t) KJ * KJ, sizeof(double)); c->phR = calloc((size_t) KJ * KJ, sizeof(double)); |
| 36 | 77 | c->N = calloc((size_t) KJ * KJ, sizeof(double)); |
| 78 | c->psiL = calloc((size_t) KJ * V, sizeof(double)); c->psiR = calloc((size_t) KJ * V, sizeof(double)); |
| 79 | dj_init(&c->dj, 1 << 12); |
| 37 | 80 | } |
| 38 | 81 | static void counts_zero (counts_t *c) { |
| 39 | 82 | memset(c->pi, 0, sizeof(double) * V * KJ); memset(c->phL, 0, sizeof(double) * KJ * KJ); |
| 40 | 83 | memset(c->phR, 0, sizeof(double) * KJ * KJ); memset(c->N, 0, sizeof(double) * KJ * KJ); |
| 84 | memset(c->psiL, 0, sizeof(double) * KJ * V); memset(c->psiR, 0, sizeof(double) * KJ * V); |
| 85 | memset(c->dj.key, 0, sizeof(uint64_t) * c->dj.cap); memset(c->dj.cnt, 0, sizeof(double) * c->dj.cap * KJ); c->dj.n = 0; |
| 41 | 86 | } |
| 42 | | static void counts_free (counts_t *c) { free(c->pi); free(c->phL); free(c->phR); free(c->N); } |
| 87 | static void counts_free (counts_t *c) { free(c->pi); free(c->phL); free(c->phR); free(c->N); free(c->psiL); free(c->psiR); dj_free(&c->dj); } |
| 43 | 88 | |
| 44 | 89 | static void params_alloc (params_t *p) { |
| 45 | 90 | p->lpi = malloc(sizeof(double) * V * KJ); |
| 46 | 91 | p->lphL = malloc(sizeof(double) * KJ * KJ); p->lphR = malloc(sizeof(double) * KJ * KJ); p->pmi = malloc(sizeof(double) * KJ * KJ); |
| 92 | p->lpsiL = calloc((size_t) KJ * V, sizeof(double)); p->lpsiR = calloc((size_t) KJ * V, sizeof(double)); p->wseen = calloc(V, sizeof(int)); |
| 93 | dj_init(&p->dj, 1 << 12); |
| 47 | 94 | } |
| 48 | | static void params_free (params_t *p) { free(p->lpi); free(p->lphL); free(p->lphR); free(p->pmi); } |
| 95 | static void params_free (params_t *p) { free(p->lpi); free(p->lphL); free(p->lphR); free(p->pmi); free(p->lpsiL); free(p->lpsiR); free(p->wseen); dj_free(&p->dj); } |
| 49 | 96 | |
| 50 | 97 | // M-step: add-λ smoothing, renormalise; PMI+ over class pairs. |
| 51 | 98 | static void derive (const counts_t *c, params_t *p) { |
| … | … | @@ -69,11 +116,78 @@ static void derive (const counts_t *c, params_t *p) { |
| 69 | 116 | p->pmi[x * KJ + y] = v > 0 ? v : 0; |
| 70 | 117 | } |
| 71 | 118 | free(rs); free(cs); |
| 119 | if (MODE == 1) { // Ψ(v | z) = (n(z, v) + β Σ_y Φ(y | z) P(v | y)) / (n(z) + β) |
| 120 | double *py = calloc(KJ, sizeof(double)), ph[64]; |
| 121 | for (int w = 0; w < V; w++) { |
| 122 | double s = 0; |
| 123 | for (int y = 0; y < KJ; y++) { py[y] += c->pi[(size_t) w * KJ + y]; s += c->pi[(size_t) w * KJ + y]; } |
| 124 | p->wseen[w] = s > 0; |
| 125 | } |
| 126 | for (int side = 0; side < 2; side++) { |
| 127 | const double *n = side ? c->psiR : c->psiL, *lph = side ? p->lphR : p->lphL; |
| 128 | double *l = side ? p->lpsiR : p->lpsiL; |
| 129 | for (int z = 0; z < KJ; z++) { |
| 130 | double nz = 0; |
| 131 | for (int w = 0; w < V; w++) nz += n[(size_t) z * V + w]; |
| 132 | for (int y = 0; y < KJ; y++) ph[y] = exp(lph[z * KJ + y]); |
| 133 | for (int w = 0; w < V; w++) { |
| 134 | if (!p->wseen[w]) { l[(size_t) z * V + w] = 0; continue; } |
| 135 | double b = 0; |
| 136 | for (int y = 0; y < KJ; y++) if (py[y] > 0) b += ph[y] * c->pi[(size_t) w * KJ + y] / py[y]; |
| 137 | l[(size_t) z * V + w] = log((n[(size_t) z * V + w] + BETA * b) / (nz + BETA)); |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | free(py); |
| 142 | } |
| 143 | if (MODE == 2) { |
| 144 | if (p->dj.cap != c->dj.cap) { dj_free(&p->dj); dj_init(&p->dj, c->dj.cap); } |
| 145 | memcpy(p->dj.key, c->dj.key, sizeof(uint64_t) * c->dj.cap); memcpy(p->dj.cnt, c->dj.cnt, sizeof(double) * c->dj.cap * KJ); |
| 146 | p->dj.n = c->dj.n; |
| 147 | for (int z = 0; z < KJ; z++) p->djn[z] = 0; |
| 148 | for (size_t i = 0; i < c->dj.cap; i++) if (c->dj.key[i]) for (int z = 0; z < KJ; z++) p->djn[z] += c->dj.cnt[i * KJ + z]; |
| 149 | } |
| 72 | 150 | } |
| 73 | 151 | |
| 74 | 152 | // ---------------------------------------------------------------- one sentence: layers of attention |
| 75 | 153 | |
| 76 | | typedef struct { double q[MAXN][64], u[MAXN][64], mL[MAXN][64], mR[MAXN][64], alpha[MAXN][MAXN]; int n; } sent_state_t; |
| 154 | #define MAXC 16 |
| 155 | typedef struct { |
| 156 | double q[MAXN][64], u[MAXN][64], mL[MAXN][64], mR[MAXN][64], alpha[MAXN][MAXN]; int n; |
| 157 | uint64_t dj[MAXN]; int nc[MAXN], con[MAXN][MAXC]; // V2-DJ: disjunct of each token; connector = side*64 + class |
| 158 | } sent_state_t; |
| 159 | |
| 160 | // V2-DJ: Eisner over α_tj + α_jt; each token's disjunct = its links in position order, connector |
| 161 | // (side, cl[j]) with side 0 = left, 1 = right. |
| 162 | static void disjuncts (sent_state_t *S, const int *cl) { |
| 163 | int n = S->n, m = n + 1, head[MAXN + 1]; |
| 164 | for (int h = 0; h < m; h++) for (int d = 0; d < m; d++) sc[h][d] = NEG; |
| 165 | for (int d = 1; d < m; d++) sc[0][d] = 0; |
| 166 | for (int i = 0; i < n; i++) for (int j = i + 1; j < n && j - i <= W; j++) { |
| 167 | double v = S->alpha[i][j] + S->alpha[j][i]; |
| 168 | sc[i + 1][j + 1] = sc[j + 1][i + 1] = v > 0 ? v : NEG; |
| 169 | } |
| 170 | eisner(m, head); |
| 171 | for (int t = 0; t < n; t++) { |
| 172 | uint64_t h = 1469598103934665603ULL; |
| 173 | S->nc[t] = 0; |
| 174 | for (int j = 0; j < n; j++) { |
| 175 | if (j == t || (head[t + 1] != j + 1 && head[j + 1] != t + 1)) continue; |
| 176 | int code = (j < t ? 0 : 64) + cl[j]; |
| 177 | h = fnv_bytes(h, &code, sizeof code); |
| 178 | if (S->nc[t] < MAXC) S->con[t][S->nc[t]++] = code; |
| 179 | } |
| 180 | S->dj[t] = h | 1; |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | // V2-DJ: log P(d | z) = log (n(z, d) + β Π Φ_side(y | z)) / (n(z) + β). |
| 185 | static double dj_logp (const params_t *p, const sent_state_t *S, int t, int z) { |
| 186 | const double *row = dj_row(&p->dj, S->dj[t]); |
| 187 | double b = 0; |
| 188 | for (int k = 0; k < S->nc[t]; k++) { int code = S->con[t][k]; b += (code < 64 ? p->lphL : p->lphR)[z * KJ + code % 64]; } |
| 189 | return log(((row ? row[z] : 0) + BETA * exp(b)) / (p->djn[z] + BETA)); |
| 190 | } |
| 77 | 191 | |
| 78 | 192 | // E-step on tokens [o, o+n) of C. Leaves q (final), alpha and messages (final layer) in S. |
| 79 | 193 | static void estep (const corpus_t *C, int o, int n, const params_t *p, sent_state_t *S) { |
| … | … | @@ -115,11 +229,24 @@ static void estep (const corpus_t *C, int o, int n, const params_t *p, sent_stat |
| 115 | 229 | double *m = j < t ? S->mL[t] : S->mR[t]; |
| 116 | 230 | for (int y = 0; y < KJ; y++) m[y] += S->alpha[t][j] * S->q[j][y]; |
| 117 | 231 | } |
| 232 | } |
| 233 | if (MODE == 2) { |
| 234 | int cl[MAXN]; |
| 235 | for (int j = 0; j < n; j++) { int b = 0; for (int z = 1; z < KJ; z++) if (S->q[j][z] > S->q[j][b]) b = z; cl[j] = b; } |
| 236 | disjuncts(S, cl); |
| 237 | } |
| 238 | for (int t = 0; t < n; t++) { |
| 118 | 239 | double mx = -1e300, sum = 0, e[64]; |
| 119 | 240 | const double *lp = p->lpi + (size_t) C->w[o + t] * KJ; |
| 120 | 241 | for (int z = 0; z < KJ; z++) { |
| 121 | 242 | double v = lp[z]; |
| 122 | | for (int y = 0; y < KJ; y++) v += S->mL[t][y] * p->lphL[z * KJ + y] + S->mR[t][y] * p->lphR[z * KJ + y]; |
| 243 | if (MODE == 0) for (int y = 0; y < KJ; y++) v += S->mL[t][y] * p->lphL[z * KJ + y] + S->mR[t][y] * p->lphR[z * KJ + y]; |
| 244 | else if (MODE == 1) { |
| 245 | for (int j = 0; j < n; j++) { |
| 246 | int wj = C->w[o + j]; |
| 247 | if (S->alpha[t][j] > 0 && p->wseen[wj]) v += S->alpha[t][j] * (j < t ? p->lpsiL : p->lpsiR)[(size_t) z * V + wj]; |
| 248 | } |
| 249 | } else v += dj_logp(p, S, t, z); |
| 123 | 250 | e[z] = v; |
| 124 | 251 | if (v > mx) mx = v; |
| 125 | 252 | } |
| … | … | @@ -142,6 +269,11 @@ static void accumulate (const corpus_t *C, int o, const sent_state_t *S, counts_ |
| 142 | 269 | c->phR[z * KJ + y] += S->q[t][z] * S->mR[t][y]; |
| 143 | 270 | } |
| 144 | 271 | } |
| 272 | if (MODE == 1) for (int j = 0; j < n; j++) if (S->alpha[t][j] > 0) { |
| 273 | double *ps = (j < t ? c->psiL : c->psiR) + C->w[o + j]; |
| 274 | for (int z = 0; z < KJ; z++) ps[(size_t) z * V] += S->q[t][z] * S->alpha[t][j]; |
| 275 | } |
| 276 | if (MODE == 2) { double *r = dj_add(&c->dj, S->dj[t]); for (int z = 0; z < KJ; z++) r[z] += S->q[t][z]; } |
| 145 | 277 | double win[64] = { 0 }; |
| 146 | 278 | for (int j = t + 1; j < n && j - t <= W; j++) for (int y = 0; y < KJ; y++) win[y] += S->q[j][y]; |
| 147 | 279 | for (int x = 0; x < KJ; x++) for (int y = 0; y < KJ; y++) c->N[x * KJ + y] += S->q[t][x] * win[y]; |
| … | … | @@ -425,9 +557,12 @@ static void train_v1 (const corpus_t *tr, params_t *p, int **cls_out, double per |
| 425 | 557 | for (int t = 0; t < n; t++) { for (int z = 0; z < KJ; z++) S.q[t][z] = 0; S.q[t][cls[tr->w[o + t]]] = 1; } |
| 426 | 558 | for (int t = 0; t < n; t++) { |
| 427 | 559 | for (int y = 0; y < KJ; y++) { S.mL[t][y] = 0; S.mR[t][y] = 0; } |
| 428 | | if (!word_attention(tr, o, n, t, SW, alpha)) continue; |
| 560 | int ok = word_attention(tr, o, n, t, SW, alpha); |
| 561 | memcpy(S.alpha[t], alpha, sizeof(double) * n); |
| 562 | if (!ok) continue; |
| 429 | 563 | for (int j = 0; j < n; j++) if (alpha[j] > 0) (j < t ? S.mL[t] : S.mR[t])[cls[tr->w[o + j]]] += alpha[j]; |
| 430 | 564 | } |
| 565 | if (MODE == 2) { int cl[MAXN]; for (int j = 0; j < n; j++) cl[j] = cls[tr->w[o + j]]; disjuncts(&S, cl); } |
| 431 | 566 | accumulate(tr, o, &S, &c); |
| 432 | 567 | } |
| 433 | 568 | c.N[0] += perturb; // audit mutation test only |
| … | … | @@ -446,9 +581,20 @@ static uint64_t params_hash (const params_t *p, const int *cls) { |
| 446 | 581 | h = fnv_bytes(h, p->lpi, sizeof(double) * V * KJ); |
| 447 | 582 | h = fnv_bytes(h, p->lphL, sizeof(double) * KJ * KJ); h = fnv_bytes(h, p->lphR, sizeof(double) * KJ * KJ); |
| 448 | 583 | h = fnv_bytes(h, p->pmi, sizeof(double) * KJ * KJ); |
| 584 | if (MODE == 1) { h = fnv_bytes(h, p->lpsiL, sizeof(double) * KJ * V); h = fnv_bytes(h, p->lpsiR, sizeof(double) * KJ * V); } |
| 585 | if (MODE == 2) { h = fnv_bytes(h, p->dj.key, sizeof(uint64_t) * p->dj.cap); h = fnv_bytes(h, p->dj.cnt, sizeof(double) * p->dj.cap * KJ); } |
| 449 | 586 | return fnv_bytes(h, cls, sizeof(int) * V); |
| 450 | 587 | } |
| 451 | 588 | |
| 589 | // X-COLL (PREREG-v2): every occurrence of a word gets the word's most frequent label in lab. |
| 590 | static void collapse (const corpus_t *C, const int *lab, int nlab, int *out) { |
| 591 | int *cnt = calloc((size_t) V * nlab, sizeof(int)), *maj = malloc(sizeof(int) * V); |
| 592 | for (int t = 0; t < C->ntok; t++) cnt[(size_t) C->w[t] * nlab + lab[t]]++; |
| 593 | for (int w = 0; w < V; w++) { int b = 0; for (int l = 1; l < nlab; l++) if (cnt[(size_t) w * nlab + l] > cnt[(size_t) w * nlab + b]) b = l; maj[w] = b; } |
| 594 | for (int t = 0; t < C->ntok; t++) out[t] = maj[C->w[t]]; |
| 595 | free(cnt); free(maj); |
| 596 | } |
| 597 | |
| 452 | 598 | // ---------------------------------------------------------------- main |
| 453 | 599 | |
| 454 | 600 | static corpus_t shuffle_within (corpus_t C, uint64_t seed) { |
| … | … | @@ -476,6 +622,7 @@ int main (int argc, char **argv) { |
| 476 | 622 | else if (!strcmp(argv[i], "--K") && i + 1 < argc) KJ = atoi(argv[++i]); |
| 477 | 623 | else if (!strcmp(argv[i], "--shuffle")) shuffle = 1; |
| 478 | 624 | else if (!strcmp(argv[i], "--v1")) v1 = 1; |
| 625 | else if (!strcmp(argv[i], "--v2") && i + 1 < argc) { v1 = 1; i++; MODE = !strcmp(argv[i], "word") ? 1 : !strcmp(argv[i], "dj") ? 2 : -1; if (MODE < 0) { fprintf(stderr, "--v2 word|dj\n"); return 1; } } |
| 479 | 626 | else if (!strcmp(argv[i], "--explain") && i + 1 < argc) explain_path = argv[++i]; |
| 480 | 627 | else if (!strcmp(argv[i], "--log") && i + 1 < argc) log_path = argv[++i]; |
| 481 | 628 | else if (!strcmp(argv[i], "--tiers") && i + 1 < argc) { |
| … | … | @@ -491,7 +638,7 @@ int main (int argc, char **argv) { |
| 491 | 638 | for (int i = 0; i < ntier; i++) if (tiers[i] > maxt) maxt = tiers[i]; |
| 492 | 639 | corpus_t full = gen_corpus(1000003ULL * seed + 1, maxt), ho = gen_corpus(1000003ULL * seed + 2, nho); |
| 493 | 640 | if (shuffle) { full = shuffle_within(full, 99ULL * seed + 1); ho = shuffle_within(ho, 99ULL * seed + 2); } |
| 494 | | const char *tag = shuffle ? "-SHUF" : ""; |
| 641 | const char *tag = shuffle ? "-SHUF" : "", *nm = MODE == 0 ? "V1" : MODE == 1 ? "V2W" : "V2D"; |
| 495 | 642 | int *lab = malloc(sizeof(int) * ho.ntok); |
| 496 | 643 | params_t p; params_alloc(&p); |
| 497 | 644 | |
| … | … | @@ -519,11 +666,14 @@ int main (int argc, char **argv) { |
| 519 | 666 | k, k ? ck[k - 1] : 0, ck[k], (unsigned long long) sh, (unsigned long long) ph, (unsigned long long) prev, (unsigned long long) h); |
| 520 | 667 | prev = h; |
| 521 | 668 | jt_labels(&ho, &p, lab); score_labels(&ho, lab, KJ, &vm, &m1, &se); |
| 522 | | printf("C\t%d\t%d\t%d\tJT-V1%s\t%d\t%.5f\t%.5f\t%.5f\n", seed, tier, KJ, tag, ck[k], vm, m1, se); |
| 669 | printf("C\t%d\t%d\t%d\tJT-%s%s\t%d\t%.5f\t%.5f\t%.5f\n", seed, tier, KJ, nm, tag, ck[k], vm, m1, se); |
| 523 | 670 | } |
| 524 | 671 | if (log) fclose(log); |
| 525 | | printf("V\t%d\t%d\t%d\tJT-V1%s\t%.5f\t%.5f\t%.5f\n", seed, tier, KJ, tag, vm, m1, se); |
| 526 | | printf("L\t%d\t%d\t%d\tATTN-V1%s\t%.5f\n", seed, tier, KJ, tag, attention_parse_f1(&ho, &p)); |
| 672 | printf("V\t%d\t%d\t%d\tJT-%s%s\t%.5f\t%.5f\t%.5f\n", seed, tier, KJ, nm, tag, vm, m1, se); |
| 673 | int *lc = malloc(sizeof(int) * ho.ntok); |
| 674 | collapse(&ho, lab, KJ, lc); score_labels(&ho, lc, KJ, &vm, &m1, &se); free(lc); |
| 675 | printf("V\t%d\t%d\t%d\tJT-%s-COLL%s\t%.5f\t%.5f\t%.5f\n", seed, tier, KJ, nm, tag, vm, m1, se); |
| 676 | printf("L\t%d\t%d\t%d\tATTN-%s%s\t%.5f\n", seed, tier, KJ, nm, tag, attention_parse_f1(&ho, &p)); |
| 527 | 677 | for (int t = 0; t < ho.ntok; t++) lab[t] = cls[ho.w[t]]; |
| 528 | 678 | score_labels(&ho, lab, KJ, &vm, &m1, &se); |
| 529 | 679 | printf("V\t%d\t%d\t%d\tTYPE-A%s\t%.5f\t%.5f\t%.5f\n", seed, tier, KJ, tag, vm, m1, se); |