Giter Club home page Giter Club logo

wongi-engine's Introduction

Hi there πŸ‘‹

wongi-engine's People

Contributors

bradleyjames avatar ch4s3 avatar dnurzynski avatar elucid avatar gitter-badger avatar quainjn avatar rcy avatar ricksuggs avatar tonywok avatar ulfurinn avatar viveksoundrapandy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wongi-engine's Issues

Overlays and Statement Generator do not appear to work together

See #61

No idea why, but when we use overlays with a statement generator we are finding that the token doesn't include an overlay.

This fix resolves the problem, but I imagine it'll have some terrible consequence in the future that we haven't noticed yet...

We are invoking the statement generator from within an action like this:

      fact = Wongi::Engine::Template.new(membership, key, value)

      generator = Wongi::Engine::DSL::Action::StatementGenerator.new fact
      generator.rete = rete
      generator.production = production
      generator.execute token

Error while trying to use ANY { option {}}

Hello,

I'm trying to use ANY { option {}} and getting this error:
gems/wongi-engine-0.2.7/lib/wongi-engine/dsl/any_rule.rb:14:in 'option': uninitialized constant Wongi::Engine::DSL::AnyRule::VariantRule (NameError)

Need help in implementing this use case. Say user hate yogurt or cheese or any other milk product, need to generate a triplet {:User, "Milk", :Product}. Unable to make it work and Variant Rule error is also stoping to move forward

milk_products = WEngine.rule "milk-products" do
  forall {
    any {
      option {
        has :User, "yogurt", :Product
        has :User, "cheese", :Product
      }
    }
  }
  make {
    gen :User, "Milk", :Product
  }
end

gen does not work inside an action (and fails silently)

engine.rule "whatever" do
  forall {
    ...
  }
  make {
    gen :This, :Will, :Work
    action { |token|
      gen :This, :Fails, :Silently
    }
  }
end

I'm guessing having this not work inside action kind of required. But having it fail silently makes me sad.

namespaced DSL

Would you accept a PR that wraps the dsl in a module? Just so the methods aren't defined on Object.

For example:

module MyModule
  extend Wongi::DSL # or include
  # ...
  rule "foo" do
    # ...
  end
end

If not willing, what's your motivation for putting them at the top level? I suppose one downside is that it could break other peoples' code who are relying on it being on Object?

Thanks :)

Assignment nodes and overlays

Hi there,

Overlays are fantastic but it seems like assignment nodes should take them into account. If you try adding an assign to that new overlay spec you'll see the test fail. I got around it by passing in the token.wme to the new token in assignment_node's beta_activate.

def beta_activate token, wme = nil, assignments = { }
      children.each do |child|
        child.beta_activate Token.new( child, token, token.wme, { @variable => @body.respond_to?(:call) ? @body.call(token) : @body } )
      end
 end

This makes the overlay test pass, you probably have a better way though, any thoughts?

Help writing rules

I have the following situation in a Rails app.

I have Companies that perform many services (has_and_belongs_to_many :services).
I have Incidents that need certain services (again has_and_belongs_to_many :services).

Now I need to find all Companies that offer the services needed by a certain Incident. Im not able to wrap my head around the DSL and come up with rules. Would love some help with this πŸ‘

Is there a safe way to clone the engine? (deep copy)

I'm looking at this gem duplicate

Duplicate.duplicate(@engine)

What I want to do is create a template wongi engine and reuse it over and over again. Originally I was loading all the rules in to one engine all at once but then the engine seems to be getting too big. So another approach I tried was to load the common rules into the engine once, then copy the engine and use the copy so that the engine is only looking for the most recent "target" facts for matching with all the common facts. Hopefully this makes it a smaller set as I noticed that the matching starts out very fast and then slows down considerably.

Let me know if that's something that makes sense to do. I'm not sure that the deep copy is working correctly because now I see duplicate matches. Since it seems like the engine is very complicated/recursive, not sure the deep copy is a good idea.

I would love to hear your thoughts on this.

Thanks!
-Laura

Add "retroactive" facts to the Engine

As mentioned in the readme: "You can only insert new facts into the current state, "retroactive" facts are not allowed."
But I need to add once deleted facts to the engine.
How can I do that?

And how can I reload the engine with facts.

Strange behavior with opposite rules

Hello.

