Libraryless. Click here for Pure Java version (1711L/11K/37K).
1 | !752 |
2 | |
3 | // TODO: translator should accept this: "s/Rational/Rat" :-) |
4 | |
5 | static S dataProgID = "#1002049"; // read/save data there |
6 | |
7 | // Numeric quadruple |
8 | static class NQ { |
9 | BigInteger a; |
10 | S b; |
11 | BigInteger c; |
12 | S d; |
13 | |
14 | *() {} |
15 | *(S a, S *b, S c, S *d) { |
16 | this.a = smartBigint(a); |
17 | this.c = smartBigint(c); |
18 | } |
19 | *(BigInteger *a, S *b, BigInteger *c, S *d) {} |
20 | |
21 | public boolean equals(O o) { |
22 | ret stdEq(this, o, "a", "b", "c", "d"); |
23 | } |
24 | |
25 | public S toString() { |
26 | ret a + " " + b + " is " + c + " " + d; |
27 | } |
28 | |
29 | NQ reverse() { |
30 | ret new NQ(c, d, a, b); |
31 | } |
32 | |
33 | bool trivial() { |
34 | ret eq(b, d) && eq(a, c); |
35 | } |
36 | |
37 | bool usable() { |
38 | if (trivial()) ret false; |
39 | if (eq(a, 0) || eq(c, 0)) ret false; |
40 | if (eq(b, d)) ret false; // matchin kinds, non-matching numbers |
41 | ret true; |
42 | } |
43 | } |
44 | |
45 | static new L<NQ> terms; |
46 | |
47 | p { |
48 | load(dataProgID, "terms"); |
49 | } |
50 | |
51 | synchronized answer { |
52 | if (match("* * is * *", s, m) || match("* * are * *", s, m)) { |
53 | NQ nq = new NQ(m.unq(0), simplify(m.unq(1)), m.unq(2), simplify(m.unq(3))); |
54 | if (terms.contains(nq)) |
55 | ret "I know!"; |
56 | terms.add(nq); |
57 | save(dataProgID, "terms"); |
58 | ret "OK, added to theory. Now " + l(terms) + " entries"; |
59 | } |
60 | |
61 | if (match("show theory", s)) { |
62 | ret structure(allToString(terms)); |
63 | } |
64 | |
65 | if (match("how many * * * *", s, m)) { |
66 | S isAre = m.get(1); |
67 | if (litlist("is", "are").contains(toLower(isAre))) { |
68 | BigInteger a = bigint(m.unq(2)); |
69 | S b = m.unq(3); |
70 | S d = m.unq(0); |
71 | Rat c = calc(new Rat(a), b, d); |
72 | if (c == null) |
73 | ret "I don't know"; |
74 | ret a + " " + b + " " + isAre + " " + c.mixed() + " " + d + "!"; |
75 | } |
76 | } |
77 | |
78 | if (match("check theory", s)) |
79 | ret checkTheory(); |
80 | |
81 | if (match("show clusters", s)) |
82 | ret showClusters(); |
83 | } |
84 | |
85 | static Rat calc(Rat a, S b, S d) { |
86 | b = simplify(b); |
87 | d = simplify(d); |
88 | ret calcTransitive(a, b, d, new TreeSet); |
89 | } |
90 | |
91 | // b is the unit we have, d is the unit we're searching for |
92 | static Rat calcTransitive(Rat a, S b, S d, Set<S> seen) { |
93 | print(format("calcTransitive * * * *", a, b, d, structure(seen))); |
94 | if (eq(b, d)) ret a; // done |
95 | if (seen.contains(b)) ret null; |
96 | seen.add(b); |
97 | for (NQ nq : terms) if (nq.usable()) { |
98 | twice { |
99 | if (eq(nq.b, b)) { |
100 | Rat r = calcTransitive(calcForward(nq, a), nq.d, d, seen); |
101 | if (r != null) ret r; |
102 | } |
103 | nq = nq.reverse(); |
104 | } |
105 | } |
106 | null; |
107 | } |
108 | |
109 | static Rat calcForward(NQ nq, Rat a) { |
110 | ret a.multiply(nq.c).divide(nq.a); |
111 | } |
112 | |
113 | static S simplify(S s) { |
114 | ret toSingular(toLower(s)); |
115 | } |
116 | |
117 | static S toSingular(S s) { |
118 | ret dropSuffix("s", s); // yeah it's rough |
119 | } |
120 | |
121 | static BigInteger smartBigint(S s) { |
122 | if (litlist("a", "an", "one").contains(toLower(s))) |
123 | ret bigint(1); |
124 | ret bigint(s); |
125 | } |
126 | |
127 | static S checkTheory() { |
128 | new L<NQ> trivial; |
129 | new L<NQ> valid; |
130 | new L<NQ> invalid; |
131 | for (NQ nq : terms) { |
132 | L<NQ> bucket = nq.trivial() ? trivial : nq.usable() ? valid : invalid; |
133 | bucket.add(nq); |
134 | } |
135 | |
136 | new StringBuilder buf; |
137 | if (!isEmpty(trivial)) |
138 | buf.append(l(trivial) + " trivial: " + joinQuoted(", ", allToString(trivial)) + ".\n"); |
139 | |
140 | if (!isEmpty(invalid)) |
141 | buf.append(l(invalid) + " invalid: " + joinQuoted(", ", allToString(invalid)) + ".\n"); |
142 | |
143 | if (!isEmpty(valid)) |
144 | buf.append(l(valid) + " valid statements.\n"); |
145 | |
146 | L<L<S>> clusters = getClusters(); |
147 | buf.append(l(clusters) + " clusters. "); |
148 | |
149 | int consistent = 0; |
150 | new L<L<S>> inconsistent; |
151 | for (L<S> cluster : clusters) { |
152 | boolean ok = checkCluster(cluster); |
153 | if (ok) ++consistent; else inconsistent.add(cluster); |
154 | } |
155 | |
156 | if (isEmpty(inconsistent)) |
157 | buf.append("All consistent.\n"); |
158 | else { |
159 | buf.append(l(inconsistent) + " cluster(s) inconsistent:\n"); |
160 | for (L<S> cluster : inconsistent) |
161 | buf.append(" " + structure(cluster) + "\n"); |
162 | } |
163 | |
164 | ret trim(buf); |
165 | } |
166 | |
167 | static L<L<S>> getClusters() { |
168 | L<NQ> l = filterByMethod(terms, "usable"); // get all usable terms |
169 | |
170 | // a cluster is a list of concepts. |
171 | // first, make trivial clusters (one per concept). |
172 | |
173 | Map<S, L<S>> clusters = new TreeMap<S, L<S>>(); |
174 | for (NQ nq : l) { |
175 | if (!clusters.containsKey(nq.b)) |
176 | clusters.put(nq.b, litlist(nq.b)); |
177 | if (!clusters.containsKey(nq.d)) |
178 | clusters.put(nq.d, litlist(nq.d)); |
179 | } |
180 | |
181 | // then, merge the clusters. |
182 | |
183 | for (NQ nq : l) { |
184 | L<S> c1 = clusters.get(nq.b), c2 = clusters.get(nq.d); |
185 | if (c1 != c2) { // different clusters, need to merge! |
186 | mergeClusters(clusters, c1, c2); |
187 | } |
188 | } |
189 | |
190 | // IdentitySet would be more efficient, but meh. |
191 | ret asList(new HashSet<L<S>>(clusters.values())); |
192 | } |
193 | |
194 | static S showClusters() { |
195 | L<L<S>> clusters = getClusters(); |
196 | ret l(clusters) + " clusters: " + structure(clusters); |
197 | } |
198 | |
199 | static void mergeClusters(Map<S, L<S>> clusters, L<S> c1, L<S> c2) { |
200 | for (S concept : c2) { |
201 | clusters.put(concept, c1); |
202 | c1.add(concept); |
203 | } |
204 | } |
205 | |
206 | static boolean checkCluster(L<S> cluster) { |
207 | new Map<S, Rat> values; |
208 | |
209 | // randomly choose a concept and a value (!= 0) to start with |
210 | values.put(cluster.get(0), rat(1)); |
211 | |
212 | while true { |
213 | int lastSize = l(values); |
214 | |
215 | for (NQ nq : terms) if (nq.usable()) { |
216 | twice { |
217 | Rat lvalue = values.get(nq.b); |
218 | if (lvalue != null) { |
219 | Rat rvalue = calcForward(nq, lvalue); |
220 | Rat expectedValue = values.get(nq.d); |
221 | if (expectedValue == null) |
222 | values.put(nq.d, rvalue); |
223 | else if (neq(expectedValue, rvalue)) |
224 | ret false; // Cluster is inconsistent! |
225 | } |
226 | nq = nq.reverse(); |
227 | } |
228 | } |
229 | if (l(values) == lastSize) ret true; // all done |
230 | } |
231 | } |
Began life as a copy of #1002049
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, jtubtzbbkimh, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1002072 |
Snippet name: | Conversion Bot (v2, LIVE) |
Eternal ID of this version: | #1002072/1 |
Text MD5: | 37af9c21f669079c45890da4580c8ff5 |
Transpilation MD5: | 449ebd0eb1bb2913c33d07c10efe6ffe |
Author: | stefan |
Category: | |
Type: | JavaX source code |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-01-06 19:41:16 |
Source code size: | 5812 bytes / 231 lines |
Pitched / IR pitched: | No / Yes |
Views / Downloads: | 738 / 1971 |
Referenced in: | [show references] |