-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathC_generator.jl
204 lines (182 loc) · 5.83 KB
/
C_generator.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#import all required libraies
import Pkg;
Pkg.add("FuzzyLogic");
Pkg.add("Dictionaries");
using FuzzyLogic
using Dictionaries
import FuzzyLogic: FuzzyOr, FuzzyAnd, FuzzyRelation, FuzzyNegation, FuzzyRule
#=
Fuzzylogic.jl standard format, input parameter for the fuzzylogic system,
Method of calling the function: fis(service=2, food=3)
=#
fis = @sugfis function tipper(service, food)::tip
service := begin
domain = 0:10
poor = GaussianMF(0.0, 1.5)
good = GaussianMF(5.0, 1.5)
excellent = GaussianMF(10.0, 1.5)
end
food := begin
domain = 0:10
rancid = TrapezoidalMF(-2, 0, 1, 3)
delicious = TrapezoidalMF(7, 9, 10, 12)
end
tip := begin
domain = 0:30
cheap = 5.002
average = 15
generous = 2service, 0.5food, 5.0
end
service == poor || food == rancid --> tip == cheap
service == good --> tip == average
service == excellent || food == delicious --> tip == generous
end
# Membership function expression for C code, need to add more
function to_c(mf::GaussianMF)
"""
double GaussianMF(double x, double mean, double sigma) {
return exp(-0.5 * pow((x - mean) / sigma, 2));
}
"""
end
function to_c(mf::TrapezoidalMF)
"""
double TrapezoidalMF(double x, double a, double b, double c, double d) {
if (x <= a || x >= d) return 0.0;
if (x >= b && x <= c) return 1.0;
if (x > a && x < b) return (x - a) / (b - a);
if (x > c && x < d) return (d - x) / (d - c);
return 0.0;
}
"""
end
#Generate membership function which is used in code
function generate_mf_definitions(fis::SugenoFuzzySystem)
visited = DataType[]
res = ""
for (var_name, var) in pairs(fis.inputs)
for (mf_name, mf) in pairs(var.mfs)
if !(typeof(mf) in visited)
res *= to_c(mf) * "\n\n"
push!(visited, typeof(mf))
end
end
end
return res
end
#Generate Fuzzification part
function collect_properties(x)
join([getproperty(x, p) for p in propertynames(x)], ", ")
end
function generate_fuzzification(fis::SugenoFuzzySystem)
res = ""
for (var_name, var) in pairs(fis.inputs)
for (mf_name, mf) in pairs(var.mfs)
line = "\tdouble $(var_name)_$mf_name = $(nameof(typeof(mf)))($var_name, $(collect_properties(mf)));"
res *= line * "\n"
end
end
return res
end
# generate rule evaluation part 1
function generate_rule_expression(r::FuzzyRelation)
prop = r.prop
subj = r.subj
return "$(subj)_$prop"
end
function generate_rule_expression(r::FuzzyAnd)
left = generate_rule_expression(r.left)
right = generate_rule_expression(r.right)
return "fmin($left, $right)"
end
function generate_rule_expression(r::FuzzyOr)
left = generate_rule_expression(r.left)
right = generate_rule_expression(r.right)
return "fmax($left, $right)"
end
function generate_rule_expression(r::FuzzyNegation)
prop = r.prop
subj = r.subj
return "1-$(subj)_$prop"
end
#Generate rule evaluation part 2
function generate_rules(fis::SugenoFuzzySystem)
rules_vector = fis.rules
rules_c_expression = "\n"
for i in eachindex(rules_vector)
rule = rules_vector[i]
ant_return = generate_rule_expression(rule.antecedent)
rules_c_expression *= "\tdouble rule$i = $ant_return;\n"
end
return rules_c_expression * "\n"
end
function generate_rules_consequent(fis::SugenoFuzzySystem)
rules_vector = fis.rules
rules_c_expression = "\n"
for i in eachindex(rules_vector)
rule = rules_vector[i]
cons_return = generate_rule_expression(rule.consequent[1])
rules_c_expression *= "\tdouble r$(i)_out = $cons_return;\n"
end
return rules_c_expression
end
#Generate rule outputs
function generate_rule_expression(r::ConstantSugenoOutput)
return "$(r.c)"
end
function generate_rule_expression(r::LinearSugenoOutput)
rule_out = ""
# combine coefficients and unknowns together to append
rule_out *= join(["$coeff * $var" for (var, coeff) in pairs(r.coeffs)], " + ") *
" + $(r.offset)"
return rule_out
end
function generate_outputs(fis::SugenoFuzzySystem)
rule_out = ""
for (var_name, var) in pairs(fis.outputs)
i = 1
for (mf_name, mf) in pairs(var.mfs)
rule_return = generate_rule_expression(mf)
rule_out *= "\tdouble r$(i)_out = $rule_return;\n"
i = i + 1
end
end
return rule_out * "\n"
end
#Generate Weighted average calculation
function generate_calculation(fis::SugenoFuzzySystem)
calculation = ""
for (var_name, var) in pairs(fis.outputs)
calculation *= "\tdouble numerator = "
calculation *= join(
["(rule$idx * r$(idx)_out)"
for (idx, (mf_name, mf)) in enumerate(pairs(var.mfs))],
" + ")
calculation *= ";\n"
calculation *= "\tdouble denominator = "
calculation *= join(
["rule$idx" for (idx, (mf_name, mf)) in enumerate(pairs(var.mfs))], " + ")
calculation *= ";\n\n"
calculation *= "\treturn numerator / denominator;\n"
end
return calculation * "\n"
end
# main C_generator function
function generate_tip(fis::SugenoFuzzySystem)
res = ""
func_def = generate_mf_definitions(fis)
top_func_param = join(
[string("double ", ele) for ele in collect(keys(fis.inputs))], ", ")
top_func_start = "double $(fis.name)($(top_func_param)){\n"
top_func_body = generate_fuzzification(fis)
rules = generate_rules(fis)
rule_outputs = generate_outputs(fis)
calculation = generate_calculation(fis)
top_func_end = "}"
res = func_def * top_func_start * top_func_body * rules * rule_outputs * calculation *
top_func_end
return res
end
c_code = generate_tip(fis)
print(c_code)
write("c_code.c", c_code)