Getting known with your engine I tried this simple example with opposite rules. As I concern in result two new facts should appear:
Bob, approved, true,
Alice, approved, false.
But the result is strange:
Bob, approved, true,
Bob, approved, false.
Is it a bug or i do something wrong, can you please explain this situation. Thanks in advance.
Regards,
Fokin Eugene.

require 'wongi-engine'
ruleset do
  name "Example"
  rule "more" do
    forall {
      has :Name, "age", :Age
      assert :Age do |age| 
        age >= 10
      end
    }
    make {
      action { |token|
          puts "#{token[:Name]} is approved"
      }
      gen :Name, "approved", true
    }
  end

  rule "less" do
    forall {
      has :Name, "age", :Age
      assert :Age do |age| 
        age < 10
      end
    }
    make {
      action { |token|
          puts "#{token[:Name]} is not approved"
      }
      gen :Name, "approved", false
    }
  end

  rule "self-printer" do
    forall {
        has :A, :B, :C
    }
    make {
        action { |token|
            puts "%s, %s, %s" % [ token[ :A ], token[ :B ], token[ :C ] ]
        }
    }
  end
end

engine = Wongi::Engine.create
engine << Wongi::Engine::Ruleset["Example"]
engine << ["Alice","age",5]
engine << ["Bob","age",15]

wongi:engine development status

how active is wongi:engine development? I came from the Drools background and its development is very active.

we're in the process of moving to Ruby on Rails and wongi:engine is a possible replacement for Drools. I'm wondering how active is it in term of development and maintenance since we plan to use it in production.

Thanks

greater and less matchers not working

I have used greater and less matchers and I can't compare with it.

has :P, "is", :B
greater :B, 10

is not working, says a String cannot be compared.

persistence

Great lib!
Is there any way to persist a rule in a database?

Making a retraction from within a rule yields unexpected results

10.times{|i| engine << [i, :is_number, true]}

engine.rule 'segregate' do
    forall {
      has :Number, :is_number, true
    }
  make {
      action { |token|
        number = token[:Number]
        engine << [number, :is_even, true]
        engine.retract [number, :is_number, true]
      }
    }
  end

engine.each :, :, :true do |item|
puts item
end

This will print all the even as :is_even true and leaves all the odds as :is_number true - even though I didn't test for that. ie. it skips every other one.

Generating a fact's object value based on a previous fact

Hey there, I'm new to rule engines and the Rete algorithm. Learning about it and reading your code has been really fun. Anyway, now that I'm playing around with some rules I was wondering if it were possible to programmatically create new facts based on variables. In other words, is something similar to this supported?

Note: using gen to illustrate what I'm doing, but aware it won't work since it supports static or variable object values.

engine.rule "example" do
    forall {
        has :A, "some_value", :B
    }
    make {
        gen :A, "some_other_value", :B + 1
    }
end

engine << ["test", "some_value", 10]
# resulting in creation of ["test", "some_other_value", 11]

Perhaps this should be done with make and action? Although then it seems like you'd lose easy access to your template variables.

I suppose you could do token.wme.(subject|predicate|object):

engine.rule "example" do
    forall {
        has :A, "some_value", :B
    }
    make {
        action { |token| engine << [token.wme.subject, "some_other_value", token.wme.object + 1] }
    }
end

Is there a better or more appropriate way? It's also possible that my question is misinformed. Either way, thanks for your time and again, appreciate the work you've done :) Let me know if the example is too contrived and I'd be glad to conjure up a more realistic one.

Many rules matching only one subject

Hi,

I have many criteria as rules and I want to match a user to these criteria. e.g.

engine << ["user", "age", 20]
engine << ["user", "state", "CA"]
engine << ["user", "weight", 130]

and I have many rules like the following
forall {
has :A, "age", :Age
less :Age, 30
greater :Age, 20
has :A, "state", "CA"
}

At any point in time there will only be one user.
Is there a way to do this matching more efficiently without having to loop through each rule? Typically one would match a rule to many subjects but I want to do this the other way around, find which rules the subject agrees with.
I tried to have the criteria expressed as facts and the user attributes be rules but I have found it to be difficult to construct combinations.

Thanks!

wongi v0.1.1 and faraday

Hello,

In the new version of wongi (v0.1.1) I note that you open Object class and include Wongi::Engine::DSL module.

