FCL compiler - JavaScript

This commit is contained in:
marcin-szczepanski 2022-05-23 11:43:42 +02:00
parent a034eb2f68
commit 3bfa35fa40
31 changed files with 764 additions and 23 deletions

View File

@ -113,6 +113,7 @@
<tr> <td valign=top> Helano P&oacute;voas de Lima </td> <td> DefuzzifierContinuous graphic bug. </td> </tr> <tr> <td valign=top> Helano P&oacute;voas de Lima </td> <td> DefuzzifierContinuous graphic bug. </td> </tr>
<tr> <td valign=top> Nikola Nikolovski </td> <td> RuleBlock name bug.</td> </tr> <tr> <td valign=top> Nikola Nikolovski </td> <td> RuleBlock name bug.</td> </tr>
<tr> <td valign=top> Ivan De Falco </td> <td> "AND Bounded Diff" bug. </td> </tr> <tr> <td valign=top> Ivan De Falco </td> <td> "AND Bounded Diff" bug. </td> </tr>
<tr> <td valign=top> Marcin Szczepanski </td> <td> FCL Compiler (JavaScript). </td> </tr>
</table> </table>
</p> </p>

View File

@ -1,7 +1,7 @@
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// Code generated by jFuzzyLogic // Code generated by jFuzzyLogic
// jFuzzyLogic Version : JFuzzyLogic 3.2g (build 2013-10-20), by Pablo Cingolani // jFuzzyLogic Version : JFuzzyLogic 4.0 (build 2022-05-12), by Pablo Cingolani
// jFuzzyLogic creted by Pablo Cingolani // jFuzzyLogic created by Pablo Cingolani
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------

208
html/fcl/tipper.js Normal file
View File

