Fork me on GitHub
#clara
<
2017-06-09
>
fabrao13:06:54

Well @jfntn , I used to classify I kind of link status to avoid chains of ifs, but my experience is that it was more complex than I thougth, so I changed to datascript to be more clear and simple

fabrao13:06:12

here is an example what I did

(defn limite [chave]
  (read-string (chave (:referencia (:config sistema)))))

(defrecord IcmpLocalizacao [nome-link localidade jitter latencia perda])
(defrecord Problema [mensagem nome-link localidade])

(defrule ligacao-fragmentada
         [?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (> perda (limite :perda))]
         =>
         (insert! (->Problema :fragmentada ?nome-link ?localidade)))

(defrule telefonia-degradada
         [?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (> jitter (limite :jitter)) (> latencia (limite :latencia)) (<= perda (limite :perda))]
         =>
         (insert! (->Problema :degradada ?nome-link ?localidade)))

(defrule perda-qualidade
         [?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (> jitter (limite :jitter)) (<= latencia (limite :latencia)) (<= perda (limite :perda))]
         =>
         (insert! (->Problema :qualidade ?nome-link ?localidade)))

(defrule atraso-telefonia
         [?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (<= jitter (limite :jitter)) (> latencia (limite :latencia)) (<= perda (limite :perda))]
         =>
         (insert! (->Problema :atraso ?nome-link ?localidade)))

(defrule sem-comunicacao
         [?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (= jitter -1) (= latencia -1) (= perda -1)]
         =>
         (insert! (->Problema :comunicacao_locais ?nome-link ?localidade)))

(defquery problemas-comunicacao []
          [Problema (= ?mensagem mensagem) (= ?nome-link nome-link) (= ?localidade localidade)])

(defn gerar-fatos [fatos]
  (let [regras (atom #{})]
    (doseq [fato fatos]
    (let [link (first (first fato))
          valor (second (first fato))
          localidade (:localidade valor)
          icmp (:icmp valor)
          jitter (:jitter icmp)
          perda (:perda icmp)
          latencia (:latencia icmp)]
    (swap! regras conj (->IcmpLocalizacao link localidade jitter latencia perda))))
    @regras))

(defn compilar-regras [fatos]
  (into #{}
        (-> (mk-session 'correlacao.item.regraslink)
            (insert-all (gerar-fatos fatos))
            (fire-rules)
            (query problemas-comunicacao))))

fabrao13:06:07

in datascript

(defn- classificar-elemento [conn tipo op-jitter op-perda op-latencia jitter perda latencia]
  (let [resultado (d/q '[:find ?localidade ?link
                         :in $ ?op-jitter ?op-perda ?op-latencia ?ref-jitter ?ref-perda ?ref-latencia
                         :where 
                         [?e :link ?link]
                         [?e :localidade ?localidade]
                         [?e :jitter ?jitter]
                         [?e :perda ?perda]
                         [?e :latencia ?latencia]
                         [(?op-jitter ?jitter ?ref-jitter)]
                         [(?op-perda ?perda ?ref-perda)]
                         [(?op-latencia ?latencia ?ref-latencia)]
                         ]
                       conn op-jitter op-perda op-latencia jitter perda latencia)]
    (if (= #{} resultado)
      []
      (resultado->set resultado tipo)
      )))

fabrao13:06:42

(classificar-elemento @conn :fragmentada nevermind > nevermind jitter perda latencia)

fabrao13:06:31

I see that datascript was more flexible, but you can use any other ways to define rules for your job, like in https://github.com/threatgrid/naga or even clojure.logic

mikerod17:06:41

@jfntn I guess I don’t fully grasp your problem statement

mikerod18:06:07

However, Clara has certainly been used in a way that creates logical “groups” and/or “hierarchies” of rules

mikerod18:06:48

You can have intermediary facts inserted that act as “blockers” for some rules, or have some rules not be able to be satisfied until certain facts are present

mikerod18:06:18

However, this isn’t done by “turning off” rules or by excluding rules from the rulebase/session created, instead it is done purely through logical relationships the rules express

mikerod18:06:12

Also, the “type” dispatch function used by Clara rules LHS conditions is pluggable. So you could do things with ad hoc hierarchies of Clojure

mikerod18:06:04

has some details on the custom “fact type” fn (and similarly the associated “ancestors” fn

mikerod18:06:22

I may be speaking way too vague to help answer your question though

jfntn18:06:57

Ok interesting, I guess I was wondering if it was valid to consider an approach where the app dynamically loads/unoads a different session depending on some external state machine

mikerod18:06:14

I think @fabrao may have had some interesting points above too. There is a chance that forward-chaining rules aren’t the best approach to certain sorts of problems

mikerod18:06:06

I would say it is not a good situation to have when your rules end up being of the form: A -> B; B -> C; C -> D; D -> E - when that chain starts to get really long and only one linear flow of logic

mikerod18:06:18

@jfntn well consider one of the compelling strengths of a Rete-based forward chaining rules impl like Clara - it stores a bunch of state to avoid re-calculation of join and non-joining constraints done in previous states of the system

mikerod18:06:41

if you flip from session to session, they will not share any of this state with one another. there is a chance that that is suitable for your needs. I’m just calling it out.

mikerod18:06:22

Also, the time to create a session is typically non-trivial if you have a fair number of rules involved. So often the pattern is to keep the sessions in memory. There will be limitations to how many rule sessions you can store in memory at a time. The size of them is mostly dependent on the number or rules and conditions involved

jfntn18:06:34

So I guess I was assuming you could somehow keep the facts but change the rules, not sure if that makes sense in practice

mikerod18:06:01

@jfntn you could query the facts produced from a fire-rules execution of a session

jfntn18:06:10

This article includes this definition for an fsm:

mikerod18:06:12

and you could insert those facts into any other sessoin that uses them

jfntn18:06:24

(def fsm {'Start          {:init             'Ready}
          'Ready          {:missing-password 'Password-Error
                           :missing-email    'Email-Error
                           :submit           'Submitting}
          'Password-Error {:change-password  'Ready}
          'Email-Error    {:change-email     'Ready}
          'Submitting     {:receive-success  'Success}})