class Object
  warn "[DEPRECATION] Future versions of wongi-engine will not define dsl on Object. Please `include Wongi::Engine::DSL` going forward."
  include Wongi::Engine::DSL
end

It caused a problem with faraday gem. Faraday executes the code below:

def url(path, params = nil)
  if path.respond_to? :query
    if query = path.query
      path = path.dup
      path.query = nil
    end
...

The query method is called without params, raising this exception:

wrong number of arguments (0 for 1)

I think that was not a good idea open the Object class and include Wongi::Engine::DSL module. I had to rollback version to fix my problem.

Trouble using gen

I have a rule like:

    eligible_person = rule "Eligible person" do
      forall {
        has :Person, "sex", "Male"
        has :_, "age", :age
        greater :age, 50
      }
      make {
        gen :Person, "eligible_person", true
      }
    end

and another rule like:

    identify_thing = rule "Identify thing" do
      forall {
        has :User, "role", "special_role_for_this_thing"
        maybe :Person, "eligible_person", :EligiblePerson
        maybe :Person, "special_marker", :SpecialMarker
        maybe :Person, "other_thing", :OtherThing

        assert do |token|
          (token[:EligiblePerson] == true && token[:SpecialMarker] != nil) || (token[:OtherThing] != nil && token[:OtherThing] > 25)
        end
      }
    end

I load the engine with facts iteratively, but the effect is basically as follows:

engine = Wongi::Engine.create
engine << ["Joe", "sex", "Male"]
engine << ["Joe", "age", 61]
engine << ["user", "role", "special_role_for_this_thing"]

Then I add the rules roughly like the following:

rules.each do |rule|
  engine << rule
end

They run, but when I pry into the assert in "Identify thing" I see that token[:EligiblePerson] = nil. I'm looking for engine.productions["Identify thing"].size > 0 and can't seem to make the rules work together. However, when I step through Wongi with the debugger in pry, I can see the template for gen making EligiblePerson, and apparently adding it to the engine. But, I can't access that fact for some reason. When I call:

engine.facts.map{|fact| p fact}

I see all of the facts I entered with <<, but not the one made by gen.

Any thoughts on what I'm doing wrong?

Edit for catching nil on token[:OtherThing]
I was able to paste this all into the console to reproduce the behavior I'm seeing in my actual application.

Best approach for creating a rule that accomplishes a reduce operation

Consider this simple scenario

#0 or more facts with "age" predicate
engine << ["mary", "age", 15]
engine << ["paul", "age", 22]
engine << ["fred", "age", 71]

I would like to make gen a new fact that contains the cumulative age of all of the persons (or the average, or any arbitrary reduce block)

My current (presumably naive) approach is to consolidate pairs into incremental "generations"

Let's take the cumulative age example (this is not an implementation, just a series of generations and facts to express how the algorithm works):

# Generation 0
["mary", "age", 15]
["mary", "generation", 0]
["paul", "age", 22]
["paul", "generation", 0]
["fred", "age", 71]
["fred", "generation", 0]

# Sum each tuple of facts (a,b), (b, a), (a,c), (c, a), (b,c), (c,b)
# concatenate the subjects in alphabetical order (to avoid duplicates)
# as the subjects of the new generation

# Generation 1
["mary&paul", "age", 37]
["mary&paul", "generation", 1]
["fred&mary", "age", 86]
["fred&mary", "generation", 1]
["fred&paul", "age", 93]
["fred&paul", "generation", 1]

# Generation 2
["fred&mary&paul", "age", 108]
["fred&mary&paul", "generation", 2]

This approach seems pretty lousy.

Is there a proper way to perform a reduce and make-gen?

maybe not working when facts are added before the rule

You can reproduce by changing maybe_rule_spec.rb like so

it "should pass with missing facts" do

engine << [1, 2, 3]

engine << rule('test') do
  forall {
    has 1, 2, :X
    maybe :X, 4, :Y
  }
end

prod = engine.productions['test']

prod.should have(1).tokens

prod.tokens.first[:X].should == 3
prod.tokens.first[:Y].should be_nil

end

Tutorial example gives error

This example in the tutorial does not seem to work when I combine rules:

my_ruleset = ruleset {
    rule "rule 1" do
        ...
    end
    rule "rule 2" do
        ...
    end
}

