File size: 7,827 Bytes
f109bf8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
NB. =============================================================================
NB. Synthetic David — hybrid evidence retrieve (PURE J)
NB. Product path against sql/001 evidence indexes; Python evidence/ stays harness.
NB. Locale: david. Verbs prefixed ev_ to avoid clobbering scorer/execution names.
NB. Smoke embeddings dim 8; production SQL uses vector(1536).
NB. =============================================================================

cocurrent 'david'

NB. --- field accessors (row is boxed list) ------------------------------------
ev_field =: 4 : '> (x { y)'

NB. Open one level if boxed
ev_unbox1 =: 3 : 'if. 32 = 3!:0 y do. > y else. y end.'

NB. --- lowercase + alphanumeric tokens len>1 (lexical stand-in for tsv) -------
EV_AZ =: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
EV_az =: 'abcdefghijklmnopqrstuvwxyz'
EV_alnum =: EV_az , '0123456789'

ev_lc1 =: 3 : 0
  i =. EV_AZ i. y
  if. i < #EV_AZ do. i { EV_az else. y end.
)

ev_lc =: 3 : 'ev_lc1"0 y'

ev_tokens =: 3 : 0
  if. 0 = #y do. 0 $ a: return. end.
  s =. ev_lc , y
  ok =. s e. EV_alnum
  s =. ok } (' ' #~ #s) ,: s
  parts =. <;._1 ' ' , s
  parts =. parts #~ 1 < #&> parts
  ~. parts
)

NB. lexical overlap = |q ∩ c| / |q|  (0 if empty query tokens)
ev_lexical =: 4 : 0
  q =. ev_tokens x
  if. 0 = #q do. 0.0 return. end.
  c =. ev_tokens y
  if. 0 = #c do. 0.0 return. end.
  (# q -. q -. c) % #q
)

NB. cosine similarity of two numeric lists
ev_cosine =: 4 : 0
  a =. , x
  b =. , y
  if. (#a) ~: #b do. 0.0 return. end.
  if. (0 = #a) +. (0 = #b) do. 0.0 return. end.
  na =. %: +/ *: a
  nb =. %: +/ *: b
  if. (0 = na) +. (0 = nb) do. 0.0 return. end.
  (+/ a * b) % (na * nb)
)

NB. Axes for dim-8 smoke query embed (prod = vector(1536) via encoder)
NB.   [cobol, balance, payment, schema, pricing, vol, greek, junk]
EV_AXES =: 'cobol';'balance';'payment';'schema';'pricing';'vol';'greek';'junk'

ev_qembed =: 3 : 0
  toks =. ev_tokens y
  NB. synonym: volatility → vol
  if. (<'volatility') e. toks do. toks =. toks , <'vol' end.
  v =. 0 #~ #EV_AXES
  i =. 0
  while. i < #EV_AXES do.
    if. (i { EV_AXES) e. toks do. v =. 1 i} v end.
    i =. i + 1
  end.
  NB. fallback canned COBOL qvec when axis hits empty but query non-blank
  if. (0 = +/ v) *. (0 < #y) do.
    v =. 0.93 0.91 0.88 0.25 0.05 0 0 0
  end.
  v
)

NB. --- seed corpus (mirrors sql/003 + Python harness columns) -----------------
NB. row: id ; source_id ; source_type ; document_id ; location ;
NB.      content ; authority ; parent_boxed ; embedding (dim 8 smoke)

ev_mk =: 3 : 0
  NB. y already a 9-field boxed row
  y
)

EV_CORPUS =: 0 $ a:

NB. ev_copybook_01
EV_CORPUS =: EV_CORPUS , < ('ev_copybook_01' ; 'src_copybook_acct' ; 'copybook' ; 'ACCTREC.cpy' ; '01-ACCOUNT-BALANCE' ; '01 ACCOUNT-RECORD. 05 ACCOUNT-BALANCE PIC S9(9)V99. 05 PAYMENT-AMOUNT PIC S9(7)V99. 05 LAST-PAYMENT-DATE PIC X(8).' ; 0.95 ; (<'ev_provenance_root') ; 0.95 0.90 0.85 0.20 0.05 0 0 0)

NB. ev_cobol_src_01
EV_CORPUS =: EV_CORPUS , < ('ev_cobol_src_01' ; 'src_cobol_pay' ; 'cobol_source' ; 'PAYROLL.cbl' ; 'PROCEDURE DIVISION / CALC-BALANCE' ; 'COMPUTE ACCOUNT-BALANCE = ACCOUNT-BALANCE - PAYMENT-AMOUNT. IF ACCOUNT-BALANCE < ZERO THEN PERFORM OVERDRAFT-CHECK. MOVE PAYMENT-AMOUNT TO WS-LAST-PAYMENT.' ; 0.90 ; (<'ev_provenance_root') ; 0.92 0.88 0.90 0.15 0.05 0 0 0)

NB. ev_db2_schema_01
EV_CORPUS =: EV_CORPUS , < ('ev_db2_schema_01' ; 'src_db2_acct' ; 'db2_schema' ; 'ACCT.DDL' ; 'TABLE ACCOUNT_BALANCES' ; 'CREATE TABLE ACCOUNT_BALANCES (ACCT_ID CHAR(12), BALANCE DECIMAL(11,2), LAST_PAYMENT DECIMAL(9,2), UPDATED_TS TIMESTAMP).' ; 0.85 ; (<'ev_provenance_root') ; 0.70 0.80 0.55 0.95 0.05 0 0 0)