@ -0,0 +1,208 @@
//--------------------------------------------------------------------------------
// Code generated by jFuzzyLogic
// jFuzzyLogic Version : JFuzzyLogic 4.0 (build 2022-05-12), by Pablo Cingolani
// jFuzzyLogic created by Pablo Cingolani
//--------------------------------------------------------------------------------
function ruleAccumulationMethod_max(defuzzifierValue, valueToAggregate) {
return (defuzzifierValue > valueToAggregate ? defuzzifierValue : valueToAggregate);
}
function ruleActivationMethod_min(degreeOfSupport, membership) {
return (degreeOfSupport < membership ? degreeOfSupport : membership);
}
function ruleConnectionMethod_and(antecedent1, antecedent2) {
return (antecedent1 < antecedent2 ? antecedent1 : antecedent2);
}
function ruleConnectionMethod_or(antecedent1, antecedent2) {
return (antecedent1 > antecedent2 ? antecedent1 : antecedent2);
}
class FunctionBlock_tipper {
// VAR_INPUT
food;
service;
// VAR_OUTPUT
tip;
// FUZZIFY food
food_delicious;
food_rancid;
// FUZZIFY service
service_excellent;
service_good;
service_poor;
// DEFUZZIFY tip
defuzzify_tip;
// Constructor
constructor() {
this.tip = 0.0;
this.defuzzify_tip = new Array(1000);
}
// Calculate function block
calc() {
this.reset();
this.fuzzify();
this.calc_No1();
this.defuzzify();
}
// RULEBLOCK No1
calc_No1() {
// RULE 1 : IF (service IS poor) OR (food IS rancid) THEN tip IS cheap;
let degreeOfSupport_1 = 1.0 * (ruleConnectionMethod_or(this.service_poor, this.food_rancid));
if (degreeOfSupport_1 > 0) {
for (let i = 0; i < 1000; i++) {
let x = 0.0 + i * 0.03;
let membership = this.membership_tip_cheap(x);
let y = ruleActivationMethod_min(degreeOfSupport_1 , membership);
this.defuzzify_tip[i] = ruleAccumulationMethod_max(this.defuzzify_tip[i], y);
}
}
// RULE 2 : IF service IS good THEN tip IS average;
let degreeOfSupport_2 = 1.0 * (this.service_good);
if (degreeOfSupport_2 > 0) {
for (let i = 0; i < 1000; i++) {
let x = 0.0 + i * 0.03;
let membership = this.membership_tip_average(x);
let y = ruleActivationMethod_min(degreeOfSupport_2 , membership);
this.defuzzify_tip[i] = ruleAccumulationMethod_max(this.defuzzify_tip[i], y);
}
}
// RULE 3 : IF (service IS excellent) AND (food IS delicious) THEN tip IS generous;
let degreeOfSupport_3 = 1.0 * (ruleConnectionMethod_and(this.service_excellent, this.food_delicious));
if (degreeOfSupport_3 > 0) {
for (let i = 0; i < 1000; i++) {
let x = 0.0 + i * 0.03;
let membership = this.membership_tip_generous(x);
let y = ruleActivationMethod_min(degreeOfSupport_3 , membership);
this.defuzzify_tip[i] = ruleAccumulationMethod_max(this.defuzzify_tip[i], y);
}
}
}
// Defuzzify
defuzzify() {
let sum_tip = 0.0;
let wsum_tip = 0.0;
let x;
for (let i = 0; i < 1000; i++) {
x = 0.0 + i * 0.03;
sum_tip += this.defuzzify_tip[i];
wsum_tip += x * this.defuzzify_tip[i];
}
this.tip = wsum_tip / sum_tip;
}
// Fuzzify all variables
fuzzify() {
this.food_delicious = this.membership_food_delicious(this.food);
this.food_rancid = this.membership_food_rancid(this.food);
this.service_excellent = this.membership_service_excellent(this.service);
this.service_good = this.membership_service_good(this.service);
this.service_poor = this.membership_service_poor(this.service);
}
// Membership functions
membership_food_delicious(x) {
if (x <= 7.0) return 0.0;
if (x > 9.0) return 1.0;
if (x <= 9.0) return 0.0 + (1.0 - 0.0) * ((x - 7.0) / (9.0 - 7.0));
}
membership_food_rancid(x) {
if (x <= 0.0) return 1.0;
if (x > 3.0) return 0.0;
if (x <= 1.0) return 1.0 + (1.0 - 1.0) * ((x - 0.0) / (1.0 - 0.0));
if (x <= 3.0) return 1.0 + (0.0 - 1.0) * ((x - 1.0) / (3.0 - 1.0));
}
membership_service_excellent(x) {
if (x <= 6.0) return 0.0;
if (x > 9.0) return 1.0;
if (x <= 9.0) return 0.0 + (1.0 - 0.0) * ((x - 6.0) / (9.0 - 6.0));
}
membership_service_good(x) {
if (x <= 1.0) return 0.0;
if (x > 9.0) return 0.0;
if (x <= 4.0) return 0.0 + (1.0 - 0.0) * ((x - 1.0) / (4.0 - 1.0));
if (x <= 6.0) return 1.0 + (1.0 - 1.0) * ((x - 4.0) / (6.0 - 4.0));
if (x <= 9.0) return 1.0 + (0.0 - 1.0) * ((x - 6.0) / (9.0 - 6.0));
}
membership_service_poor(x) {
if (x <= 0.0) return 1.0;
if (x > 4.0) return 0.0;
if (x <= 4.0) return 1.0 + (0.0 - 1.0) * ((x - 0.0) / (4.0 - 0.0));
}
membership_tip_average(x) {
if (x <= 10.0) return 0.0;
if (x > 20.0) return 0.0;
if (x <= 15.0) return 0.0 + (1.0 - 0.0) * ((x - 10.0) / (15.0 - 10.0));
if (x <= 20.0) return 1.0 + (0.0 - 1.0) * ((x - 15.0) / (20.0 - 15.0));
}
membership_tip_cheap(x) {
if (x <= 0.0) return 0.0;
if (x > 10.0) return 0.0;
if (x <= 5.0) return 0.0 + (1.0 - 0.0) * ((x - 0.0) / (5.0 - 0.0));
if (x <= 10.0) return 1.0 + (0.0 - 1.0) * ((x - 5.0) / (10.0 - 5.0));
}
membership_tip_generous(x) {
if (x <= 20.0) return 0.0;
if (x > 30.0) return 0.0;
if (x <= 25.0) return 0.0 + (1.0 - 0.0) * ((x - 20.0) / (25.0 - 20.0));
if (x <= 30.0) return 1.0 + (0.0 - 1.0) * ((x - 25.0) / (30.0 - 25.0));
}
// Print
print() {
console.log("Function block tipper:\n");
console.log(" Input %s: %f\n", "food" , this.food);
console.log(" %s: %f\n", "food_delicious" , this.food_delicious);
console.log(" %s: %f\n", "food_rancid" , this.food_rancid);
console.log(" Input %s: %f\n", "service" , this.service);
console.log(" %s: %f\n", "service_excellent" , this.service_excellent);
console.log(" %s: %f\n", "service_good" , this.service_good);
console.log(" %s: %f\n", "service_poor" , this.service_poor);
console.log(" Output %s: %f\n", "tip" , this.tip);
}
// Reset output
reset() {
for (let i = 0 ; i < 1000; i++) {
this.defuzzify_tip[i] = 0.0;
}
}
};
function main(food, service) {
// Create function blocks
const tipper = new FunctionBlock_tipper();
// Parse input
tipper.food = food;
tipper.service = service;
// Calculate
tipper.calc();
// Show results
tipper.print();
}

BIN
html/images/js.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@ -180,6 +180,7 @@
<p class="lead">Tons of advanced features <p class="lead">Tons of advanced features
<ul> <ul>
<li> C++ compiler (convert FCL to C++) <li> C++ compiler (convert FCL to C++)
<li> JavaScript compiler (convert FCL to JavaScript)
<li> Core library available for Android developers <img src="images/android.png"> <li> Core library available for Android developers <img src="images/android.png">
<li> Parameter optimization <li> Parameter optimization
<li> Parametric membership functions <li> Parametric membership functions

View File