engine << my_ruleset

I get this:

undefined method `ruleset' for main:Object (NoMethodError)

Any help or clarity in the doc would be appreciated.

using assign for a false bool value causes 'DefinitionError: unbound variable'

I am creating a rule that should generate new facts.

rule :get_customer_facts do
  for_all {
    has :base_fact, :customer_id, :CustomerId
    assign :Customer do |token|
      Customer.find(token[:CustomerId])
    end
    assign :IsFrozen do |token|
      token[:Customer].frozen? # frozen? returns false
    end
  }
  make {
    gen :CustomerId, :customer_is_frozen, :IsFrozen
  }

When .frozen? returns false in the :IsFrozen assignment, then I get the following error:
Wongi::Engine::DefinitionError: unbound variable IsFrozen in token TOKEN [ 70248794866740 parent=70248783279520 CustomerId => object of {:base_fact :customer_id 40000010} Customer => #<Customer::Unit:0x007fc8238c6b10> IsFrozen => false ]

any matcher question

Hi,

I'm trying to use the any matcher to include "or" conditions, but the engine only matches if the the first option rule is verified.

  • Case 1
engine = Wongi::Engine.create
ruleset "my Rules" do
    rule "error en rojo" do
        forall {
            any {
                option {
                    has :A, :scenario, "OT en rojo"
                }    
                option {
                    has :A, :msisdn, "12345678"
                }    
            }
            has :A, :cliente, "manolito" 
        }
        make {
            action { 
              puts "Es un error en rojo"
            }
        }

    end    
end    
engine << Wongi::Engine::Ruleset["my Rules"]
engine << ["123456", :msisdn, "12345678"]
engine << ["123456", :cliente, "manolito"]
engine << ["123456", :scenario, "OT en rojo"]

Output: Es un error en rojo

  • Case 2
engine = Wongi::Engine.create
ruleset "my Rules" do
    rule "error en rojo" do
        forall {
            any {
                option {
                    has :A, :scenario, "OT en rojo"
                }    
                option {
                    has :A, :msisdn, "12345678"
                }    
            }
            has :A, :cliente, "manolito" 
        }
        make {
            action { 
              puts "Es un error en rojo"
            }
        }

    end    
end    
engine << Wongi::Engine::Ruleset["my Rules"]
engine << ["123456", :msisdn, "12345678"]
engine << ["123456", :cliente, "manolito"]
engine << ["123456", :scenario, "OT en rojos"]

Output:

Dynamic Rules

Hello @ulfurinn,

Is there anyway to build rules based on dynamic dataset.
I have a set of rules in my database. How can I build and add in my engine of dynamic mode.

Thanks!

How to use the engine with OpenStruct object

I would like to try wongi-engine but I get some problems to set it.
I am used to ruleby where I can easily access fields in the OpenStruct objects I want to put in the facts base and do some comparison on them to trigger rules.
I want to be able to see if a node has already recorded an error , and from there trigger an action, and depending on the type of error, remove the facts.

I wonder how I can write the "has" or other matchers.

Each object has a box method so I would like to do obj1.box == obj2.box
and also some other comparisons on other fields too

Thanks
RenΓ©

Custom Action Class deexecute method seems not work

require 'wongi-engine'
include Wongi::Engine::DSL
class MActionClass
  def execute(token)
    p 'execute'
  end
  def deexecute(token)
    p 'deexecute'
  end
end

engine = Wongi::Engine.create

engine.rule 'test' do
  forall {
    has :A, :friend, :B
  }
  make {
    action MActionClass
  }
end

engine << ['tester', :friend, 'tester2']
engine.retract ['tester', :friend, 'tester2']

## output
# "execute"
# "execute"

How does deexecute work ?

Timeline not working properly

We want to load a bunch of past facts into working memory, then snapshot and then handle new facts. (so just two periods). In the example below, I'd expect to see a single output of "Found a 1, 7, 3", but I'm seeing none.

engine = Wongi::Engine.create
engine.debug!

myrule = engine.rule "added 123" do
  forall {
    neg 1, :Number, 3, -1
    has 1, :Number, 3, 0
  }
end

# Past Events
engine << [1, 2, 3]
engine.snapshot!

# New event(s) we are processing
engine << [3, 4, 5]
engine << [4, 5, 6]
engine << [1, 7, 3]

myrule.tokens.each do |token|
  puts "Found a 1, #{token[:Number]},3"
end

Furthermore, if I introduce an action into the rule to output, then instead I see one output of "Found a 1, 2, 3" (output before the first snapshot).. then nothing.

I snapshot again after all facts are added, it outputs "Found a 1, 2, 3" (again) and then "Found a 1, 7, 3". I can't seem to figure out how to load past facts in or use timeline features at all.

Seems very promising for us other than that! Thanks in advance!

How to write ruleset?

I'm developing rails application.
I set up wongi-engine for rule-engine in my application.

I try to write my rule, but I can't.
My rule is to find a member who has a value larger than critical value.
Plz tell me how to write.

following, I tried it.

engine << ["Alex", "Value", 100]
engine << ["Caley", "Value", 200]


master = engine.rule "master" do
  forall {
    greater "Value", 100
  }
end

I expect Caley as the result.

More information about Wongi.

Hi,
First of all, let me thank you for your great work. I am developing my master's thesis using wongi-engine and works fine!
I would like to put a better reference of your work on my thesis. Could you tell me some information about you (name, institution, etc)?
Do you have something else written about Wongi-engine beyond of the Readme file?

Best,
Vagner

Better comments

Hi,

We are considering using wongi-engine, but we are having a hard time understanding the code since there are no comments. Are there any plans to comment the code?

String matches should be exact, not fuzzy

We have a rule:

has :Event, 'program_name', "Level 1 Coaching Certification v2"

It's matching facts like:

[:Event, 'program_name', "Level 1 Coaching Certification"]

(note missing v2)

How to use it to match some patterns and accordingly return a variable

My use case is, let us say, that if a given hash has a particular value for a key, I have to return some other key from the hash. Basically, if I want to use this in an already existing repo deployed on VMs, how would I integrate that?

ds = Network.new

    ds << ruleset {

      rule "type" do
        forall {
          has :A, :type, "Goods"
        }
       make {
           action do
                return true
          end
      end
    }


  return_value =  ds << WME.new( "Sample Product", :type, "Goods" )

How would I achieve this?

rule with DateTime fact and generates fact with string causes an error

engine = Wongi::Engine.create
engine << Wongi::Engine::DSL::rule :active_less_than_1_of_last_7_days do
      for_all {
        has :last_capture_at, :CustomerId, :LastCaptureAt
        any {
          option {
            same :LastCaptureAt, nil
          }
          option {
            assign :SevenDaysAgo do
              Time.current - 7.days
            end
            diff :LastCaptureAt, nil
            less :LastCaptureAt, :SevenDaysAgo
          }
        }
      }
      make {
        gen :decline_reason, :CustomerId, 'active_less_than_1_of_last_7_days'
      }
    end

engine << [:last_cature_at, 'token1', Time.current - 7.days]

callstack:

/Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/core_ext/string/conversions.rb:54:in 'parse': invalid date (ArgumentError)
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/core_ext/string/conversions.rb:54:in 'to_datetime'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/core_ext/date_time/calculations.rb:157:in '<=>'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/core_ext/time/calculations.rb:241:in 'compare_with_coercion'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/time_with_zone.rb:214:in '<=>'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/wme.rb:78:in '=='
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/wme.rb:78:in 'match_member'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/wme.rb:52:in '=~'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'block in find'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/enumerators.rb:6:in '<<'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/enumerators.rb:6:in 'block (2 levels) in new'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/enumerators.rb:5:in 'each'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/enumerators.rb:5:in 'block in new'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'each'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'each'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'find'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'find'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:127:in 'real_assert'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/data_overlay.rb:86:in 'block in process_cascade'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/data_overlay.rb:82:in 'each'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/data_overlay.rb:82:in 'process_cascade'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/data_overlay.rb:63:in 'assert'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:113:in 'assert'
    from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:203:in '<<'
    from ./script/wongi-test.rb:137:in 'load_facts'
    from ./script/wongi-test.rb:183:in '<main>'

Linting Rules

I know this may fall far from what Wongi is intending, but I was hoping you can help me sort out how to do this ;)

We have a bunch of rules that are heavily dependent on certain data being present. Specifically, our rules state things like given form "x" the user answered question "y" in a particular way.

We often run into simple things like name mismatches between the rules and the data.

I'd like to lint the data/rules by confirming that it is possible for a given rule to fire.

So, given something like:

forall {
  has :Event, 'program_name', "Level 1 Coaching Certification" 
  has :Event, 'activity_name', "Redo Exam #1"

}

I want to quickly run through and make sure that the program referenced does indeed include an activity with that name.

So, in a sense, I want to run rules on rules ;) I'd love to setup a "linter ruleset", then load my normal production rulesets as facts to check.

I know that sounds crazy... is it doable?

Thanks in advance!

Question: how to avoid duplicate action

The wongi-engine is really awesome. Its working great except in this case I get the same action called repeatedly and I'm not sure how to avoid that. Any suggestions would be very appreciated.
I have a relationship, where an Event can have an Actor and a Manager. The action should fire for a fact where the Event is in the same location as the manager and the actor. When there is only one location it seems to work but when there are multiple locations then its called duplicate times. Not sure if this is what I should be doing. I changed the scenario a bit because I don't want to publish production code. I have a database of rules and I'm trying to check each event against the matching rules and execute code for matching events.

Thanks!
-Laura
self.engine.rule do
forall {
has :Event, 'actor_distance', :Actor_distance
has :Event, 'manager_distance', :Manager_distance
has :Event, 'manager', :Manager
has :Event, 'actor', :Actor
has :Event, 'location', :Location
has :Manager, 'location', :Location
has :Manager, 'bill_by_event', 1
has :Manager, 'manager_limit', :Manager_limit
has :Manager, 'manager_lt', :Manager_lt
has :Manager, 'manager_gte', :Manager_gte
}
make {
action { |token|
Rails.logger.info("Rules met #{token[:Event]} for manager bill_by_event.")
}
}
end
end

18EEN9E1 status is scheduled
18EEN9E1 actor_distance is 0.1683
18EEN9E1 location is Downtown Chicago
18EEN9E1 actor is actor-49
18EEN9E1 venue is 267
18EEN9E1 manager manager-37
actor-49 bill_by_event is 1
actor-49 location is Downtown Chicago
actor-49 location is San Francisco
manager-37 location is San Fransisco

Token Comparison Not working

Hi,

in my project am using rails and used below code to check the budget is going positive or not . But the variable comparison is not working . Any ideas?

    @@engine.rule("Positive Budget Rule") do
    forall {
        has :id, "budget-expect", :num1
        has :id, "budget-actual", :num2
        greater :num1, :num2
    }           
    make {
        gen "result", "Postitive Trends", :id
    }
    end

How to handle tokens in v0.0.14

I noticed that the handling of tokens has changed between v0.0.13 and .14. How are tokens meant to be used in situations like:

if my_rule_name.tokens.size > 0
    return stuff
end

I can see that the token code gained a new method here and changes a bit here.

Could you give me some advice on how to use the new version so I'm not stuck on v0.0.13?

If you can give me a thorough explanation, I would be happy to help update the docs.

Finding latest fact by date?

Are there any temporal operations where I could for example find the latest fact based on a date.

So for example:

Claim1, "is", "Claim"
Claim2, "is", "Claim"
Claim3, "is", "Claim"

Claim1, "dateofservice", 1/1/2016
Claim2, "dateofservice", 2/1/2016
Claim3, "dateofservice", 3/1/2016

Can I ask the engine to return the latest Claim or the earliest Claim?

Deprecation warning with Ruby 2.2

.rvm/gems/ruby-2.2.0/bundler/gems/wongi-engine-ee696450d9af/lib/wongi-engine/wme.rb:129: warning: Comparable#== will no more rescue exceptions of #<=> in the next release.

I'm not quite sure how to fix this. @ulfurinn any thoughts?

Warnings with JRuby

I'm not sure if this is a problem yet, or just the JVM complaining about nothing.

/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/filter/asserting_test.rb:14 warning: *' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/alpha_memory.rb:48 warning:&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/alpha_memory.rb:52 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/beta/beta_node.rb:130 warning:&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl.rb:6 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl.rb:12 warning:&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl.rb:18 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl.rb:23 warning:&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/dsl_extensions.rb:18 warning: *' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/dsl_extensions.rb:26 warning:' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/dsl_builder.rb:11 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/extension_clause.rb:15 warning:
' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/extension_clause.rb:28 warning: *' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/extension_clause.rb:32 warning:_' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/generic_production_rule.rb:16 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/ncc_production_rule.rb:7 warning:&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/any_rule.rb:9 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/any_rule.rb:15 warning:&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/query.rb:18 warning: _' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/actions/simple_action.rb:7 warning: *' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/ruleset.rb:60 warning:&' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/ruleset.rb:67 warning: &' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/network.rb:148 warning:&' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/network.rb:154 warning: &' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/network.rb:376 warning: Statement not reached.
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/network.rb:377 warning: shadowing outer local variable - template
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/graph.rb:36 warning: Ambiguous first argument; make sure.
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/graph.rb:42 warning: Ambiguous first argument; make sure.

Implementation of wongi

This is my use case:

I have many events in the system like:

user1, create, meeting1
meeting1, has, tag1
meeting1, has, tag2
meeting1, has, tag3
user1, create, meeting2
user2, create, meeting3

The rules are dynamic because is based in the interest of each user. Example:

user3 wants to know of create meetings but with tag 1 or 2.

Now, my questions and search for suggestions. I guess there's a way to write rules like the example case for user3. So not a problem. But:

  1. Any time I create a new event I should add this event as triple in the engine and the engine should have the rules already loaded, no?
  2. Given the rule set can be large, did anyone implement an architecture where the engine rules is keep alive in memory and react to new facts

Enhancement requests: The balance of ruby collection iterators & forall runtime polymorphism

Pretty extensive users of wongi-engine. Glad to see that declarative collections are on the path to becoming first class with collectors.

Two items that would make our lives easier if they were available.

1 #map and #inject for tokens matching a rule

Consider this circumstance

facts_matching_my_rule = rules[:my_rule].tokens
facts_matching_my_rule.each do |token|
    # yada yada
end

Many times I find myself wishing that #map and #inject also worked in these circumstances. I imagine that #map! isn't feasible although it does sound appealing.

2 forall_eval (or if this already exists, then documentation and examples)

The wongi-engine rules can be frustratingly incompatible with a notion of rule inheritance - and while you can combine queries and rules to, in some cases, achieve single inheritance it would really be more idiomatic if we had access to the equivalent of instance_eval for a particular rule - it seems that the notion of a rule's singleton is roughly parallel to a class's singleton. Even if the notion of runtime polymorphism of rules (specifically the forall sections) is infeasible then the addition of an explicit rule inheritance operator would be splendid.

Dynamically add conditions to a rule

Hi,

I have a situation where I need to generate conditions for the rule dynamically based on the user input. For example, this is what am trying to do.

def convert(title, variables)
  engine.rule title do |variables|
    forall {
      has :_, :id, :Id
      variables.each do |v|
        has :Id, v.downcase.to_sym, v.capitalize.to_sym
      end
    }
  end
end 

Similarly for other matchers after has, I want to dynamically set them. However seems like I can't pass any of my variables into the rule block. Is there anyway of doing this? Can I extend the DSL for this functionality? Based on the documentation, it seems that the DSL extension is only for actions. Thanks.

Data overlays

This is something I've had on my mind for a while, and going through old tickets I saw similar concerns from other people, so I decided to get something written.

Generally, a rule engine should be compiled once and reused, because compiling a large rule base can be expensive. However, up until now, data was stored inside logic elements, which means that if you do want to reuse an engine instance, you need to retract all asserted facts, will which retrigger rule execution, which is also expensive.

Data overlays separate facts from logic elements, allowing a user to quickly wipe data from en engine instance.

A minimal example

Overlays can be stackable indefinitely, for data with different lifetimes. #<< called on the engine instance will add facts to #default_overlay, which is globally visible and permanent.

This is intended for 0.2.0.

Dynamically add Conditions to a Rule

Hi,

Is it possible to create a rule with dynamic conditions? Something like the following...

engine = Wongi::Engine.create

engine << ["Joe", "gender", "Male"]
engine << ["Joe", "age", 61]

# Records of conditions with predicates and constraints, as defined by the user.
conditions = Condition.all 

el = engine.rule( "Eligible person" ) do
  forall {
    has :Person, "age", :Age
    conditions.each do |condition|
      #add condition here, e.g. `has :_, condition.predicate, condition.match_value`
    end
  }
end

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.