NB. ev_quant_pricing_01
EV_CORPUS =: EV_CORPUS , < ('ev_quant_pricing_01' ; 'src_quant_report' ; 'quant_report' ; 'PRICING_Q3.pdf' ; 'section:monte_carlo' ; 'Monte Carlo pricing of exotic options. Implied volatility surface and greek sensitivities. No COBOL or account balance fields.' ; 0.80 ; (<'ev_provenance_root') ; 0.05 0.05 0.05 0.05 0.95 0.90 0.85 0.10)

NB. ev_lexical_lift_01 — weak dense, strong lexical (no dense floor)
EV_CORPUS =: EV_CORPUS , < ('ev_lexical_lift_01' ; 'src_glossary' ; 'glossary' ; 'LEGACY-GLOSSARY.txt' ; 'entry:PAYMENT-BALANCE' ; 'cobol payment balance glossary entry: PAYMENT and BALANCE fields on ACCOUNT records in legacy batch.' ; 0.70 ; (<'ev_provenance_root') ; 0.10 0.15 0.10 0.05 0.40 0.35 0.30 0.20)

NB. ev_junk_low_auth — authority ~0.1, no parents
EV_CORPUS =: EV_CORPUS , < ('ev_junk_low_auth' ; 'src_web_scrape' ; 'web_scrape' ; 'random-blog.html' ; 'body' ; 'Someone said COBOL payment balance might work like a spreadsheet. Unverified forum post.' ; 0.10 ; (0 $ a:) ; 0.60 0.55 0.50 0.10 0.10 0 0 0.9)

NB. --- score one row ----------------------------------------------------------
NB. score = dense + lexical + authority - parent_penalty
NB. (no dense floor — lexical can lift weak dense)
NB. x = query ; qvec ; require_parent   y = corpus row
ev_score_row =: 4 : 0
  q =. 0 ev_field x
  qv =. 1 ev_field x
  reqp =. 2 ev_field x
  row =. y
  emb =. 8 ev_field row
  content =. 5 ev_field row
  auth =. 6 ev_field row
  parents =. boxopen 7 ev_field row
  dense =. qv ev_cosine emb
  lex =. q ev_lexical content
  pen =. 0.0
  if. reqp *. (0 = # parents) do. pen =. 1.0 end.
  dense + lex + auth - pen
)

NB. --- retrieve ---------------------------------------------------------------
NB. y = query ; min_authority ; top_k  [; require_parent]
NB. returns boxed list of (evidence_id ; score) sorted score DESC, id ASC
ev_retrieve =: 3 : 0
  args =. y
  q =. 0 ev_field args
  min_a =. 1 ev_field args
  top_k =. 2 ev_field args
  reqp =. 0
  if. 3 < # args do. reqp =. 3 ev_field args end.
  NB. empty / blank query → empty result
  if. 0 = # q do. 0 $ a: return. end.
  if. 0 = # ev_tokens q do. 0 $ a: return. end.
  qv =. ev_qembed q
  ctx =. q ; qv ; reqp
  ids =. 0 $ a:
  scores =. 0 $ 0.0
  i =. 0
  while. i < # EV_CORPUS do.
    row =. ev_unbox1 i { EV_CORPUS
    auth =. 6 ev_field row
    parents =. boxopen 7 ev_field row
    if. auth >: min_a do.
      if. (-. reqp) +. (0 < # parents) do.
        sc =. ctx ev_score_row row
        ids =. ids , < 0 ev_field row
        scores =. scores , sc
      end.
    end.
    i =. i + 1
  end.
  if. 0 = # ids do. 0 $ a: return. end.
  NB. stable: id asc then score desc → ORDER BY score DESC, evidence_id
  ix =. /: ids
  ix =. ix \: ix { scores
  if. top_k < # ix do. ix =. top_k {. ix end.
  out =. 0 $ a:
  j =. 0
  while. j < # ix do.
    k =. j { ix
    out =. out , < ((k { ids) ; k { scores)
    j =. j + 1
  end.
  out
)

NB. peel nested boxes to open string
ev_openstr =: 3 : 0
  v =. y
  while. 32 = 3!:0 v do. v =. > v end.
  v
)

NB. ids only from retrieve result (single-boxed strings)
ev_ids =: 3 : 0
  rs =. y
  out =. 0 $ a:
  i =. 0
  while. i < # rs do.
    out =. out , < ev_openstr 0 ev_field ev_unbox1 i { rs
    i =. i + 1
  end.
  out
)

NB. --- smoke ------------------------------------------------------------------
ev_smoke =: 3 : 0
  q =. 'cobol account payment balance CALC-BALANCE'
  NB. 1) COBOL-ish ranks copybook/cobol/db2 above quant; quant not #1
  r1 =. ev_retrieve q ; 0.5 ; 5 ; 1
  ids1 =. ev_ids r1
  assert. 0 < # ids1
  assert. -. (< 'ev_quant_pricing_01') -: 0 { ids1
  legacy =. 'ev_copybook_01' ; 'ev_cobol_src_01' ; 'ev_db2_schema_01'
  assert. 0 < # (ids1 -. ids1 -. legacy)
  top3 =. 3 <. # ids1
  top3 =. top3 {. ids1
  assert. -. (< 'ev_quant_pricing_01') e. top3
  NB. 2) min_authority 0.5 drops junk
  r2 =. ev_retrieve q ; 0.5 ; 10 ; 0
  ids2 =. ev_ids r2
  assert. -. (< 'ev_junk_low_auth') e. ids2
  r2open =. ev_retrieve q ; 0.0 ; 10 ; 0
  ids2o =. ev_ids r2open
  assert. (< 'ev_junk_low_auth') e. ids2o
  NB. 3) empty query → empty result
  r3 =. ev_retrieve '' ; 0.0 ; 10
  assert. 0 = # r3
  'ok' ; ids1
)