@ -86,6 +86,7 @@
<a class="list-group-item" href="#using">Using jFuzzyLogic in projects</a> <a class="list-group-item" href="#using">Using jFuzzyLogic in projects</a>
<a class="list-group-item" href="#plugin">Eclipse plug-in</a> <a class="list-group-item" href="#plugin">Eclipse plug-in</a>
<a class="list-group-item" href="#compiler">FCL compiler</a> <a class="list-group-item" href="#compiler">FCL compiler</a>
<a class="list-group-item" href="#compilerJS">FCL compiler (JavaScript)</a>
<a class="list-group-item" href="#optim">Parameter optimization</a> <a class="list-group-item" href="#optim">Parameter optimization</a>
</ul> </ul>
</div> </div>
@ -956,11 +957,32 @@ java -jar jFuzzyLogic.jar -c tipper.fcl > tipper.cpp
</p> </p>
</section> </section>
<section id="compilerJS">
<div class="page-header">
<h1>10. FCL compiler (JavaScript)</h1>
</div>
<p class="lead">
jFuzzyLogic can compile FCL into JavaScript code.
</p>
<p>
A built in compiler allows to compiler FCL code into JavaScript.
For instance, by simply running the following command, we can create a JavaScript program that has the same functionality as the FCL program:
<pre>
java -jar jFuzzyLogic.jar -j tipper.fcl > tipper.js
</pre>
The previous command creates <a href="fcl/tipper.js">this JavaScript code</a>.
<br>
<br>
<img src="images/js.png">
</p>
</section>
<!-- Parameter optimization <!-- Parameter optimization
================================================== --> ================================================== -->
<section id="optim"> <section id="optim">
<div class="page-header"> <div class="page-header">
<h1>10. Parameter optimization</h1> <h1>11. Parameter optimization</h1>
</div> </div>
<p class="lead"> <p class="lead">
jFuzzyLogic provides a parameter optimization framework, allowing to learn or refine fuzzy parameters using machine learning algorithms. jFuzzyLogic provides a parameter optimization framework, allowing to learn or refine fuzzy parameters using machine learning algorithms.

View File

@ -0,0 +1,11 @@
package net.sourceforge.jFuzzyLogic;
/**
* Create JS code
*
* @author marcin-szczepanski
*/
public interface CompileJS {
public String toStringJS();
}

View File

