使用规则引擎Drools计算圆周率PI
实际上是使用规则引擎能够更新工作内存区重新匹配规则实现迭代功能。 使用了策略模式实现。
《规则引擎与RETE算法介绍》 PPT :
1. CalcPI.java
package sample; import java.util.ArrayList; import java.util.List; import org.drools.KnowledgeBase; import org.drools.builder.ResourceType; import org.drools.logger.KnowledgeRuntimeLogger; import org.drools.logger.KnowledgeRuntimeLoggerFactory; import org.drools.runtime.StatefulKnowledgeSession; import sample.helper.KnowledgeBaseHelper; import sample.model.PI; import sample.model.RuleResource; public class CalcPI { public static void main(String[] args) { try { // load up the knowledge base KnowledgeBase kbase = readKnowledgeBase(); StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test"); // go ! PI pi = new PI(); pi.setIterStrategy(PI.IterStrategySetting.ballardMethod.getStrategy()); ksession.insert(pi); ksession.fireAllRules(); System.out.println("PI: " + pi.getPi()); logger.close(); } catch (Throwable t) { t.printStackTrace(); } } private static KnowledgeBase readKnowledgeBase() throws Exception { List<RuleResource> resources = new ArrayList<RuleResource>(); resources.add(new RuleResource("rules/CalcPI.drl", ResourceType.DRL)); return KnowledgeBaseHelper.readKnowledgeBase(resources); } }
2. PI.java
package sample.model; import java.math.BigDecimal; /** * @author qin.shuq * @see http://zh.wikipedia.org/wiki/%E5%9C%93%E5%91%A8%E7%8E%87 */ public class PI { private BigDecimal pi; // PI 值 private int iterValue; // 迭代值 private IterStrategy iterStrategy ; // 迭代策略 public PI() { iterStrategy = IterStrategySetting.WallisMethod.getStrategy(); this.pi = BigDecimal.valueOf(IterStrategySetting.WallisMethod.getInitPi()); this.iterValue = IterStrategySetting.WallisMethod.getInitIterValue(); } public PI(IterStrategy strategy) { this.iterStrategy = strategy; this.pi = BigDecimal.valueOf(IterStrategySetting.toEnum(this.iterStrategy).getInitPi()); this.iterValue = IterStrategySetting.toEnum(this.iterStrategy).getInitIterValue(); } private static final IterStrategy leibnizStrategy = new LeibnizIterStrategy(); private static final IterStrategy wallisStrategy = new WallisIterStrategy(); private static final IterStrategy arctanStrategy = new ArctanIterStrategy(); private static final IterStrategy ballardStrategy = new BallardIterStrategy(); /** * 迭代一次的计算 */ public void iterOne() { iterStrategy.iterCalcOne(this); } public BigDecimal getPi() { return pi; } public void setPi(BigDecimal pi) { this.pi = pi; } public int getIterValue() { return iterValue; } public void setIterValue(int iterValue) { this.iterValue = iterValue; } public void setIterStrategy(IterStrategy iterStrategy) { this.iterStrategy = iterStrategy; this.pi = BigDecimal.valueOf(IterStrategySetting.toEnum(this.iterStrategy).getInitPi()); this.iterValue = IterStrategySetting.toEnum(this.iterStrategy).getInitIterValue(); } public enum IterStrategySetting { LeibnizMethod(leibnizStrategy, 4, 1), // PI: 3.141590653589692 iterValue: 1000000 WallisMethod(wallisStrategy, 2, 1), // PI: 3.141591082795387 iterValue: 1000000 // PI: 3.141592653589793057092897568389359 // 021087492184878678890301622544682 // 870922262624376585084262078791652 // 664665170934387960240111985365743 // 816329749380749612568341860137676 // 992899578827196104523046458933737 // 232212198503616995641765457187290 // 803101355648406923221343642309071 // 354773081438421905649763339659738 // 095339778728962929492812141689849872323987745 // iterValue: 183 ArctanMethod(arctanStrategy, 4*((double)44/57+(double)7/239-(double)12/682+(double)24/12943), 1), ballardMethod(ballardStrategy, 0.015625*(-32-(double)1/3+256-(double)64/3-0.8-(double)4/7+(double)1/9), 0); private IterStrategy strategy; private double initPi; private int initIterValue; private IterStrategySetting(IterStrategy strategy, double initPi, int initIterValue) { this.strategy = strategy; this.initPi = initPi; this.initIterValue = initIterValue; } public double getInitPi() { return initPi; } public int getInitIterValue() { return initIterValue; } public void setStrategy(IterStrategy strategy) { this.strategy = strategy; } public IterStrategy getStrategy() { return strategy; } public static IterStrategySetting toEnum(IterStrategy strategy) { for (IterStrategySetting s: IterStrategySetting.values()) { if (strategy.equals(s.getStrategy())) { return s; } } return null; } } } interface IterStrategy { void iterCalcOne(PI pi); } class LeibnizIterStrategy implements IterStrategy { public void iterCalcOne(PI pi) { /** * according to formula : * PI/4 = (1-1/3+1/5-1/7+1/9-...) */ int iterValue = pi.getIterValue()+2; pi.setIterValue(iterValue); int sign = (iterValue % 4 == 3) ? -1 : 1; pi.setPi(BigDecimal.valueOf(pi.getPi().doubleValue() + (double) 4 * sign / iterValue)); } } class WallisIterStrategy implements IterStrategy { public void iterCalcOne(PI pi) { /** * according to formula : * PI/2 = (2/1 * 2/3) * (4/3 * 4/5) * (6/5 * 6/7) ... */ long iterValue = pi.getIterValue(); double newpi = pi.getPi().doubleValue() * (1 + (double)1/(iterValue*(iterValue+2))); pi.setPi(BigDecimal.valueOf(newpi)); pi.setIterValue((int)(iterValue+2)); } } /** * PI: 3.141592653589793 iterValue: 183 */ class ArctanIterStrategy implements IterStrategy { public void iterCalcOne(PI pi) { /** * according to formula : * PI/4 = 44arctan(1/57) + 7arctan(1/239) - 12arctan(1/682) + 24arctan(1/12943) * arctan(x) = x - 1/3*x^3 + 1/5*x^5 - 1/7*x^7 */ long iterValue = pi.getIterValue() + 2; int sign = (iterValue % 4 == 3) ? -1 : 1; BigDecimal part1 = BigDecimal.valueOf((double)44*Math.pow((double)1/57, iterValue)); BigDecimal part2 = BigDecimal.valueOf((double)7*Math.pow((double)1/239, iterValue)); BigDecimal part3 = BigDecimal.valueOf((double)12*Math.pow((double)1/682, iterValue)); BigDecimal part4 = BigDecimal.valueOf((double)24*Math.pow((double)1/12943, iterValue)); BigDecimal incre = BigDecimal.valueOf(4*sign*((double)1/iterValue)).multiply( part1.add(part2).subtract(part3).add(part4)); pi.setPi(pi.getPi().add(incre)); pi.setIterValue((int)iterValue); } } class BallardIterStrategy implements IterStrategy { /** * PI = 0.015625* SUM(0-n) {(-1)^n/2^(10*n)*(-32/(4n+1)-1/(4n+3)+256/(10n+1)-64/(10n+3)-4/(10n+5)-4/(10n+7)+1/(10n+9)))} */ public void iterCalcOne(PI pi) { int iterValue = pi.getIterValue()+1; int sign = (iterValue % 2 == 0) ? 1: -1; BigDecimal part1 = BigDecimal.valueOf(-32/(double)(4*iterValue+1)); BigDecimal part2 = BigDecimal.valueOf(-1/(double)(4*iterValue+3)); BigDecimal part3 = BigDecimal.valueOf(256/(double)(10*iterValue+1)); BigDecimal part4 = BigDecimal.valueOf(-64/(double)(10*iterValue+3)); BigDecimal part5 = BigDecimal.valueOf(-4/(double)(10*iterValue+5)); BigDecimal part6 = BigDecimal.valueOf(-4/(double)(10*iterValue+7)); BigDecimal part7 = BigDecimal.valueOf(1/(double)(10*iterValue+9)); BigDecimal incre = BigDecimal.valueOf(0.015625*sign/Math.pow(2, 10*iterValue)).multiply( part1.add(part2).add(part3).add(part4).add(part5).add(part6).add(part7)); pi.setPi(pi.getPi().add(incre)); System.out.println(iterValue); pi.setIterValue((int)iterValue); } }
3. RuleResource.java
package sample.model; import org.drools.builder.ResourceType; public class RuleResource { private String ruleResourceFile; private ResourceType resType; public RuleResource(String ruleResourceFile, ResourceType resType) { this.ruleResourceFile = ruleResourceFile; this.resType = resType; } public String getRuleResourceFile() { return ruleResourceFile; } public void setRuleResourceFile(String ruleResourceFile) { this.ruleResourceFile = ruleResourceFile; } public ResourceType getResType() { return resType; } public void setResType(ResourceType resType) { this.resType = resType; } }
4. KnowledgeBaseHelper.java
package sample.helper; import java.util.List; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseFactory; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderError; import org.drools.builder.KnowledgeBuilderErrors; import org.drools.builder.KnowledgeBuilderFactory; import org.drools.io.ResourceFactory; import sample.model.RuleResource; public class KnowledgeBaseHelper { private KnowledgeBaseHelper() {} public static KnowledgeBase readKnowledgeBase(List<RuleResource> resources) { KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); for (RuleResource res: resources) { try { kbuilder.add(ResourceFactory.newClassPathResource(res.getRuleResourceFile()), res.getResType()); } catch (Exception ex) { kbuilder.add(ResourceFactory.newFileResource(res.getRuleResourceFile()), res.getResType()); } } KnowledgeBuilderErrors errors = kbuilder.getErrors(); if (errors.size() > 0) { for (KnowledgeBuilderError error: errors) { System.err.println(error); } throw new IllegalArgumentException("Could not parse knowledge."); } KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(kbuilder.getKnowledgePackages()); return kbase; } }
5. 规则文件
#created on: 2011-1-12 package mymath import sample.model.PI; rule "CalcPI" no-loop false when pi: PI(iterValue<183) then System.out.println("exec rule CalcPI ... "); System.out.println("PI: " + pi.getPi() + " iterValue: " + pi.getIterValue()); pi.iterOne(); update(pi); end
6. POM 文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>drools-study</groupId> <artifactId>drools-study</artifactId> <version>1.0</version> <name>drools-study</name> <description>a project for learning drools5.1.1</description> <dependencies> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> <version>5.1.1</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>5.1.1</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-api</artifactId> <version>5.1.1</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-bpmn2</artifactId> <version>5.1.1</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.3.1</version> </dependency> </dependencies> </project>