Apama "within" and "and" operator not execute listener? - operator-keyword

I'd like to build a simple monitor. Who listens for events in a time window and executes a listener. But the listener is not executed. I have a feeling the Apama Engine doesn't support that.
From documentation:
Temporal operations are a common requirement for CEP. For example, we may want to put a time limit on our expressions. The within operator specifies a time in seconds within which the expression must complete, starting from when a constituent template is first activated. The below expression is complete when we receive both a MyEvent and a MyOtherEvent with the appropriate fields inside of 15.0 seconds. To clarify, in this expression the timer starts when either the MyEvent or MyOtherEvent is matched:
on all MyEvent(id="important") and MyOtherEvent(id="important") within 15.0
//Eventdefinition
&FLUSHING(1)
&SETTIME("2019-04-03T14:07:00.0+01:00")
&TIME("2019-04-03T14:07:01.0+01:00") // sec 1
TestEvent("START","1")
&TIME("2019-04-03T14:07:02.0+01:00") // sec 2
TestEvent("BODY_ID","1")
&TIME("2019-04-03T14:07:03.0+01:00") // sec 3
TestEvent("BODY_TYPE","1")
&TIME("2019-04-03T14:07:20.0+01:00") // sec 4
TestEvent("BODY_MODELL","1")
//EPL monitor Rule
on all TestEvent(tag= "BODY_ID") as test
and TestEvent(tag = "START") as test1 within(5.0)
{
log "test" + test.tag at INFO; //never called!
}
-----EDIT------
Another solution is this one, but not beautiful! And you can't access the details of the events.
on all (
TestEvent(tag = "START") as e1
or TestEvent(tag= "BODY_ID") as e2
or TestEvent(tag= "BODY_TYPE") as e3
or TestEvent(tag= "BODY_MODELL") as e4
) -> (//followd by random tag
TestEvent(tag = "START")
or TestEvent(tag = "BODY_ID")
or TestEvent(tag = "BODY_TYPE")
or TestEvent(tag = "BODY_MODELL")
) within(3.0) -> (//followd by random tag
TestEvent(tag = "START")
or TestEvent(tag = "BODY_ID")
or TestEvent(tag = "BODY_TYPE")
or TestEvent(tag = "BODY_MODELL")
) within(3.0) -> (//followd by random tag
TestEvent(tag = "START")
or TestEvent(tag = "BODY_ID")
or TestEvent(tag = "BODY_TYPE")
or TestEvent(tag = "BODY_MODELL")
) within(3.0) {
//Problem: No e1, e2,e3,e4 are not accessible...
}

Why the listener doesn't trigger
For reference see: http://www.apamacommunity.com/documents/10.3.0.2/apama_10.3.0.2_webhelp/apama-webhelp/index.html#page/apama-webhelp%2Fta-DevApaAppInEpl_listening_for_event_patterns_within_a_set_time.html%23
When you run the code an event listener is created that attempts to
match the sequence of events based on the operators you choose. So
on A() within(10.0) listenerAction();
After the correlator sets up this event listener, the event listener
must detect an A event within 10 seconds. If no A event is detected
within 10 seconds, the event expression becomes permanently false and
the correlator subsequently terminates the event listener.
With your expression the 'within' is essentially behaving as above.
on all TestEvent(tag= "BODY_ID") as test
and TestEvent(tag = "START") as test1 within(5.0)
{
log "test" + test.tag at INFO; //never called!
}
The and operator will be false if either operand evaluates to false. That triggers the removal of the Event Listener.
In this case the within will be false if the timeout expires without an event being received. The within is actually with reference to the creation of the event listener because the and has no concept of order or timings. This means that the evaluation returns permanently false and the all doesn't recreate the event template because it will never be true and neither will the and.
If you try to use brackets to force the 'within' to apply to the second event only the same result applies (the timeout is still from listener creation).
If you remove the within and ignore timings then the and works as you expect, either order will trigger the event body. However, there is a side effect that may not be desired, if you had a sequence of events like:
A
B
A
You would trigger the body twice, A+B and B+A because of how the event listener behaves.
Solution
he simplest way to achieve what you want is to use the 'follows' operator and within. Because you want to receive the events in either order we need to use the or operator and specify both with a within.
on all ( ( TestEvent(tag= "BODY_ID") as test
-> TestEvent(tag = "START") as test1 within(5.0))
or
( TestEvent(tag= "START") as test
-> TestEvent(tag = "BODY_ID") as test1 within(5.0)) )
{
log "test" + test.tag at INFO; //never called!
}
When you create the event listener it doesn't evaluate (start the timer) on the right hand side of the '-> ' until either a START or BODY_ID is received. If no event comes in before the timer expires then the listener will terminate as before but it isn't now permanently false and so the 'all' recreates the event listener and waits for the first event to arrive.
See this for more details : listening for event patterns within a set time
Alternative
An Alternative would be to use streams as I mentioned below.
I have looked a little into and this works, but I am not completely sure if this is what you need. There may be a better way to set up the streams so that they do what you need
from t1 in all TestEvent () select t1.tag as tag1
from t2 in all TestEvent ()
within (5.0) select t2.tag as tag2 {
if( ( tag1 = "BODY_ID" and tag2 = "START" ) or
( tag1 = "START" and tag2 = "BODY_ID" ) ) {
log "t1 " + tag1 + " t2 " + tag2 at INFO;
}
}
Checkout the sections around here in the docs : Stream network