@ -257,7 +257,7 @@ public class FIS extends FclObject implements Iterable<FunctionBlock>, CompileCp
out.append("//--------------------------------------------------------------------------------\n"); out.append("//--------------------------------------------------------------------------------\n");
out.append("// Code generated by jFuzzyLogic\n"); out.append("// Code generated by jFuzzyLogic\n");
out.append("// jFuzzyLogic Version : " + JFuzzyLogic.VERSION + " \n"); out.append("// jFuzzyLogic Version : " + JFuzzyLogic.VERSION + " \n");
out.append("// jFuzzyLogic creted by Pablo Cingolani\n"); out.append("// jFuzzyLogic created by Pablo Cingolani\n");
out.append("//--------------------------------------------------------------------------------\n\n"); out.append("//--------------------------------------------------------------------------------\n\n");
out.append("\n#include <stdio.h>\n"); out.append("\n#include <stdio.h>\n");
out.append("\n#include <stdlib.h>\n"); out.append("\n#include <stdlib.h>\n");
@ -337,6 +337,117 @@ public class FIS extends FclObject implements Iterable<FunctionBlock>, CompileCp
return out.toString(); return out.toString();
} }
/**
* Create a JS code for this FIS
* @return
*/
@Override
public String toStringJS() {
StringBuffer out = new StringBuffer();
out.append("//--------------------------------------------------------------------------------\n");
out.append("// Code generated by jFuzzyLogic\n");
out.append("// jFuzzyLogic Version : " + JFuzzyLogic.VERSION + " \n");
out.append("// jFuzzyLogic created by Pablo Cingolani\n");
out.append("//--------------------------------------------------------------------------------\n\n");
// Sort function blocks by name
ArrayList<String> fbNames = new ArrayList<String>(functionBlocks.keySet());
Collections.sort(fbNames);
// Ge all activations and accumulation methods
HashSet<RuleAccumulationMethod> raccs = new HashSet<RuleAccumulationMethod>();
HashSet<RuleActivationMethod> racts = new HashSet<RuleActivationMethod>();
HashSet<RuleConnectionMethod> rcons = new HashSet<RuleConnectionMethod>();
for (String name : fbNames) {
FunctionBlock functionBlock = getFunctionBlock(name);
for (RuleBlock rb : functionBlock.getRuleBlocks().values()) {
raccs.add(rb.getRuleAccumulationMethod());
racts.add(rb.getRuleActivationMethod());
for (Rule r : rb) {
RuleExpression rexp = r.getAntecedents();
rcons.addAll(rexp.getRuleConnectionMethods());
}
}
}
// Show code
for (RuleAccumulationMethod racc : raccs)
out.append(racc.toStringJSFunction() + "\n");
for (RuleActivationMethod ract : racts)
out.append(ract.toStringJSFunction() + "\n");
for (RuleConnectionMethod rcon : rcons)
out.append(rcon.toStringJSFunction() + "\n");
// Iterate over each function block and append it to output string
for (String name : fbNames) {
FunctionBlock functionBlock = getFunctionBlock(name);
out.append(functionBlock.toStringJS());
}
// Main method
out.append("function main(");
int inV = 0;
for (String name : fbNames) {
FunctionBlock functionBlock = getFunctionBlock(name);
for (Variable var : functionBlock.variablesSorted()) {
if (var.isInput()) {
out.append(var.getName());
if (inV < (functionBlock.variablesSorted().size() - 1)) {
out.append(", ");
}
inV++;
}
}
}
String outWithMainStr = out.toString();
if (outWithMainStr.endsWith(", ")) {
outWithMainStr = outWithMainStr.substring(0, outWithMainStr.length() - 2);
out = new StringBuffer(outWithMainStr);
}
out.append(") {\n");
// Create function blocks
out.append("\t// Create function blocks\n");
for (String name : fbNames)
out.append("\tconst " + name + " = new FunctionBlock_" + name + "();\n");
out.append("\n");
// Assign values
out.append("\t// Parse input\n");
int inVar = 1;
for (String name : fbNames) {
FunctionBlock functionBlock = getFunctionBlock(name);
for (Variable var : functionBlock.variablesSorted()) {
if (var.isInput()) {
out.append("\t" + name + "." + var.getName() + " = " + var.getName() + ";\n");
inVar++;
}
}
}
out.append("\n");
// Calculate
out.append("\t// Calculate\n");
for (String name : fbNames)
out.append("\t" + name + ".calc();\n");
out.append("\n");
// Show results
out.append("\t// Show results\n");
for (String name : fbNames)
out.append("\t" + name + ".print();\n");
out.append("}");
return out.toString();
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
StringBuffer out = new StringBuffer(); StringBuffer out = new StringBuffer();

View File

@ -740,6 +740,131 @@ public class FunctionBlock extends FclObject implements Iterable<RuleBlock>, Com
; // ; //
} }
@Override
public String toStringJS() {
StringBuffer calcMethod = new StringBuffer(); // Method calc()
StringBuffer constructor = new StringBuffer(); // Constructor
StringBuffer defuzzifyMethod = new StringBuffer(); // Method defuzzify()
StringBuffer fuzzifyMethod = new StringBuffer(); // Fuzzify method
StringBuffer membershipMethods = new StringBuffer(); // All membership functions
StringBuffer printMethod = new StringBuffer(); // Method print()
StringBuffer resetMethod = new StringBuffer(); // Method reset()
StringBuffer varDefuzzifiers = new StringBuffer(); // All defuzzifier variables
StringBuffer varsFuzzify = new StringBuffer(); // Fuzzify variables
StringBuffer varsIn = new StringBuffer(); // Input vars
StringBuffer varsOut = new StringBuffer(); // Output vars
varsIn.append("\t// VAR_INPUT\n");
varsOut.append("\t// VAR_OUTPUT\n");
// Methods
String className = "FunctionBlock_" + name;
calcMethod.append("\t// Calculate function block\n\tcalc() {\n\t\tthis.reset();\n\t\tthis.fuzzify();\n");
constructor.append("\t// Constructor\n\tconstructor() {\n");
defuzzifyMethod.append("\t// Defuzzify \n\tdefuzzify() {\n");
fuzzifyMethod.append("\t// Fuzzify all variables\n\tfuzzify() {\n");
membershipMethods.append("\t// Membership functions \n");
printMethod.append("\t// Print \n\tprint() {\n\t\tconsole.log(\"Function block " + name + ":\\n\");\n");
resetMethod.append("\t// Reset output\n\treset() {\n");
//---
// Show variables (sorted by name)
//---
for (Variable var : variablesSorted()) {
var.estimateUniverse();
if (!Double.isNaN(var.getDefaultValue())) constructor.append("\t\tthis." + var.getName() + " = " + var.getDefaultValue() + ";\n");
if (var.isInput()) {
// Add input variables
varsIn.append("\t" + var.getName());
varsIn.append(";\n");
// Add to print method
printMethod.append("\t\tconsole.log(\"\tInput %s: %f\\n\", \"" + var.getName() + "\" , this." + var.getName() + ");\n");
// Add fuzzyfiers
varsFuzzify.append("\t// FUZZIFY " + var.getName() + "\n");
for (LinguisticTerm linguisticTerm : var.linguisticTermsSorted()) {
String ltVar = var.getName() + "_" + linguisticTerm.getTermName();
varsFuzzify.append("\t" + ltVar + ";\n");
fuzzifyMethod.append("\t\tthis." + ltVar + " = this." + linguisticTerm.toStringJSMethodName(var) + "(this." + var.getName() + ");\n");
// Membership function
membershipMethods.append(linguisticTerm.toStringJS(var) + "\n");
// Add to print method
printMethod.append("\t\tconsole.log(\"\t %s: %f\\n\", \"" + ltVar + "\" , this." + ltVar + ");\n");
}
varsFuzzify.append("\n");
} else {
int len = ((DefuzzifierContinuous) var.getDefuzzifier()).getLength();
constructor.append("\t\tthis." + var.toStringJSDefuzzifyVarName() + " = new Array(" + len + ");\n");
// Add output variables
varsOut.append("\t" + var.getName());
varsOut.append(";\n");
// Add to print method
printMethod.append("\t\tconsole.log(\"\tOutput %s: %f\\n\", \"" + var.getName() + "\" , this." + var.getName() + ");\n");
// Add defuzzyfier variable
varDefuzzifiers.append("\t// DEFUZZIFY " + var.getName() + "\n");
varDefuzzifiers.append("\t" + var.toStringJSDefuzzifyVarName() + ";\n");
// Add to reset method
resetMethod.append("\t\tfor (let i = 0 ; i < " + len + "; i++) {\n\t\t\tthis." + var.toStringJSDefuzzifyVarName() + "[i] = 0.0;\n\t\t}\n");
for (LinguisticTerm linguisticTerm : var.linguisticTermsSorted()) {
// Membership function
membershipMethods.append(linguisticTerm.toStringJS(var) + "\n");
}
varDefuzzifiers.append("\n");
defuzzifyMethod.append(var.getDefuzzifier().toStringJS());
}
}
//---
// Iterate over each ruleSet and append it to output string
// Sort ruleBlocks by name
//---
StringBuffer ruleBlocksStr = new StringBuffer();
for (RuleBlock ruleBlock : ruleBlocksSorted()) {
ruleBlocksStr.append(ruleBlock.toStringJS());
calcMethod.append("\t\tthis.calc_" + ruleBlock.getName() + "();\n");
}
constructor.append("\t}\n");
calcMethod.append("\t\tthis.defuzzify();\n\t}\n");
defuzzifyMethod.append("\t}\n");
fuzzifyMethod.append("\t}\n");
printMethod.append("\t}\n");
resetMethod.append("\t}\n");
// Build the whole thing
return "class FunctionBlock_" + name + " {\n\n" //
+ varsIn + "\n" //
+ varsOut //
+ "\n" //
+ varsFuzzify //
+ varDefuzzifiers //
+ constructor + "\n" //
+ calcMethod + "\n" //
+ ruleBlocksStr + "\n" //
+ defuzzifyMethod + "\n" //
+ fuzzifyMethod + "\n" //
+ membershipMethods + "\n" //
+ printMethod + "\n" //
+ resetMethod + "\n" //
+ "};\n\n" //
; //
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
StringBuffer varsIn = new StringBuffer(); StringBuffer varsIn = new StringBuffer();

View File

@ -1,6 +1,5 @@
package net.sourceforge.jFuzzyLogic; package net.sourceforge.jFuzzyLogic;
import net.sourceforge.jFuzzyLogic.ruleConnectionMethod.Szczepanski;
import org.antlr.runtime.RecognitionException; import org.antlr.runtime.RecognitionException;
import net.sourceforge.jFuzzyLogic.demo.tipper.TipperAnimation; import net.sourceforge.jFuzzyLogic.demo.tipper.TipperAnimation;
@ -24,7 +23,7 @@ public class JFuzzyLogic {
public static final String BUILD = "2022-05-12"; public static final String BUILD = "2022-05-12";
public static final String VERSION_MAJOR = "4.0"; public static final String VERSION_MAJOR = "4.0";
public static final String VERSION_SHORT = VERSION_MAJOR + REVISION; public static final String VERSION_SHORT = VERSION_MAJOR + REVISION;
public static final String VERSION_NO_NAME = VERSION_SHORT + " (build " + BUILD + "), by " + Pcingola.BY + " and " + Szczepanski.BY; public static final String VERSION_NO_NAME = VERSION_SHORT + " (build " + BUILD + "), by " + Pcingola.BY;
public static final String VERSION = SOFTWARE_NAME + " " + VERSION_NO_NAME; public static final String VERSION = SOFTWARE_NAME + " " + VERSION_NO_NAME;
public static boolean debug = false; public static boolean debug = false;
@ -56,6 +55,21 @@ public class JFuzzyLogic {
} }
} }
/**
* Compile an FCL program into JavaScript
*/
void compileJS(String fileName) {
load(fileName); // Read FIS
System.out.println(fis.toStringJS()); // Show JS code
// Dump JS code to a file (debug)
if (debug) {
String jsfile = Gpr.HOME + "/x.js";
Gpr.debug("Writing to file " + jsfile);
Gpr.toFile(jsfile, fis.toStringJS());
}
}
/** /**
* Run demo * Run demo
*/ */
@ -170,6 +184,11 @@ public class JFuzzyLogic {
String fileName = args[++i]; String fileName = args[++i];
compile(fileName); compile(fileName);
return; return;
} else if (arg.equals("-j")) {
// Sanity check
String fileName = args[++i];
compileJS(fileName);
return;
} else if (arg.equals("-e")) { } else if (arg.equals("-e")) {
evaluate(i + 1); evaluate(i + 1);
return; return;
@ -202,11 +221,12 @@ public class JFuzzyLogic {
System.err.println("Usage: java -jar jFuzzyLogic.jar [-noCharts] [{-e|-c}] file.fcl [in_1 ... in_N]"); System.err.println("Usage: java -jar jFuzzyLogic.jar [-noCharts] [{-e|-c}] file.fcl [in_1 ... in_N]");
System.err.println("Options:"); System.err.println("Options:");
System.err.println("\t file.fcl : Load FCL file and show memebership functions (default, when no option is provided)."); System.err.println("\t file.fcl : Load FCL file and show membership functions (default, when no option is provided).");
System.err.println("\t-c file.fcl : Compile. Generate C++ code from FCL file (to STDOUT)"); System.err.println("\t-c file.fcl : Compile. Generate C++ code from FCL file (to STDOUT)");
System.err.println("\t-j file.fcl : Compile. Generate JavaScript code from FCL file (to STDOUT)");
System.err.println("\t-e file.fcl in_1 in_2 ... in_N : Evaluate. Load FCL file, assign inputs i_1, i_2, ..., i_n and evaluate (variables sorted alphabetically)."); System.err.println("\t-e file.fcl in_1 in_2 ... in_N : Evaluate. Load FCL file, assign inputs i_1, i_2, ..., i_n and evaluate (variables sorted alphabetically).");
System.err.println("\t-noCharts : Use a mock class for charts. This is used when not compiled using JFreeCharts."); System.err.println("\t-noCharts : Use a mock class for charts. This is used when not compiled using JFreeCharts.");
System.err.println("\tdemo : Run a demo exmaple (tipper.fcl)"); System.err.println("\tdemo : Run a demo example (tipper.fcl)");
System.exit(1); System.exit(1);
} }
} }

