Related
I have already generated the corresponding CFG of my source code. Then, I want to modify the CFG (merge some nodes). In then end, I need to convert the modified CFG back into a corresponding source code. How could I do that? I am using LLVM at this point.
This is a deceptively difficult problem. Usually the CFG is simplified
so that the original source code cannot be reconstructed. For example,
while and for-loops are replaced with tests and conditional jump
instructions. I'm sure that is the case for LLVM:s intermediate form
so you are out of luck there.
However, if the CFG has not been simplified it is possible to recreate
the program's abstract syntax tree (AST). To do that you need to have
the basic blocks of the CFG in program order. This is not difficult
since that is the natural order you get when creating the CFG. You
also need to precompute every basic block's immediate dominator. You
can find an algorithm for computing that in the article A Simple,
Fast Dominance
Algorithm. Then the
algorithm proceeds as follows:
For every block except for the first one:
Check whether this block is the direct child of its immediate
dominator. I.e, whether this block is the first block in a
while, for, or if-else clause.
If yes, add the block to its immediate dominator's children.
If no, mark this block as its immediate dominator's follower.
Use the collected data to build an AST as follows:
Traverse the follower data from the first block in the CFG until
the last block which has no follower.
For every block that is a for, if, or while, recurse from step 3
but start with the first and second child (in case of else) of
the block.
Here is some Python code that implements the algorithm:
from ast import *
class BasicBlock:
def __init__(self, insns):
self.insns = insns
def type(self):
return type(self.insns[-1]) if self.insns else None
def build_tree(bb, foll, children):
nodes = []
while bb:
if not bb.insns:
break
last_insn = bb.insns[-1]
childs = children[bb]
tp = bb.type()
if tp in (For, If, While):
last_insn.body = \
build_tree(childs[0], foll, children)
if len(childs) == 2:
last_insn.orelse = \
build_tree(childs[1], foll, children)
nodes.extend(bb.insns)
bb = foll.get(bb)
return nodes
def is_dom_child(bb, dom_bb, succ):
childs = succ[dom_bb]
if bb in childs:
tp = dom_bb.type()
if tp in (If, For, While) and childs[0] == bb:
return True
if (tp == If and bb == childs[1] and
not reachable(succ, childs[0], childs[1], {dom_bb})):
return True
return False
def bbs_to_ast(bbs, succ, idoms):
foll = {}
children = defaultdict(list)
for bb in bbs[1:]:
dom_bb = idoms[bb]
if is_dom_child(bb, dom_bb, succ):
children[dom_bb].append(bb)
else:
foll[dom_bb] = bb
nodes = build_tree(bbs[0], foll, children)
return Module(nodes, [])
def print_bbs(bbs, succ, idoms):
mod = bbs_to_ast(bbs, succ, idoms)
return unparse(mod)
I am trying to find total no of nodes in a Shared-BDD using CUDD.
I have already written C Code using BuDDy-2.4 and it is running fine But when i am using CUDD instead of BuDDy, My program is showing error.
My BuDDY C File is:
//BuDDY_C Code for Node Count:
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
#define X2 (a&b&d&!c)|(!c&!c&d)^(g) //Define Function-2 here
#include<bdd.h>
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
bdd z[2],a,b,c,d,e,f,g,h;
int i,INPUT=8,node_count,order[8]={2,5,1,6,0,4,3,7};
printf("\nGiven Variable Order:\t ");
for(i=0;i<INPUT;i++)
printf("%d \t",order[i]);
bdd_init(1000,100);
bdd_setvarnum(INPUT);
a = bdd_ithvar(order[0]); //Assign Variable order stored in order[0] to a
b = bdd_ithvar(order[1]); //Assign Variable order stored in order[1] to b
c = bdd_ithvar(order[2]); //Assign Variable order stored in order[2] to c
d = bdd_ithvar(order[3]); //Assign Variable order stored in order[3] to d
e = bdd_ithvar(order[4]); //Assign Variable order stored in order[4] to e
f = bdd_ithvar(order[5]); //Assign Variable order stored in order[5] to f
g = bdd_ithvar(order[6]); //Assign Variable order stored in order[6] to g
h = bdd_ithvar(order[7]); //Assign Variable order stored in order[7] to h
z[0]=X1;
z[1]=X2;
node_count=bdd_anodecount(z,2);
bdd_done();
printf("\n Total no of nodes are %d\n",node_count);
return 0;
}
My CUDD C Program is:
//CUDD_C Code for Node Count
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
#define X2 (a&b&d&!c)|(!c&!c&d)^(g) //Define Function-2 here
#include <stdio.h>
#include <stdlib.h>
#include "cudd.h"
int main(void) {
DdNode *z[2],*a,*b,*c,*d,*e,*f,*g,*h;
int i,INPUT=8,node_count,order[8]={2,5,1,6,0,4,3,7};
printf("\nGiven Variable Order:\t ");
for(i=0;i<INPUT;i++)
printf("%d \t",order[i]);
DdManager * mgr = Cudd_Init(INPUT,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0);
a = Cudd_bddIthVar(mgr, order[0]); //Assign Variable order stored in order[0] to a
b = Cudd_bddIthVar(mgr, order[1]); //Assign Variable order stored in order[0] to b
c = Cudd_bddIthVar(mgr, order[2]); //Assign Variable order stored in order[0] to c
d = Cudd_bddIthVar(mgr, order[3]); //Assign Variable order stored in order[0] to d
e = Cudd_bddIthVar(mgr, order[4]); //Assign Variable order stored in order[0] to e
f = Cudd_bddIthVar(mgr, order[5]); //Assign Variable order stored in order[0] to f
g = Cudd_bddIthVar(mgr, order[6]); //Assign Variable order stored in order[0] to g
h = Cudd_bddIthVar(mgr, order[7]); //Assign Variable order stored in order[0] to h
z[0]=X1;
z[1]=X2;
Cudd_Ref(z[0]);
Cudd_Ref(z[1]);
/*-----Calculate no of nodes and number of shared nodes*/
node_count= Cudd_SharingSize( z, 2);
printf("\n Total no of nodes are %d\n",node_count);
int err = Cudd_CheckZeroRef(mgr);
Cudd_Quit(mgr);
return err;
}
But this CUDD C program is showing Error
balal#balal-HP-H710:~/Desktop/cudd-3.0.0$ g++ -o test test2_cudd.c -lbdd
test2_cudd.c: In function ‘int main()’:
test2_cudd.c:2:14: error: invalid operands of types ‘DdNode*’ and ‘DdNode*’ to binary ‘operator&’
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
~^~
test2_cudd.c:30:7: note: in expansion of macro ‘X1’
z[0]=X1;
^~
test2_cudd.c:2:25: error: invalid operands of types ‘bool’ and ‘DdNode*’ to binary ‘operator&’
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
~~^~
test2_cudd.c:30:7: note: in expansion of macro ‘X1’
z[0]=X1;
^~
test2_cudd.c:2:33: error: invalid operands of types ‘DdNode*’ and ‘bool’ to binary ‘operator&’
#define X1 (a&b&c&d)|(!c&d&f)|(g&!g) //Define Function-1 here
~^~~
test2_cudd.c:30:7: note: in expansion of macro ‘X1’
z[0]=X1;
^~
test2_cudd.c:3:14: error: invalid operands of types ‘DdNode*’ and ‘DdNode*’ to binary ‘operator&’
#define X2 (a&b&d&!c)|(!c&!c&d)^(g) //Define Function-2 here
~^~
test2_cudd.c:31:7: note: in expansion of macro ‘X2’
z[1]=X2;
^~
test2_cudd.c:3:29: error: invalid operands of types ‘int’ and ‘DdNode*’ to binary ‘operator&’
#define X2 (a&b&d&!c)|(!c&!c&d)^(g) //Define Function-2 here
~~~~~^~
test2_cudd.c:31:7: note: in expansion of macro ‘X2’
z[1]=X2;
^~
balal#balal-HP-H710:~/Desktop/cudd-3.0.0$
You are trying to use the "&" operator on BDD nodes while writing your program in C. Since C does not support operator overloading, this won't work because the "&" operator could at most mean to take the bitwise AND of the addresses, which is not what you want.
In order to compute the AND of two BDDs, you have to use the Cudd_bddAnd function. See, for instance, here for an example. Note that your macros will become a lot longer in this way and need to include local variables apart from scopes.
The alternative is to use the C++ interface to CUDD, where BDDs can be encapsulated into objects that support operator overloading.
Note that
z[0]=X1;
z[1]=X2;
Cudd_Ref(z[0]);
Cudd_Ref(z[1]);
can also potentially cause trouble. In CUDD, nodes have to be referenced with Cudd_Ref(...) before any other CUDD function is called that can create new nodes. Since your X2 macro includes operations over BDDs, this can happen. So it's best practice to Cudd_Ref(...) BDDs immediately. The following looks better:
z[0]=X1;
Cudd_Ref(z[0]);
z[1]=X2;
Cudd_Ref(z[1]);
Note that your Buddy code is also wrong for the same reason. However, since the BDD type there is defined as "typedef int BDD;" the compiler used bitwise AND and OR on the BDD node numbers instead, which is why it compiled to code that produces wrong results.
Another possibility is to use the Cython interface to CUDD that is included in the Python package dd. Installation of dd with the module dd.cudd is described here and could be summarized as
pip download dd --no-deps
tar -xzf dd-*.tar.gz
cd dd-*/
python setup.py install --fetch --cudd
This will download and build CUDD, and build and install the Cython bindings of dd to CUDD. dd has Cython bindings also to BuDDy, and those could be built similarly, with the user downloading and building BuDDy, and passing --buddy to the script setup.py.
The example code could be translated to the following Python code.
from dd import cudd as _bdd
bdd = _bdd.BDD()
bdd.declare('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')
# /\ is conjunction in TLA+, \/ disjunction, ~ negation
X1 = bdd.add_expr('(a /\ b /\ c /\ d) \/ (~ c /\ d /\ f) \/ (g /\ ~ g)')
# note that g /\ ~ g is FALSE
X2 = bdd.add_expr('(a /\ b /\ d /\ ~ c) \/ ((~ c /\ ~ c /\ d) ^ g)')
# note that ~ c /\ ~ c is ~ c
# using the operators &, |, ! for conjunction, disjunction, and negation
X1_ = bdd.add_expr('(a & b & c & d) \/ (!c & d & f) \/ (g & !g)')
X2_ = bdd.add_expr('(a & b & d & !c) \/ ((!c & !c & d) ^ g)')
assert X1 == X1_, (X1, X1_)
assert X2 == X2_, (X2, X2_)
def descendants(roots):
"""Return nodes reachable from `roots`.
Nodes in `roots` are included.
"""
if not roots:
return set()
visited = set()
for u in roots:
_descendants(u, visited)
assert set(roots).issubset(visited), (roots, visited)
return visited
def _descendants(u, visited):
v, w = u.low, u.high
# terminal node or visited ?
if u.low is None or u in visited:
return
_descendants(v, visited)
_descendants(w, visited)
visited.add(u)
r = descendants([X1, X2])
print(len(r))
# plot diagrams of the results using GraphViz
bdd.dump('X1.pdf', [X1])
bdd.dump('X2.pdf', [X2])
The function descendants computes the set of nodes reachable from the given nodes (the nodes referenced by X1 and X2), including the given nodes. The answer for the variable order in my run is 16 nodes. The diagrams for the BDDs of the Boolean functions X1 and X2 are the following.
BDD of Boolean function X1
BDD of Boolean function X2
I'm trying to code the fast Non Dominated Sorting algorithm (NDS) of Deb used in NSGA2 in immutable way using Scala.
But the problem seems more difficult than i think, so i simplify here the problem to make a MWE.
Imagine a population of Seq[A], and each A element is decoratedA with a list which contains pointers to other elements of the population Seq[A].
A function evalA(a:decoratedA) take the list of linkedA it contains, and decrement value of each.
Next i take a subset list decoratedAPopulation of population A, and call evalA on each. I have a problem, because between each iteration on element on this subset list decoratedAPopulation, i need to update my population of A with the new decoratedA and the new updated linkedA it contain ...
More problematic, each element of population need an update of 'linkedA' to replace the linked element if it change ...
Hum as you can see, it seem complicated to maintain all linked list synchronized in this way. I propose another solution bottom, which probably need recursion to return after each EvalA a new Population with element replaced.
How can i do that correctly in an immutable way ?
It's easy to code in a mutable way, but i don't find a good way to do this in an immutable way, do you have a path or an idea to do that ?
object test extends App{
case class A(value:Int) {def decrement()= new A(value - 1)}
case class decoratedA(oneAdecorated:A, listOfLinkedA:Seq[A])
// We start algorithm loop with A element with value = 0
val population = Seq(new A(0), new A(0), new A(8), new A(1))
val decoratedApopulation = Seq(new decoratedA(population(1),Seq(population(2),population(3))),
new decoratedA(population(2),Seq(population(1),population(3))))
def evalA(a:decoratedA) = {
val newListOfLinked = a.listOfLinkedA.map{e => e.decrement()
new decoratedA(a.oneAdecorated,newListOfLinked)}
}
def run()= {
//decoratedApopulation.map{
// ?
//}
}
}
Update 1:
About the input / output of the initial algorithm.
The first part of Deb algorithm (Step 1 to Step 3) analyse a list of Individual, and compute for each A : (a) domination count, the number of A which dominate me (the value attribute of A) (b) a list of A i dominate (listOfLinkedA).
So it return a Population of decoratedA totally initialized, and for the entry of Step 4 (my problem) i take the first non dominated front, cf. the subset of elements of decoratedA with A value = 0.
My problem start here, with a list of decoratedA with A value = 0; and i search the next front into this list by computing each listOfLinkedA of each of this A
At each iteration between step 4 to step 6, i need to compute a new B subset list of decoratedA with A value = 0. For each , i decrementing first the domination count attribute of each element into listOfLinkedA, then i filter to get the element equal to 0. A the end of step 6, B is saved to a list List[Seq[DecoratedA]], then i restart to step 4 with B, and compute a new C, etc.
Something like that in my code, i call explore() for each element of B, with Q equal at the end to new subset of decoratedA with value (fitness here) = 0 :
case class PopulationElement(popElement:Seq[Double]){
implicit def poptodouble():Seq[Double] = {
popElement
}
}
class SolutionElement(values: PopulationElement, fitness:Double, dominates: Seq[SolutionElement]) {
def decrement()= if (fitness == 0) this else new SolutionElement(values,fitness - 1, dominates)
def explore(Q:Seq[SolutionElement]):(SolutionElement, Seq[SolutionElement])={
// return all dominates elements with fitness - 1
val newSolutionSet = dominates.map{_.decrement()}
val filteredSolution:Seq[SolutionElement] = newSolutionSet.filter{s => s.fitness == 0.0}.diff{Q}
filteredSolution
}
}
A the end of algorithm, i have a final list of seq of decoratedA List[Seq[DecoratedA]] which contain all my fronts computed.
Update 2
A sample of value extracted from this example.
I take only the pareto front (red) and the {f,h,l} next front with dominated count = 1.
case class p(x: Int, y: Int)
val a = A(p(3.5, 1.0),0)
val b = A(p(3.0, 1.5),0)
val c = A(p(2.0, 2.0),0)
val d = A(p(1.0, 3.0),0)
val e = A(p(0.5, 4.0),0)
val f = A(p(0.5, 4.5),1)
val h = A(p(1.5, 3.5),1)
val l = A(p(4.5, 1.0),1)
case class A(XY:p, value:Int) {def decrement()= new A(XY, value - 1)}
case class ARoot(node:A, children:Seq[A])
val population = Seq(
ARoot(a,Seq(f,h,l),
ARoot(b,Seq(f,h,l)),
ARoot(c,Seq(f,h,l)),
ARoot(d,Seq(f,h,l)),
ARoot(e,Seq(f,h,l)),
ARoot(f,Nil),
ARoot(h,Nil),
ARoot(l,Nil))
Algorithm return List(List(a,b,c,d,e), List(f,h,l))
Update 3
After 2 hour, and some pattern matching problems (Ahum...) i'm comming back with complete example which compute automaticaly the dominated counter, and the children of each ARoot.
But i have the same problem, my children list computation is not totally correct, because each element A is possibly a shared member of another ARoot children list, so i need to think about your answer to modify it :/ At this time i only compute children list of Seq[p], and i need list of seq[A]
case class p(x: Double, y: Double){
def toSeq():Seq[Double] = Seq(x,y)
}
case class A(XY:p, dominatedCounter:Int) {def decrement()= new A(XY, dominatedCounter - 1)}
case class ARoot(node:A, children:Seq[A])
case class ARootRaw(node:A, children:Seq[p])
object test_stackoverflow extends App {
val a = new p(3.5, 1.0)
val b = new p(3.0, 1.5)
val c = new p(2.0, 2.0)
val d = new p(1.0, 3.0)
val e = new p(0.5, 4.0)
val f = new p(0.5, 4.5)
val g = new p(1.5, 4.5)
val h = new p(1.5, 3.5)
val i = new p(2.0, 3.5)
val j = new p(2.5, 3.0)
val k = new p(3.5, 2.0)
val l = new p(4.5, 1.0)
val m = new p(4.5, 2.5)
val n = new p(4.0, 4.0)
val o = new p(3.0, 4.0)
val p = new p(5.0, 4.5)
def isStriclyDominated(p1: p, p2: p): Boolean = {
(p1.toSeq zip p2.toSeq).exists { case (g1, g2) => g1 < g2 }
}
def sortedByRank(population: Seq[p]) = {
def paretoRanking(values: Set[p]) = {
//comment from #dk14: I suppose order of values isn't matter here, otherwise use SortedSet
values.map { v1 =>
val t = (values - v1).filter(isStriclyDominated(v1, _)).toSeq
val a = new A(v1, values.size - t.size - 1)
val root = new ARootRaw(a, t)
println("Root value ", root)
root
}
}
val listOfARootRaw = paretoRanking(population.toSet)
//From #dk14: Here is convertion from Seq[p] to Seq[A]
val dominations: Map[p, Int] = listOfARootRaw.map(a => a.node.XY -> a.node.dominatedCounter) //From #dk14: It's a map with dominatedCounter for each point
val listOfARoot = listOfARootRaw.map(raw => ARoot(raw.node, raw.children.map(p => A(p, dominations.getOrElse(p, 0)))))
listOfARoot.groupBy(_.node.dominatedCounter)
}
//Get the first front, a subset of ARoot, and start the step 4
println(sortedByRank(Seq(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)).head)
}
Talking about your problem with distinguishing fronts (after update 2):
val (left,right) = population.partition(_.node.value == 0)
List(left, right.map(_.copy(node = node.copy(value = node.value - 1))))
No need for mutating anything here. copy will copy everything but fields you specified with new values. Talking about the code, the new copy will be linked to the same list of children, but new value = value - 1.
P.S. I have a feeling you may actually want to do something like this:
case class A(id: String, level: Int)
val a = A("a", 1)
val b = A("b", 2)
val c = A("c", 2)
val d = A("d", 3)
clusterize(List(a,b,c,d)) === List(List(a), List(b,c), List(d))
It's simple to implement:
def clusterize(list: List[A]) =
list.groupBy(_.level).toList.sortBy(_._1).map(_._2)
Test:
scala> clusterize(List(A("a", 1), A("b", 2), A("c", 2), A("d", 3)))
res2: List[List[A]] = List(List(A(a,1)), List(A(b,2), A(c,2)), List(A(d,3)))
P.S.2. Please consider better naming conventions, like here.
Talking about "mutating" elements in some complex structure:
The idea of "immutable mutating" some shared (between parts of a structure) value is to separate your "mutation" from the structure. Or simply saying, divide and conquerror:
calculate changes in advance
apply them
The code:
case class A(v: Int)
case class AA(a: A, seq: Seq[A]) //decoratedA
def update(input: Seq[AA]) = {
//shows how to decrement each value wherever it is:
val stats = input.map(_.a).groupBy(identity).mapValues(_.size) //domination count for each A
def upd(a: A) = A(a.v - stats.getOrElse(a, 0)) //apply decrement
input.map(aa => aa.copy(aa = aa.seq.map(upd))) //traverse and "update" original structure
}
So, I've introduced new Map[A, Int] structure, that shows how to modify the original one. This approach is based on highly simplified version of Applicative Functor concept. In general case, it should be Map[A, A => A] or even Map[K, A => B] or even Map[K, Zipper[A] => B] as applicative functor (input <*> map). *Zipper (see 1, 2) actually could give you information about current element's context.
Notes:
I assumed that As with same value are same; that's default behaviour for case classess, otherwise you need to provide some additional id's (or redefine hashCode/equals).
If you need more levels - like AA(AA(AA(...)))) - just make stats and upd recursive, if dеcrement's weight depends on nesting level - just add nesting level as parameter to your recursive function.
If decrement depends on parent node (like decrement only A(3)'s, which belongs to A(3)) - add parent node(s) as part of stats's key and analise it during upd.
If there is some dependency between stats calculation (how much to decrement) of let's say input(1) from input(0) - you should use foldLeft with partial stats as accumulator: val stats = input.foldLeft(Map[A, Int]())((partialStats, elem) => partialStats ++ analize(partialStats, elem))
Btw, it takes O(N) here (linear memory and cpu usage)
Example:
scala> val population = Seq(A(3), A(6), A(8), A(3))
population: Seq[A] = List(A(3), A(6), A(8), A(3))
scala> val input = Seq(AA(population(1),Seq(population(2),population(3))), AA(population(2),Seq(population(1),population(3))))
input: Seq[AA] = List(AA(A(6),List(A(8), A(3))), AA(A(8),List(A(6), A(3))))
scala> update(input)
res34: Seq[AA] = List(AA(A(5),List(A(7), A(3))), AA(A(7),List(A(5), A(3))))
I am reading something like this from my configuration file :
metric1.critical = "<2000 || >20000"
metric1.okay = "=1"
metric1.warning = "<=3000"
metric2.okay = ">0.9 && < 1.1 "
metric3.warning ="( >0.9 && <1.5) || (<500 &&>200)"
and I have a
metric1.value = //have some value
My aim is to basically evaluate
if(metric1.value<2000 || metric1.value > 20000)
metric1.setAlert("critical");
else if(metric1.value=1)
metric.setAlert("okay");
//and so on
I am not really good with regex so I am going to try not to use it. I am coding in Scala and wanted to know if any existing library can help with this. Maybe i need to put placeholders to fill in the blanks and then evaluate the expression? But how do I evaluate the expression most efficiently and with less overhead?
EDIT:
In java how we have expression evaluator Libraries i was hoping i could find something similar for my code . Maybe I can add placeholders in the config file like "?" these to substitute my metric1.value (read variables) and then use an evaluator?
OR
Can someone suggest a good regex for this?
Thanks in advance!
This sounds like you want to define your own syntax using a parser combinator library.
There is a parser combinator built into the scala class library. Since the scala library has been modularized, it is now a separate project that lives at https://github.com/scala/scala-parser-combinators.
Update: everybody looking for a parser combinator library that is conceptually similar to scala-parser-combinators should take a look at fastparse. It is very fast, and does not use macros. So it can serve as a drop-in replacement for scala-parser-combinators.
There are some examples on how to use it in Programming in Scala, Chapter 33, "Combinator Parsing".
Here is a little grammar, ast and evaluator to get you started. This is missing a lot of things such as whitespace handling, operator priority etc. You should also not use strings for encoding the different comparison operators. But I think with this and the chapter from Programming in Scala you should be able to come up with something that suits your needs.
import scala.util.parsing.combinator.{JavaTokenParsers, PackratParsers}
sealed abstract class AST
sealed abstract class BooleanExpression extends AST
case class BooleanOperation(op: String, lhs: BooleanExpression, rhs:BooleanExpression) extends BooleanExpression
case class Comparison(op:String, rhs:Constant) extends BooleanExpression
case class Constant(value: Double) extends AST
object ConditionParser extends JavaTokenParsers with PackratParsers {
val booleanOperator : PackratParser[String] = literal("||") | literal("&&")
val comparisonOperator : PackratParser[String] = literal("<=") | literal(">=") | literal("==") | literal("!=") | literal("<") | literal(">")
val constant : PackratParser[Constant] = floatingPointNumber.^^ { x => Constant(x.toDouble) }
val comparison : PackratParser[Comparison] = (comparisonOperator ~ constant) ^^ { case op ~ rhs => Comparison(op, rhs) }
lazy val p1 : PackratParser[BooleanExpression] = booleanOperation | comparison
val booleanOperation = (p1 ~ booleanOperator ~ p1) ^^ { case lhs ~ op ~ rhs => BooleanOperation(op, lhs, rhs) }
}
object Evaluator {
def evaluate(expression:BooleanExpression, value:Double) : Boolean = expression match {
case Comparison("<=", Constant(c)) => value <= c
case Comparison(">=", Constant(c)) => value >= c
case Comparison("==", Constant(c)) => value == c
case Comparison("!=", Constant(c)) => value != c
case Comparison("<", Constant(c)) => value < c
case Comparison(">", Constant(c)) => value > c
case BooleanOperation("||", a, b) => evaluate(a, value) || evaluate(b, value)
case BooleanOperation("&&", a, b) => evaluate(a, value) && evaluate(b, value)
}
}
object Test extends App {
def parse(text:String) : BooleanExpression = ConditionParser.parseAll(ConditionParser.p1, text).get
val texts = Seq(
"<2000",
"<2000||>20000",
"==1",
"<=3000",
">0.9&&<1.1")
val xs = Seq(0.0, 1.0, 100000.0)
for {
text <- texts
expression = parse(text)
x <- xs
result = Evaluator.evaluate(expression, x)
} {
println(s"$text $expression $x $result")
}
}
Scala has built in Interpreter library which you can use. The library provides functionalities similar to eval() in many other languages. You can pass Scala code snippet as String to the .interpret method and it will evaluate it.
import scala.tools.nsc.{ Interpreter, Settings }
val settings = new Settings
settings.usejavacp.value = true
val in = new Interpreter(settings)
val lowerCritical = "<2000" // set the value from config
val value = 200
in.interpret(s"$value $lowerCritical") //> res0: Boolean = true
val value1 = 20000 //> value1 : Int = 20000
in.interpret(s"$value1 $lowerCritical") //> res1: Boolean = false
You want to use an actual parser for this.
Most answers are suggesting Scala's parser combinators, and that's a perfectly valid choice, if a bit out-of-date.
I'd suggest Parboiled2, an other parser combinator implementation that has the distinct advantage of being written as Scala macros - without getting too technical, it means your parser is generated at compile time rather than runtime, which can yield significant performance improvements. Some benchmarks have Parboiled2 up to 200 times as fast as Scala's parser combinator.
And since parser combinators are now in a separate dependency (as of 2.11, I believe), there really is no good reason to prefer them to Parboiled2.
I recently faced the same problem and I ended up writing my own expression evaluation library scalexpr. It is a simple library but it can validate / evaluate expressions that are similar to the ones in the question. You can do things like:
val ctx = Map("id" -> 10L, "name" -> "sensor1")
val parser = ExpressionParser()
val expr = parser.parseBooleanExpression(""" id == 10L || name == "sensor1" """).get
println(expr3.resolve(ctx3)) // prints true
If you don't want to use the library, I recommend the fastparse parser... It is much faster than parser combinators, a little bit slower than parboiled, but much easier to use than both.
I ve got the following class and I want to write some Spec test cases, but I am really new to it and I don't know how to start. My class do loke like this:
class Board{
val array = Array.fill(7)(Array.fill(6)(None:Option[Coin]))
def move(x:Int, coin:Coin) {
val y = array(x).indexOf(None)
require(y >= 0)
array(x)(y) = Some(coin)
}
def apply(x: Int, y: Int):Option[Coin] =
if (0 <= x && x < 7 && 0 <= y && y < 6) array(x)(y)
else None
def winner: Option[Coin] = winner(Cross).orElse(winner(Naught))
private def winner(coin:Coin):Option[Coin] = {
val rows = (0 until 6).map(y => (0 until 7).map( x => apply(x,y)))
val cols = (0 until 7).map(x => (0 until 6).map( y => apply(x,y)))
val dia1 = (0 until 4).map(x => (0 until 6).map( y => apply(x+y,y)))
val dia2 = (3 until 7).map(x => (0 until 6).map( y => apply(x-y,y)))
val slice = List.fill(4)(Some(coin))
if((rows ++ cols ++ dia1 ++ dia2).exists(_.containsSlice(slice)))
Some(coin)
else None
}
override def toString = {
val string = new StringBuilder
for(y <- 5 to 0 by -1; x <- 0 to 6){
string.append(apply(x, y).getOrElse("_"))
if (x == 6) string.append ("\n")
else string.append("|")
}
string.append("0 1 2 3 4 5 6\n").toString
}
}
Thank you!
I can only second Daniel's suggestion, because you'll end up with a more practical API by using TDD.
I also think that your application could be nicely tested with a mix of specs2 and ScalaCheck. Here the draft of a Specification to get you started:
import org.specs2._
import org.scalacheck.{Arbitrary, Gen}
class TestSpec extends Specification with ScalaCheck { def is =
"moving a coin in a column moves the coin to the nearest empty slot" ! e1^
"a coin wins if" ^
"a row contains 4 consecutive coins" ! e2^
"a column contains 4 consecutive coins" ! e3^
"a diagonal contains 4 consecutive coins" ! e4^
end
def e1 = check { (b: Board, x: Int, c: Coin) =>
try { b.move(x, c) } catch { case e => () }
// either there was a coin before somewhere in that column
// or there is now after the move
(0 until 6).exists(y => b(x, y).isDefined)
}
def e2 = pending
def e3 = pending
def e4 = pending
/**
* Random data for Coins, x position and Board
*/
implicit def arbitraryCoin: Arbitrary[Coin] = Arbitrary { Gen.oneOf(Cross, Naught) }
implicit def arbitraryXPosition: Arbitrary[Int] = Arbitrary { Gen.choose(0, 6) }
implicit def arbitraryBoardMove: Arbitrary[(Int, Coin)] = Arbitrary {
for {
coin <- arbitraryCoin.arbitrary
x <- arbitraryXPosition.arbitrary
} yield (x, coin)
}
implicit def arbitraryBoard: Arbitrary[Board] = Arbitrary {
for {
moves <- Gen.listOf1(arbitraryBoardMove.arbitrary)
} yield {
val board = new Board
moves.foreach { case (x, coin) =>
try { board.move(x, coin) } catch { case e => () }}
board
}
}
}
object Cross extends Coin {
override def toString = "x"
}
object Naught extends Coin {
override def toString = "o"
}
sealed trait Coin
The e1 property I've implemented is not the real thing because it doesn't really check that we moved the coin to the nearest empty slot, which is what your code and your API suggests. You will also want to change the generated data so that the Boards are generated with an alternation of x and o. That should be a great way to learn how to use ScalaCheck!
I suggest you throw all that code out -- well, save it somewhere, but start from zero using TDD.
The Specs2 site has plenty examples of how to write tests, but use TDD -- test driven design -- to do it. Adding tests after the fact is suboptimal, to say the least.
So, think of the most simple case you want to handle of the most simple feature, write a test for that, see it fail, write the code to fix it. Refactor if necessary, and repeat for the next most simple case.
If you want help with how to do TDD in general, I heartily endorse the videos about TDD available on Clean Coders. At the very least, watch the second part where Bob Martin writes a whole class TDD-style, from design to end.
If you know how to do testing in general but are confused about Scala or Specs, please be much more specific about what your questions are.