Streaming is the magic word:
from t1 in all TestEvent () select t1.tag as tag1
from t2 in all TestEvent ()
within (5.0) select t2.tag as tag2 {
if( ( tag1 = "BODY_ID" and tag2 = "START" ) or
( tag1 = "START" and tag2 = "BODY_ID" ) ) {
log "t1 " + tag1 + " t2 " + tag2 at INFO;
}
}
thanks Caribou!

Related

How to create basic pagination logic in Gatling?

So I am trying to create basic pagination in Gatling but failing miserably.
My current scenario is as follows:
1) First call is always a POST request, the body includes page index 1 and page size 50
{"pageIndex":1,"pageSize":50}
I am then receiving 50 object + the total count of objects on the environment:
"totalCount":232
Since I need to iterate through all objects on the environment, I will need to POST this call 5 time, each time with an updated pageIndex.
My current (failing) code looks like:
def getAndPaginate(jsonBody: String) = {
val pageSize = 50;
var totalCount: Int = 0
var currentPage: Int = 1
var totalPages: Int =0
exec(session => session.set("pageIndex", currentPage))
exec(http("Get page")
.post("/api")
.body(ElFileBody("json/" + jsonBody)).asJson
.check(jsonPath("$.result.objects[?(#.type == 'type')].id").findAll.saveAs("list")))
.check(jsonPath("$.result.totalCount").saveAs("totalCount"))
.exec(session => {
totalCount = session("totalCount").as[Int]
totalPages = Math.ceil(totalCount/pageSize).toInt
session})
.asLongAs(currentPage <= totalPages)
{
exec(http("Get assets action list")
.post("/api")
.body(ElFileBody("json/" + jsonBody)).asJson
.check(jsonPath("$.result.objects[?(#.type == 'type')].id").findAll.saveAs("list")))
currentPage = currentPage+1
exec(session => session.set("pageIndex", currentPage))
pause(Config.minDelayValue seconds, Config.maxDelayValue seconds)
}
}
Currently the pagination values are not assign to the variables that I have created at the beginning of the function, if I create the variables at the Object level then they are assigned but in a manner which I dont understand. For example the result of Math.ceil(totalCount/pageSize).toInt is 4 while it should be 5. (It is 5 if I execute it in the immediate window.... I dont get it ). I would than expect asLongAs(currentPage <= totalPages) to repeat 5 times but it only repeats twice.
I tried to create the function in a class rather than an Object because as far as I understand there is only one Object. (To prevent multiple users accessing the same variable I also ran only one user with the same result)
I am obviously missing something basic here (new to Gatling and Scala) so any help would be highly appreciated :)
using regular scala variables to hold the values isn't going to work - the gatling DSL defines builders that are only executed once at startup, so lines like
.asLongAs(currentPage <= totalPages)
will only ever execute with the initial values.
So you just need to handle everything using session variables
def getAndPaginate(jsonBody: String) = {
val pageSize = 50;
exec(session => session.set("notDone", true))
.asLongAs("${notDone}", "index") {
exec(http("Get assets action list")
.post("/api")
.body(ElFileBody("json/" + jsonBody)).asJson
.check(
jsonPath("$.result.totalCount")
//transform lets us take the result of a check (and an optional session) and modify it before storing - so we can use it to get store a boolean that reflects whether we're on the last page
.transform( (totalCount, session) => ((session("index").as[Int] + 1) * pageSize) < totalCount.toInt)
.saveAs("notDone")
)
)
.pause(Config.minDelayValue seconds, Config.maxDelayValue seconds)
}
}