View File

@ -68,4 +68,9 @@ public abstract class Defuzzifier extends FclObject {
public String toStringCpp() { public String toStringCpp() {
throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName()); throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName());
} }
@Override
public String toStringJS() {
throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName());
}
} }

View File

@ -51,6 +51,27 @@ public class DefuzzifierCenterOfGravity extends DefuzzifierContinuous {
return out.toString(); return out.toString();
} }
@Override
public String toStringJS() {
StringBuilder out = new StringBuilder();
String defuzzName = "defuzzify_" + variable.getName();
String sumName = "sum_" + variable.getName();
String wsumName = "wsum_" + variable.getName();
out.append("\t\tlet " + sumName + " = 0.0;\n");
out.append("\t\tlet " + wsumName + " = 0.0;\n");
out.append("\t\tlet x;\n");
out.append("\t\tfor (let i = 0; i < " + getLength() + "; i++) {\n");
out.append("\t\t\tx = " + min + " + i * " + stepSize + ";\n");
out.append("\t\t\t" + sumName + " += this." + defuzzName + "[i];\n");
out.append("\t\t\t" + wsumName + " += x * this." + defuzzName + "[i];\n");
out.append("\t\t}\n");
out.append("\t\tthis." + variable.getName() + " = " + wsumName + " / " + sumName + ";\n");
return out.toString();
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
return "METHOD : COG;"; return "METHOD : COG;";

View File

@ -1,6 +1,7 @@
package net.sourceforge.jFuzzyLogic.fcl; package net.sourceforge.jFuzzyLogic.fcl;
import net.sourceforge.jFuzzyLogic.CompileCpp; import net.sourceforge.jFuzzyLogic.CompileCpp;
import net.sourceforge.jFuzzyLogic.CompileJS;
/** /**
* The root of all FCL objects * The root of all FCL objects
@ -8,7 +9,7 @@ import net.sourceforge.jFuzzyLogic.CompileCpp;
* @author pcingola * @author pcingola
* *
*/ */
public abstract class FclObject implements CompileCpp { public abstract class FclObject implements CompileCpp, CompileJS {
@Override @Override
public String toString() { public String toString() {
@ -20,5 +21,10 @@ public abstract class FclObject implements CompileCpp {
return "// " + this.getClass().getName(); return "// " + this.getClass().getName();
} }
@Override
public String toStringJS() {
return "// " + this.getClass().getName();
}
public abstract String toStringFcl(); public abstract String toStringFcl();
} }

View File

@ -110,6 +110,11 @@ public abstract class MembershipFunction extends FclObject {
throw new RuntimeException("Unimplemented method 'toStringCpp()' for class " + this.getClass().getCanonicalName()); throw new RuntimeException("Unimplemented method 'toStringCpp()' for class " + this.getClass().getCanonicalName());
} }
@Override
public String toStringJS() {
throw new RuntimeException("Unimplemented method 'toStringJS()' for class " + this.getClass().getCanonicalName());
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
return getName(); return getName();

View File

@ -157,6 +157,17 @@ public class MembershipFunctionPieceWiseLinear extends MembershipFunctionContinu
return sb.toString(); return sb.toString();
} }
@Override
public String toStringJS() {
StringBuilder sb = new StringBuilder();
int i, len = x.length;
sb.append("\t\tif (x <= " + x[0].getValue() + ")\t\treturn " + y[0].getValue() + ";\n");
sb.append("\t\tif (x > " + x[len - 1].getValue() + ")\t\treturn " + y[len - 1].getValue() + ";\n");
for (i = 1; i < len; i++)
sb.append("\t\tif (x <= " + x[i].getValue() + ")\t\treturn " + y[i - 1].getValue() + " + (" + y[i].getValue() + " - " + y[i - 1].getValue() + ") * ((x - " + x[i - 1].getValue() + ") / (" + x[i].getValue() + " - " + x[i - 1].getValue() + "));\n");
return sb.toString();
}
/** FCL representation */ /** FCL representation */
@Override @Override
public String toStringFcl() { public String toStringFcl() {

View File

@ -116,6 +116,18 @@ public abstract class MffFunction extends FclObject {
return out + ")"; return out + ")";
} }
@Override
public String toStringJS() {
if (terms == null) return "";
String out = this.getClass().getSimpleName() + "(";
for (int i = 0; i < terms.length; i++) {
out += terms[i].toStringFcl();
if (i < terms.length - 1) out += ", ";
}
return out + ")";
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
if (terms == null) return ""; if (terms == null) return "";

View File

@ -59,10 +59,22 @@ public class LinguisticTerm extends FclObject implements Comparable<LinguisticTe
return sb.toString(); return sb.toString();
} }
public String toStringJS(Variable var) {
StringBuilder sb = new StringBuilder();
sb.append("\t" + toStringJSMethodName(var) + "(x) {\n");
sb.append(membershipFunction.toStringJS());
sb.append("\t}\n");
return sb.toString();
}
public String toStringCppMethodName(Variable var) { public String toStringCppMethodName(Variable var) {
return "membership_" + var.getName() + "_" + getTermName(); return "membership_" + var.getName() + "_" + getTermName();
} }
public String toStringJSMethodName(Variable var) {
return "membership_" + var.getName() + "_" + getTermName();
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
return "TERM " + termName + " := " + membershipFunction.toStringFcl() + ";"; return "TERM " + termName + " := " + membershipFunction.toStringFcl() + ";";

View File

@ -187,6 +187,24 @@ public class Rule extends FclObject implements CompileCpp {
return sb.toString(); return sb.toString();
} }
@Override
public String toStringJS() {
RuleActivationMethod ruleActivationMethod = ruleBlock.getRuleActivationMethod();
StringBuilder sb = new StringBuilder();
// Show antecedents
String dosName = "degreeOfSupport_" + name;
sb.append("\t\tlet " + dosName + " = " + weight + " * (" + antecedents.toStringJS() + ");\n");
// Accumulate & activate
RuleAccumulationMethod ruleAccumulationMethod = ruleBlock.getRuleAccumulationMethod();
for (RuleTerm term : consequents)
sb.append(ruleActivationMethod.toStringJS(term, ruleAccumulationMethod, dosName) + "\n");
return sb.toString();
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
String strAnt = "", strCon = ""; String strAnt = "", strCon = "";

View File

@ -441,6 +441,28 @@ public class RuleBlock extends FclObject implements Iterable<Rule>, Comparable<R
return rb.toString(); return rb.toString();
} }
public String toStringJS() {
StringBuffer rb = new StringBuffer();
rb.append("\t// RULEBLOCK " + name + "\n");
rb.append("\tcalc_" + name + "() {\n");
// Show rules
int ruleNum = 1;
for (Rule rule : rules) {
// Rule name/number
String name = rule.getName();
if ((name == null) || (name.equals(""))) name = Integer.toString(ruleNum);
rb.append("\t\t// RULE " + name + " : " + rule.toStringFcl() + "\n");
rb.append(rule.toStringJS());
ruleNum++;
}
rb.append("\t}\n");
return rb.toString();
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
StringBuffer rb = new StringBuffer(); StringBuffer rb = new StringBuffer();

View File

@ -237,6 +237,35 @@ public class RuleExpression extends FclObject implements Iterable<Variable>, Com
return str; return str;
} }
@Override
public String toStringJS() {
String str = "";
String connector = ruleConnectionMethod.toStringJS();
if ((term1 == null) || (term2 == null)) {
// Only one term?
if (term1 != null) str += term1.toStringJS();
if (term2 != null) str += term2.toStringJS();
} else {
str += connector + "(";
// Both terms connected
if (isFuzzyRuleExpression(term1)) str += ((RuleExpression) term1).toStringJS();
else if (isFuzzyRuleTerm(term1)) str += ((RuleTerm) term1).toStringJS();
str += ", ";
if (isFuzzyRuleExpression(term2)) str += ((RuleExpression) term2).toStringJS();
else if (isFuzzyRuleTerm(term2)) str += ((RuleTerm) term2).toStringJS();
str += ")";
}
if (negated) str = "1.0 - (" + str + ")";
return str;
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
String str = ""; String str = "";

View File

@ -73,10 +73,21 @@ public class RuleTerm extends FclObject {
return neg + variable.getName() + "_" + termName; return neg + variable.getName() + "_" + termName;
} }
@Override
public String toStringJS() {
String neg = "";
if (negated) neg = "1 -";
return neg + "this." + variable.getName() + "_" + termName;
}
public String toStringCppDeffName() { public String toStringCppDeffName() {
return getVariable().getName() + "_" + getTermName(); return getVariable().getName() + "_" + getTermName();
} }
public String toStringJSDeffName() {
return getVariable().getName() + "_" + getTermName();
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
String is = "IS"; String is = "IS";

View File

@ -338,6 +338,27 @@ public class Variable extends FclObject implements Comparable<Variable>, Iterabl
return "defuzzify_" + getName(); return "defuzzify_" + getName();
} }
@Override
public String toStringJS() {
String str = name + " : \n";
// Show defuzifier for "output" variables, value for "input" variables
if (defuzzifier != null) str += "\tDefuzzifier : " + defuzzifier.toString() + "\n\tLatest defuzzified value: " + latestDefuzzifiedValue + "\n";
else str += "\tValue: " + value + "\n";
if (!Double.isNaN(defaultValue)) str += "\tDefault value: " + defaultValue + "\n";
// Show each 'termName' and it's membership function
for (LinguisticTerm linguisticTerm : this)
str += "\t" + linguisticTerm.toString(value) + "\n";
return str;
}
public String toStringJSDefuzzifyVarName() {
return "defuzzify_" + getName();
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
return name; return name;

View File

@ -49,8 +49,17 @@ public abstract class RuleAccumulationMethod extends FclObject {
return "ruleAccumulationMethod_" + getName(); return "ruleAccumulationMethod_" + getName();
} }
@Override
public String toStringJS() {
return "ruleAccumulationMethod_" + getName();
}
public String toStringCppFunction() { public String toStringCppFunction() {
throw new RuntimeException("Unimplemented method foe class " + this.getClass().getCanonicalName()); throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName());
}
public String toStringJSFunction() {
throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName());
} }
@Override @Override

