Browse Source

integrated math.js into formula evaluation (algorithm incomplete)

Brandon Wong 4 years ago
parent
commit
68a21e4775
2 changed files with 90 additions and 7 deletions
  1. 24 2
      frontend/src/js/index.js
  2. 66 5
      frontend/src/microtables_frontend/core.cljs

+ 24 - 2
frontend/src/js/index.js

@@ -1,5 +1,27 @@
 
-const mathjs = require('mathjs');
+// to include an npm module/package into clojurescript:
+// https://figwheel.org/docs/npm.html
 
-window.mathjs = mathjs;
+// to reduce the bundle size:
+// https://mathjs.org/docs/custom_bundling.html
+
+import { parse, evaluate } from 'mathjs';
+
+function getVariables(expression) {
+    if( !expression || typeof expression !== 'string' ) {
+        console.log('not correct input', expression, typeof expression);
+        return [];
+    }
+    try {
+        const expressionObject = parse(expression);
+        console.log('now returning', expressionObject);
+        return expressionObject.filter(x => x.isSymbolNode).map(x => x.name);
+    }
+    catch(e) {
+        console.error('error in parsing or filtering for variables', e.message || e);
+        return [];
+    }
+}
+
+window.mathjs = {parse, evaluate, getVariables};
 

+ 66 - 5
frontend/src/microtables_frontend/core.cljs

@@ -11,16 +11,14 @@
                   {:row 2 :col "F" :value "8650"}
                   {:row 6 :col "D" :value "4065"}
                   {:row 7 :col "F" :value "5316"}
-                  {:row 1 :col "A" :value "4910"}
                   {:row 12 :col "A" :value "2405"}
                   {:row 5 :col "B" :value "7863"}
                   {:row 9 :col "E" :value "3144"}
                   {:row 10 :col "D" :value "8272"}
-                  {:row 2 :col "F" :value "3013"}
                   {:row 11 :col "D" :value "2495"}
                   {:row 15 :col "E" :value "8968"}])
 
-(def data-atom (r/atom sample-data))
+(defonce data-atom (r/atom sample-data))
 
 (defn highest [dir data] (apply max (map dir data)))
 
@@ -74,11 +72,74 @@
                (map #(row % cols data) (range 1 (inc maxrow)))))
            ]])
 
+(defn temp1 [data]
+  (let [first-order (group-by #(not= (first (:value %)) "=") data)
+        evaluated-cells (map #(keyword (str (:col %) (:row %))) (first-order true))
+        non-evaluated-cells (map #(keyword (str (:col %) (:row %))) (first-order false))
+        evaluated-values (map :value (first-order true))
+        non-evaluated-values (map #(subs (:value %) 1) (first-order false))]
+    {:remaining (zipmap non-evaluated-cells non-evaluated-values)
+     :evaluated (zipmap evaluated-cells evaluated-values)}))
+
+(defn temp2 [evaluated remaining]
+  (if (empty? remaining)
+    evaluated
+    (let [jsvars (map #(.getVariables mathjs (val %)) remaining)
+          vars (js->clj jsvars)
+          remaining-vars (zipmap (keys remaining) vars)
+          evaluated-vars (map (fn [x] (map #(let [item (keyword %)]
+                                              (cond
+                                                (contains? evaluated item) [% (evaluated item)]
+                                                (contains? remaining item) [% :not-yet]
+                                                :else [% 0]
+                                                )) x)) vars)
+          parsed (zipmap (keys remaining) evaluated-vars)
+          ready-or-not (group-by (fn [[ k v ]] (some #(not= :not-yet (last %)) v)) parsed)
+          ;TODO: detect circular references
+          ;prepared (map #([(key %) (.stringify js/JSON (apply js-obj (flatten (val %))))]) (ready-or-not true))
+          ;prepared (map (fn [[k v]] [k (.evaluate mathjs (remaining k) (.stringify js/JSON (apply js-obj (flatten v)))) (.stringify js/JSON (apply js-obj (flatten v)))]) (ready-or-not true))
+          prepared (map (fn [[k v]] [k (.evaluate mathjs (remaining k) (apply js-obj (flatten v)))]) (ready-or-not true))
+          ;TODO: merge new values into data with the :display keyword (or similar)
+          ]
+      ;remaining ; {:B8 B7 * 2, :C7 D1, :B7 C5 + D6}
+      ;remaining-vars ; {:B8 [B7], :C7 [D1], :B7 [C5 D6]}
+      ;parsed ; {:B8 ([B7 :not-yet]), :C7 ([D1 0]), :B7 ([C5 269] [D6 4065])}
+      ;ready-or-not ; {nil [[:B8 ([B7 :not-yet])]], true [[:C7 ([D1 0])] [:B7 ([C5 269] [D6 4065])]]}
+      prepared ; ([:C7 0] [:B7 4334])
+      )
+    )
+  )
+
 (defn app []
   [:div
-   [:h3 "Microtables"]
+   ;[:h3 "Microtables"]
    (do
-     (println (.stringify js/JSON (.parse mathjs "3 + 4")))
+     (println (.stringify js/JSON (.parse mathjs "3 + 4x")))
+     (println (js->clj (.parse js/JSON (.stringify js/JSON (.parse mathjs "3 + 4x")))))
+     (println (type (js->clj (.stringify js/JSON (.parse mathjs "3 + 4x")))))
+     (println (js-obj "a" 2 "b" "one"))
+     (println (type (js-obj "a" 2 "b" "one")))
+     (println (type (.parse mathjs "3 + 4x")))
+     (println (.log js/console (.parse mathjs "3 + 4x")))
+     (println (.keys js/Object (.parse mathjs "3 + 4x")))
+     (println (js->clj (.parse mathjs "3 + 4x")))
+     (println (js->clj (.parse mathjs "3 + 4x") :keywordize-keys true))
+     (println (.-op (.parse mathjs "3 + 4x")))
+     (println (.-fn (.parse mathjs "3 + 4x")))
+     (println (js->clj (.-args (.parse mathjs "3 + 4x"))))
+     (println (.-comment (.parse mathjs "3 + 4x")))
+     (println (.-implicit (.parse mathjs "3 + 4x")))
+     (println (.-value (.parse mathjs "3 + 4x")))
+     (println (second (.-args (.parse mathjs "3 + 4x"))))
+     (println (.-implicit (second (.-args (.parse mathjs "3 + 4x")))))
+     (println (.-op (second (.-args (.parse mathjs "3 + 4x")))))
+     (println (.-fn (second (.-args (.parse mathjs "3 + 4x")))))
+     (println (.evaluate mathjs "3 + 4x" (js-obj "x" 10)))
+     (println (filter #(not= (first (:value %)) "=") @data-atom))
+     (let [rt (temp1 @data-atom)]
+       (do
+         (println rt)
+         (println (temp2 (:evaluated rt) (:remaining rt)))))
      "hi")
    [sheet @data-atom]])