Merging multiple streams, keeping ordering and avoiding duplicates

I have a problem that I do not know how to handle beautifully with RX.
I have multiple streams that all supposedly contain the same elements
However​ each stream may lose messages (UDP is involved) or be late/early compared to others. Each of these messages have a sequence number.
Now what I want to achieve is get a single stream out of all those streams, ​without duplicate and keeping the message order​. In other words, the same sequence number should not appear twice and their values only have to increase, never decrease.
When a message was lost on all the streams, I'm OK with losing it (as there is another TCP mechanism involved that allows me to ask explicitly for missing messages).
I am looking to do that in RxJava, but I guess my problem is not specific to Java.
Here's a marble diagram to help visualizing what I want to achieve:
marble diagram
You can see in that diagram that we are waiting for 2 on the first stream to output 3 from the second stream.
Likewise, 6 is only outputted once we receive 6 from the second stream because only at that point can we know for sure that 5 will never be received by any stream.
This is browser code, but I think it should give you a good idea of how you could solve this.
public static IObservable<T> Sequenced<T>(
this IObservable<T> source,
Func<T, int> getSequenceNumber,
int sequenceBegin,
int sequenceRedundancy)
{
return Observable.Create(observer =>
{
// The next sequence number in order.
var sequenceNext = sequenceBegin;
// The key is the sequence number.
// The value is (T, Count).
var counts = new SortedDictionary<int, Tuple<T, int>>();
return source.Subscribe(
value =>
{
var sequenceNumber = getSequenceNumber(value);
// If the sequence number for the current value is
// earlier in the sequence, just throw away this value.
if (sequenceNumber < sequenceNext)
{
return;
}
// Update counts based on the current value.
Tuple<T, int> count;
if (!counts.TryGetValue(sequenceNumber, out count))
{
count = Tuple.Create(value, 0);
}
count = Tuple.Create(count.Item1, count.Item2 + 1);
counts[sequenceNumber] = count;
// If the current count has reached sequenceRedundancy,
// that means any seqeunce values S such that
// sequenceNext < S < sequenceNumber and S has not been
// seen yet will never be seen. So we emit everything
// we have seen up to this point, in order.
if (count.Item2 >= sequenceRedundancy)
{
var removal = counts.Keys
.TakeWhile(seq => seq <= sequenceNumber)
.ToList();
foreach (var seq in removal)
{
count = counts[seq];
observer.OnNext(count.Item1);
counts.Remove(seq);
}
sequenceNext++;
}
// Emit stored values as long as we keep having the
// next sequence value.
while (counts.TryGetValue(sequenceNext, out count))
{
observer.OnNext(count.Item1);
counts.Remove(sequenceNext);
sequenceNext++;
}
},
observer.OnError,
() =>
{
// Emit in order any remaining values.
foreach (var count in counts.Values)
{
observer.OnNext(count.Item1);
}
observer.OnCompleted();
});
});
}
If you have two streams IObservable<Message> A and IObservable<Message> B, you would use this by doing Observable.Merge(A, B).Sequenced(msg => msg.SequenceNumber, 1, 2).
For your example marble diagram, this would look like the following, where the source column shows the values emitted by Observable.Merge(A, B) and the counts column shows the contents of the SortedDictionary after each step of the algorithm. I am assuming that the "messages" of the original source sequence (without any lost values) is (A,1), (B,2), (C,3), (D,4), (E,5), (F,6) where the second component of each message is its sequence number.
source | counts
-------|-----------
(A,1) | --> emit A
(A,1) | --> skip
(C,3) | (3,(C,1))
(B,2) | (3,(C,1)) --> emit B,C and remove C
(D,4) | --> emit D
(F,6) | (6,(F,1))
(F,6) | (6,(F,2)) --> emit F and remove
A similar question came up a while ago and I have a custom merge operator that when given ordered streams, it merges them in order but doesn't do deduplication.
Edit:
If you can "afford" it, you can use this custom merge and then distinctUntilChanged(Func1) to filter out subsequent messages with the same sequence number.
Observable<Message> messages = SortedMerge.create(
Arrays.asList(src1, src2, src3), (a, b) -> Long.compare(a.id, b.id))
.distinctUntilChanged(v -> v.id);