View File

@ -24,6 +24,11 @@ public class RuleAccumulationMethodMax extends RuleAccumulationMethod {
return "double " + toStringCpp() + "(double defuzzifierValue, double valueToAggregate)\t{ return ( defuzzifierValue > valueToAggregate ? defuzzifierValue : valueToAggregate ); }\n"; return "double " + toStringCpp() + "(double defuzzifierValue, double valueToAggregate)\t{ return ( defuzzifierValue > valueToAggregate ? defuzzifierValue : valueToAggregate ); }\n";
} }
@Override
public String toStringJSFunction() {
return "function " + toStringJS() + "(defuzzifierValue, valueToAggregate) {\n\treturn (defuzzifierValue > valueToAggregate ? defuzzifierValue : valueToAggregate);\n}\n";
}
/** /**
* @see net.sourceforge.jFuzzyLogic.ruleAccumulationMethod.RuleAccumulationMethod#toStringFcl() * @see net.sourceforge.jFuzzyLogic.ruleAccumulationMethod.RuleAccumulationMethod#toStringFcl()
*/ */

View File

@ -157,7 +157,49 @@ public abstract class RuleActivationMethod extends FclObject {
} }
public String toStringCppFunction() { public String toStringCppFunction() {
throw new RuntimeException("Unimplemented method foe class " + this.getClass().getCanonicalName()); throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName());
}
@Override
public String toStringJS() {
return "ruleActivationMethod_" + name;
}
public String toStringJS(RuleTerm fuzzyRuleTerm, RuleAccumulationMethod ruleAccumulationMethod, String degreeOfSupportName) {
StringBuilder out = new StringBuilder();
Variable variable = fuzzyRuleTerm.getVariable();
Defuzzifier defuzzifier = variable.getDefuzzifier();
if (fuzzyRuleTerm.getMembershipFunction().isDiscrete()) {
throw new RuntimeException("Unimplemented for discre cases!");
} else {
//---
// Continuous case
//---
DefuzzifierContinuous defuzzifierContinuous = (DefuzzifierContinuous) defuzzifier;
// Add membership function to defuzzifier
out.append("\t\tif (" + degreeOfSupportName + " > 0) {\n");
out.append("\t\t\tfor (let i = 0; i < " + defuzzifierContinuous.getLength() + "; i++) {\n");
out.append("\t\t\t\tlet x = " + defuzzifierContinuous.getMin() + " + i * " + defuzzifierContinuous.getStepSize() + ";\n");
// Is term negated?
if (fuzzyRuleTerm.isNegated()) out.append("\t\t\tlet membership = 1 - mf.membership(x);\n");
else out.append("\t\t\t\tlet membership = this." + fuzzyRuleTerm.getLinguisticTerm().toStringJSMethodName(fuzzyRuleTerm.getVariable()) + "(x);\n");
out.append("\t\t\t\tlet y = " + toStringJS() + "(" + degreeOfSupportName + " , membership);\n");
// Aggregate value
out.append("\t\t\t\tthis." + variable.toStringJSDefuzzifyVarName() + "[i] = " + ruleAccumulationMethod.toStringJS() + "(this." + variable.toStringJSDefuzzifyVarName() + "[i], y);\n");
out.append("\t\t\t}\n");
out.append("\t\t}\n");
}
return out.toString();
}
public String toStringJSFunction() {
throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName());
} }
} }