mikerod18:06:32

I believe I just read this a few days ago

mikerod18:06:40

I hadn’t really thought much about it though.

jfntn18:06:18

I was imagining something like rules as transitions instead of keywords, and a sort of recursive definition where the Symbols on the right-hand side could be whole FSMs

mikerod18:06:22

Have you found that it is difficult to express the FSM sort of logic just using 1 session?

jfntn18:06:12

Wouldn’t you have to encode the transitions across many rules though? Maybe I just want something that will define a valid session from recursing over this tree

mikerod18:06:50

It isn’t immediately clear to me how it would look

mikerod18:06:03

Perhaps this article is enough to go off to make a toy example in Clara with 1 session

mikerod18:06:23

But it may not be sophisticated enough to show anything useful - I don’t know

mikerod18:06:06

I’m just trying to find the simplest solution the the problem and I’d hope there would be a nice mapping of the idea to a single session. Just to avoid the details of bouncing around between them

mikerod18:06:19

You could certainly have a map of “session name key” -> session

mikerod18:06:38

and have RHS’s produce a fact that says what is the “next session” to evaluate

mikerod18:06:20

Or to flip that and just have the RHS produce a fact that your outer FSM uses to transition to the next step - I think that is what you said above

fabrao18:06:49

it seems like workflow engine

mikerod18:06:37

JBoss had jBPM I think

mikerod18:06:55

which basically (I believe) is a FSM sort of system that triggers Drools rules at certain stages

mikerod18:06:58

(among other things)

mikerod18:06:22

So I guess the idea came up there as well. I’m still just curious about whether or not a single session can’t express an FSM in the sense of the web app article though

jfntn18:06:06

Seems like it should be possible, but the article is only trying to represent a single FSM, and to extend that definition to a Statechart you have to imagine that each state on the right is not final but can have recursive fsm definitions.

jfntn18:06:29

You’d be able to chart the whole app with something along those lines:

jfntn18:06:33

(def app-statechart
  {'Visitor
   {:login
    {'LoginForm
     {'Start          {:init 'Ready}
      'Ready          {:missing-password 'Password-Error
                       :missing-email    'Email-Error
                       :submit           'Submitting}
      'Password-Error {:change-password 'Ready}
      'Email-Error    {:change-email 'Ready}
      'Submitting     {:receive-success 'Success}}}
    :signup {... }}
   'User  {...}
   'Admin {...}})

jfntn18:06:59

The key distinction is that for a given node in the tree, valid transitions at that state are the union of its and its parents’ transitions (or rules in our case), so rules that are not in this set are illegal

mikerod18:06:01

interesting

fabrao19:06:50

Dont you think clara is too complex for that?

fabrao19:06:51

you can define many ruleset and apply it in your context, so you can dynamic it for your needs

mikerod20:06:49

There is no engine there, but I’m assuming you put it on top of something like datascript

mikerod20:06:58

and I think you end up in a backwards-chaining situation there

mikerod20:06:08

which may be find and fit the need. I think it just comes down to what you want out of it.

mikerod20:06:57

also, you have to consider any performance concerns you may have, clj/cljs support (I think datalog-rules would be fine in either), etc

jfntn22:06:35

No I think conceptually we do want forward chaining and all the caching goodness from clara, just trying to wrap my head around what type of application-level integration we could have