Dealing with recursion/sync-loops in coffeescript

Right now I'm trying to build some code to handle lists over 100 items, as returned by the Amazon API endpoints. This requires building page-support into our data-gathering routines. This is my first time doing much with coffeescript, so I'm running into some conceptual walls here.
In a less async language, what I'm trying to do would be handleable using an until loop:
puts "Fetching launch configs"
next_token = ''
do
if next_token.length > 0
page_list = get_autoscale_configs(next_token)
else
page_list = get_autoscale_configs
if page_list.NextToken is undefined
next_token = ''
else
next_token = page_list.NextToken
until(next_token.length == 0)
The method of doing this in coffeescript is eluding me. What I have now...
populate_configs = ( ) ->
process_results = ( err data ) ->
if err
return err
# do some logic
if data.NextToken
saved.next_token = data.NextToken
else
saved.next_token = ''
return console.log "Finished parsing #{data.LaunchConfigurations.length} items."
if saved.next_token = ''
autoscaling.describeLaunchConfigurations {
MaxRecords: 100, StartToken: next_token
}, ( err, data ) -> process_results( err, data )
else
autoscaling.describeLaunchConfigurations {
MaxRecords: 100
}, ( err, data ) -> process_results( err, data )
And then in the body of the code, this function is invoked:
saved = {}
async.series [
( series_cb ) ->
saved.next_token = ''
async.doWhilst populate_configs,
saved.next_token.length > 4,
( err ) ->
if err
# complain about it.
# else, log success
return series_cb()
# more callbacks
]
The idea here being that populate_configs is called by doWhilst, which then fetches a list of launch_configs out of amazon. The data is then passed into another function called process_results, which persists things that should be persisted and sets variables for next_token. It returns, and doWhilst tests to see if the test is passing (the string-length of saved.next_token is long enough to be data); if it passes, it runs through populate_configs again, if it fails, it runs the third callback.
What I'm getting right now is that the first iteration of that populate_configs block is executed, but then the entire execution stops dead at that point. None of the calls in the error-handler of doWhilst are being executed.
Clearly, I'm misunderstanding how callbacks work and how to get myself out of this hole. This part needs to be synchronous. Once I have this list built, I can do all sorts of async fun with the list I'm building. But I need the list first.
I think the issue is here: if saved.next_token = ''. You set next_token to '' so populate_configs runs only once. The comparaison is done with == or is in CoffeeScript.
Also, ( err, data ) -> process_results( err, data ) can be replaced by process_results.

RX misunderstood behavior