View File

@ -22,6 +22,11 @@ public class RuleActivationMethodMin extends RuleActivationMethod {
return "double " + toStringCpp() + "(double degreeOfSupport, double membership)\t{ return (degreeOfSupport < membership ? degreeOfSupport : membership); }\n"; return "double " + toStringCpp() + "(double degreeOfSupport, double membership)\t{ return (degreeOfSupport < membership ? degreeOfSupport : membership); }\n";
} }
@Override
public String toStringJSFunction() {
return "function " + toStringJS() + "(degreeOfSupport, membership) {\n\treturn (degreeOfSupport < membership ? degreeOfSupport : membership);\n}\n";
}
/** Printable FCL version */ /** Printable FCL version */
@Override @Override
public String toStringFcl() { public String toStringFcl() {

View File

@ -40,8 +40,17 @@ public abstract class RuleConnectionMethod extends FclObject {
return "ruleConnectionMethod_" + name; return "ruleConnectionMethod_" + name;
} }
@Override
public String toStringJS() {
return "ruleConnectionMethod_" + name;
}
public String toStringCppFunction() { public String toStringCppFunction() {
throw new RuntimeException("Unimplemented method foe class " + this.getClass().getCanonicalName()); throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName());
}
public String toStringJSFunction() {
throw new RuntimeException("Unimplemented method for class " + this.getClass().getCanonicalName());
} }
} }