I have the below repro code which demonstrate a problem in a more complex flow:
static void Main(string[] args)
{
var r = Observable.Range(1, 10).Finally(() => Console.WriteLine("Disposed"));
var x = Observable.Create<int>(o =>
{
for (int i = 1; i < 11; i++)
{
o.OnNext(i);
}
o.OnCompleted();
return Disposable.Create(() => Console.WriteLine("Disposed"));
});
var src = x.Publish().RefCount();
var a = src.Where(i => i % 2 == 0).Do(i => Console.WriteLine("Pair:" + i));
var b = src.Where(i => i % 2 != 0).Do(i => Console.WriteLine("Even:" + i));
var c = Observable.Merge(a, b);
using (c.Subscribe(i => Console.WriteLine("final " + i), () => Console.WriteLine("Complete")))
{
Console.ReadKey();
}
}
running this snippet with r as src (var src = r.Publish().RefCount()) will produce all the numbers from 1 till 10,
switching the src to x(like in example) will produce only the pairs, actually the first observable to subscribe unless i change Publish() to Replay().
Why? What is the difference between r and x?
Thanks.
Although I do not have the patience to sort through the Rx.NET source code to find exactly what implementation detail causes this exact behavior, I can provide the following insight:
The difference in behavior your are seeing is caused by a race condition. The racers in this case are the subscriptions of a and b which happen as a result of your subscription to the observable returned by Observable.Merge. You subscribe to c, which in turn subscribes to a and b. a and b are defined in terms of a Publish and RefCount of either x or r, depending on which case you choose.
Here's what's happening.
src = r
In this case, you are using a custom Observable. When subscribed to, your custom observible immediately and synchronously begins to onNext the numbers 1 though 10, and then calls onCompleted. Interestingly enough, this subscription is caused by your Publish().RefCount() Observable when it is subscribe to the first time. It is subscribed to the first time by a, because a is the first parameter to Merge. So, before Merge has even subscribed to b, your subscription has already completed. Merge subscribes to b, which is the RefCount observable. That observable is already completed, so Merge looks for the next Observable to merge. Since there are no more Observables to merge, and because all of the existing Observables have completed, the merged observable completes.
The values onNext'd through your custom observable have traveled through the "pairs" observable, but not the "evens" observable. Therefore, you end up with the following:
// "pairs" (has this been named incorrectly?)
[2, 4, 6, 8, 10]
src = x
In this case, you are using the built-in Range method to create an Observable. When subscribed to, this Range Observable does something that eventually ends up yielding the numbers 1 though 10. Interesting. We haven't a clue what's happening in that method, or when it's happening. We can, however, make some observations about it. If we look at what happens when src = r (above), we can see that only the first subscription takes effect because the observable is yielding immediately and synchronously. Therefore, we can determine that the Range Observable must not be yielding in the same manner, but instead allows the application's control flow to execute the subscription to b before any values are yielded. The difference between your custom Observable and this Range Observable, is probably that the Range Observable is scheduling the yields to happen on the CurrentThread Scheduler.
How to avoid this kind of race condition:
var src = a.Publish(); // not ref count
var a = src.where(...);
var b = src.where(...);
var c = Observable.Merge(a, b);
var subscription = c.Subscribe(i => Console.WriteLine("final " + i), () => Console.WriteLine("Complete"))
// don't dispose of the subscription. The observable creates an auto-disposing subscription which will call dispose once `OnCompleted` or `OnError` is called.
src.Connect(); // connect to the underlying observable, *after* merge has subscribed to both a and b.
Notice that the solution to fixing the subscription to this composition of Observables was not to change how the source observable works, but instead to make sure your subscription logic isn't allowing any race conditions to exist. This is important, because trying to fix this problem in the Observable is simply changing behavior, not fixing the race. Had we changed the source and switched it out later, the subscription logic would still be buggy.
I suspect it's the schedulers. This change causes the two to behave identically:
var x = Observable.Create<int>(o =>
{
NewThreadScheduler.Default.Schedule(() =>
{
for (int i = 1; i < 11; i++)
{
o.OnNext(i);
}
o.OnCompleted();
});
return Disposable.Create(() => Console.WriteLine("Disposed"));
});
Whereas using Scheduler.Immediate gives the same behavior as yours.

Subtracting using minus function in alloy