View File

@ -31,6 +31,11 @@ public class RuleConnectionMethodAndMin extends RuleConnectionMethod {
return "double " + toStringCpp() + "(double antecedent1, double antecedent2)\t{ return (antecedent1 < antecedent2 ? antecedent1 : antecedent2); }\n"; return "double " + toStringCpp() + "(double antecedent1, double antecedent2)\t{ return (antecedent1 < antecedent2 ? antecedent1 : antecedent2); }\n";
} }
@Override
public String toStringJSFunction() {
return "function " + toStringJS() + "(antecedent1, antecedent2) {\n\treturn (antecedent1 < antecedent2 ? antecedent1 : antecedent2);\n}\n";
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
return "AND : MIN;"; return "AND : MIN;";

View File

@ -31,6 +31,11 @@ public class RuleConnectionMethodOrMax extends RuleConnectionMethod {
return "double " + toStringCpp() + "(double antecedent1, double antecedent2)\t{ return (antecedent1 > antecedent2 ? antecedent1 : antecedent2); }\n"; return "double " + toStringCpp() + "(double antecedent1, double antecedent2)\t{ return (antecedent1 > antecedent2 ? antecedent1 : antecedent2); }\n";
} }
@Override
public String toStringJSFunction() {
return "function " + toStringJS() + "(antecedent1, antecedent2) {\n\treturn (antecedent1 > antecedent2 ? antecedent1 : antecedent2);\n}\n";
}
@Override @Override
public String toStringFcl() { public String toStringFcl() {
return "OR: MAX;"; return "OR: MAX;";

View File

@ -1,11 +0,0 @@
package net.sourceforge.jFuzzyLogic.ruleConnectionMethod;
/**
* Author's data
* @author marcin-szczepanski
*/
public class Szczepanski {
public static final String EMAIL = "marcin.szczepanski@amu.edu.pl";
public static final String BY = "Marcin Szczepanski";
}