I have created a vending machine it works fine. I want to subtract 1 from the quantity of items once the transaction is completed. I have provided comments in my code for understanding. Ignore some of the comments in pred chocolate. Somehow I am trying to subtract but it just wont. I don't know what seems to be the problem. Any help is appreciated .
sig button {
qty:Int} // buttons on vending machine for selecting chocolates
//sig coin{}
sig choco{
value:Int, // Each chocolate has some cost as an attribute aka value.
choice :one button // Selecting option
}
fact {
// all c:choco | all c1:choco -c | c1.choice != c.choice
}
sig machine{
cust : one customer, // Customer entity
a,b,c,d,nullb ,ip: one button, // buttons on vending machine ,ip is the input selected by user
//oners,twors,fivers ,tenrs,null1: set coin,
ipp,opc2 : one Coin, // ipp = input rs , opc = balance rs
customeripb: cust one -> one ip, // customer presses a button
customeripc: cust one -> one ipp, // customer enters coins
customeropc: opc2 one -> one cust, //customer receives balance of coins
op: one choco , // output of chocolate from machine
customerop: op one -> one cust, // customer receives a chocolate
cadbury, kitkat, eclairs , gum,null: lone choco // types of chocolate
}
{
//#(fivers+tenrs+null+twors+oners) = 5
#(a+b+c+d) = 4 // no of buttons of a b c and d are 4 on machine
# (cadbury+kitkat+ eclairs +gum) =4 // no of options to choose = 4
cadbury=choice.a // cadbury corresponds to button a
cadbury.value= 10 // cadbury costs 10rs
kitkat=choice.b // kitkat corresponds to button b
kitkat.value=5 // kitkat costs 5rs
null.value=0 // null costs 0 rs
null=choice.nullb
// as such null doesnt exist it is just to specify no i/p no o/p and nulb is an imaginary button
eclairs=choice.c // eclairs corresponds to button c
eclairs.value=1 // eclairs costs 1 rs
gum=choice.d // gum corresponds to button d
gum.value=2 // gum costs 1 rs
a.qty>=10 and a.qty<=40
b.qty>=11 and b.qty<=40
c.qty>=12 and c.qty<=40
d.qty>=13 and d.qty<=40
nullb.qty=0
//ip=nullb //input button selection is never nullb(which is imaginary button)
ipp.value!=0 // input of coins is never = 0rs
/* all m:machine|all o:opc2
|all opp: op| all i:ip|all ii:ipp| all c:m.cust
|c -> i in m.customeripb and c->ii in m.customeripc and o->c in m.customerop and opp->c in m.customerop
*/
//button=!=none
}
sig customer //user of machine
{
}
abstract sig Coin { //each coin has a valueof rs
value: Int
}
sig Nullrs extends Coin {} { value = 0 } // void rs
sig Oners extends Coin {} { value = 1 } // one rs
sig Twors extends Coin {} { value = 2 } // twors
sig Fivers extends Coin {}{ value = 5 } // five rs
sig Tenrs extends Coin {} { value = 10 } // ten rs
sig Threers extends Coin {} { value = 3 } // this is only used in o/p to specify 3rs will come out
sig Fourrs extends Coin {} { value = 4 }// this is only used in o/p to specify 4rs will come out
sig Sixrs extends Coin {} { value = 6 }// this is only used in o/p to specify 6rs will come out
sig Sevenrs extends Coin {}{ value = 7 }// this is only used in o/p to specify 7rs will come out
sig Eightrs extends Coin {} { value = 8 } // this is only used in o/p to specify 8rs will come out
sig Niners extends Coin {} { value = 9} //// this is only used in o/p to specify 9rs will come out
pred show{} // show
pred chocolate [before,after:machine ] // machine has two states one before o/p and one after
{
before.cadbury=after.cadbury
before.kitkat=after.kitkat
before.eclairs=after.eclairs
before.gum=after.gum
//all chocolates will not change and are fixed
before.ipp.value=after.ipp.value
// input value of rs remains same i.e i/p is inside machine once inputed so it cant change
before.opc2.value=0 // before state o/p value of balance coins =0
before.op=before.null // beforestate o/p = no chocolate
before.ip!=before.nullb // input button pressed never equals nullb
after.ip!=after.nullb // input button pressed never equals nullb
//before.ip=after.ip // input button pressed remains same
after.op=after.kitkat or after.op=after.eclairs
before.null=after.null // imaginary null chocolate remains in same state
before.opc2!=none and after.opc2 !=none
// balance of coins is never empty in case of empty I have defined nullrs
(after.op.value=before.ipp.value=>after.opc2.value=0)
//
(after.op=after.null=>after.opc2.value=before.ipp.value)
(before.ipp.value > after.op.value=>after.opc2.value=before.ipp.value-after.op.value)
//(before.ipp.value=after.op.value=>after.opc2.value=0)
//opc2.value!=ipp.value
before.ip=before.a or before.ip=before.b or before.ip=before.c or before.ip=before.d
(after.op=after.cadbury ) => ( ( after.ip=after.a and after.a.qty=minus[before.a.qty,1])) else
(after.op=after.kitkat ) => ( (after.ip=after.b and after.b.qty=minus[before.b.qty, 1])) else
(after.op=after.eclairs ) =>( (after.ip=after.c and after.c.qty=minus[before.c.qty,1])) else
(after.op=after.gum ) =>((after.ip=after.d and after.d.qty=minus[before.d.qty,1])) else
(after.ip=before.ip and after.ip.qty=minus[before.ip.qty,0] )
after.op!=before.null => after.op.choice=before.ip
(after.op=before.gum=>before.ipp.value>=Twors.value)
after.op=before.cadbury=>before.ipp.value>=Tenrs.value
after.op=before.eclairs=>before.ipp.value>=Oners.value
after.op=before.kitkat=>before.ipp.value>=Fivers.value
(before.ipp=Oners or before.ipp=Twors or before.ipp=Fivers or before.ipp=Tenrs or before.ipp=Nullrs) and
before.ipp!=Threers and before.ipp!=Fourrs and before.ipp !=Sixrs and before.ipp!=Sevenrs and before.ipp!=Eightrs and before.ipp!=Niners
(before.ip=before.b and before.ipp.value < 5) => (after.op!=before.kitkat or after.op!=before.eclairs or after.op!=before.cadbury or after.op!=before.gum)and after.op=before.null
(before.ip=before.d and before.ipp.value < 2) => (after.op!=before.kitkat or after.op!=before.eclairs or after.op!=before.cadbury or after.op!=before.gum)and after.op=before.null
(before.ip=before.a and before.ipp.value < 10 )=> (after.op!=before.kitkat or after.op!=before.eclairs or after.op!=before.cadbury or after.op!=before.gum) and after.op=before.null
(before.ip=before.c and before.ipp.value >= 1) => (after.op!=before.kitkat or after.op!=before.null or after.op!=before.cadbury or after.op!=before.gum) and after.op=before.eclairs
(before.ip=before.c and before.ipp.value = 0) => (after.op!=before.kitkat or after.op!=before.null or after.op!=before.cadbury or after.op!=before.gum) and after.op=before.null
(before.ip=before.a and before.ipp.value =10) => (after.op!=before.kitkat or after.op!=before.null or after.op!=before.eclairs or after.op!=before.gum) and after.op= before.cadbury
(before.ip=before.d and before.ipp.value >= 2) => (after.op!=before.kitkat or after.op!=before.null or after.op!=before.cadbury or after.op!=before.eclairs) and after.op=before.gum
(before.ip=before.b and before.ipp.value >= 5) => (after.op!=before.eclairs or after.op!=before.null or after.op!=before.cadbury or after.op!=before.gum) and after.op=before.kitkat
}
run chocolate for exactly 2 machine, 8 button, 5 choco,9 Int,5 Coin,1 customer
In general, it would make sense to be more specific than "it doesn't work".
I'm assuming that what you mean by "it doesn't work" is that in the after machine you expect the quantity of the selected chocolate to be decreased by 1, but instead, it stays the same. The reason for that is your (if-then-else) or (if-then-else) or ... expression, which is logically flawed. What you probably wanted to express is to enforce at least one then branch (because you know that exactly one if condition will be satisfied), but that is not necessary to satisfy this whole disjunction.
More concretely, in
((after.op=after.cadbury)
=> (... and after.a.qty=minus[before.a.qty,1] and ...)
else (... and after.a.qty=before.a.qty and ...)
)
or
((after.op=after.kitkat)
=> (... and after.b.qty=minus[before.b.qty,1] and ...)
else (... and after.b.qty=before.b.qty and ...)
)
even if after.op is equal to after.cadbury, that does not enforce the then branch of that clause to be true, because to satisfy this whole expression, it is enough to satisfy the else branch of the next clause, which says that all quantities should stay the same.
What you want is some soft of if-then-elsif-...-else construct, e.g.,
(after.op = after.cadbury) => {
...
} else (after.op = after.kitkat) => {
...
} else {
...
}
If you do that, your machine will still not work, that is, your model will become unsatisfiable: your constraints enforce that both after and before machines share the same buttons1 and quantities are associated with buttons (the qty field is in the button sig), which means that quantities must be the same in both after and before machines. I don't really see any good reason to put qty in sig button.
[1]: by having before.cadbury=after.cadbury and ... in your chocolate predicate, and cadbury=choice.a and ... in your appended facts for sig machine