Skip to content

Commit

Permalink
Gaussian fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Fuminides committed Feb 10, 2025
1 parent 30e2b89 commit 2dc083d
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 19 deletions.
1 change: 1 addition & 0 deletions Demos/demos_module/main_iris_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
# Compute the fuzzy partitions using n linguistic variables
precomputed_partitions_vl = utils.construct_partitions(X, fz_type_studied, n_partitions=vl)


# Split the data into a training set and a test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=0)

Expand Down
57 changes: 51 additions & 6 deletions ex_fuzzy/ex_fuzzy/fuzzy_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,16 @@ def trapezoidal_membership(x: np.array, params: list[float], epsilon=10E-5) -> n



def __gaussian2(x, params: list[float]) -> np.array:
def _gaussian2(x, params: list[float]) -> np.array:
'''
Gaussian membership functions.
:param mean: real number, mean of the gaussian function.
:param amplitude: real number.
:param standard_deviation: std of the gaussian function.
'''
mean, amplitude, standard_deviation = params
return amplitude * np.exp(- ((x - mean) / standard_deviation) ** 2)
mean, standard_deviation = params
return np.exp(- ((x - mean) / standard_deviation) ** 2)


class FS():
Expand Down Expand Up @@ -146,6 +146,15 @@ def __str__(self) -> str:
:return: string.
'''
return f'{self.name} ({self.type().name}) - {self.membership_parameters}'


def shape(self) -> str:
'''
Returns the shape of the fuzzy set.
:return: string.
'''
return 'trapezoid'



Expand Down Expand Up @@ -201,10 +210,20 @@ def __str__(self) -> str:
:return: string.
'''
return f'Categorical set: {self.name}, type 1 output'


def shape(self) -> str:
'''
Returns the shape of the fuzzy set.
:return: string.
'''
return 'categorical'


class IVFS(FS):
'''
Class to define a iv fuzzy set.
'''

Expand Down Expand Up @@ -334,6 +353,14 @@ def __str__(self) -> str:
return f'Categorical set: {self.name}, type 2 output'


def shape(self) -> str:
'''
Returns the shape of the fuzzy set.
:return: string.
'''
return 'categorical'


class GT2(FS):
'''
Expand Down Expand Up @@ -472,8 +499,8 @@ def membership(self, input: np.array) -> np.array:
:param input: input values in the fuzzy set referencial domain.
:return: np array samples x 2
'''
lower = __gaussian2(input, self.secondMF_lower)
upper = __gaussian2(input, self.secondMF_upper)
lower = _gaussian2(input, self.secondMF_lower)
upper = _gaussian2(input, self.secondMF_upper)

return np.array(np.concatenate([lower, upper])).T

Expand All @@ -483,6 +510,15 @@ def type(self) -> FUZZY_SETS:
Returns the type of the fuzzy set. (t1)
'''
return FUZZY_SETS.t2


def shape(self) -> str:
'''
Returns the shape of the fuzzy set.
:return: string.
'''
return 'gaussian'


class gaussianFS(FS):
Expand All @@ -497,14 +533,23 @@ def membership(self, input: np.array) -> np.array:
:param input: input values in the fuzzy set referencial domain.
:return: np array samples
'''
return __gaussian2(input, self.membership_parameters)
return _gaussian2(input, self.membership_parameters)


def type(self) -> FUZZY_SETS:
'''
Returns the type of the fuzzy set. (t1)
'''
return FUZZY_SETS.t1


def shape(self) -> str:
'''
Returns the shape of the fuzzy set.
:return: string.
'''
return 'gaussian'


class fuzzyVariable():
Expand Down
24 changes: 15 additions & 9 deletions ex_fuzzy/ex_fuzzy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,13 @@ def t1_n_gaussian_partition_parameters(x: np.array, n_partitions: int) -> np.arr
for partition in range(n_partitions):
if partition == 0: # First partition
# Center at first interior quantile
partition_parameters[:, partition, 0] = quantile_numbers[1, :] # mean
partition_parameters[:, partition, 0] = quantile_numbers[0, :] # mean
# Spread based on distance to next quantile
partition_parameters[:, partition, 1] = (quantile_numbers[2, :] - quantile_numbers[0, :]) / 2 # std

elif partition == n_partitions - 1: # Last partition
# Center at last interior quantile
partition_parameters[:, partition, 0] = quantile_numbers[-2, :] # mean
partition_parameters[:, partition, 0] = quantile_numbers[-1, :] # mean
# Spread based on distance to previous quantile
partition_parameters[:, partition, 1] = (quantile_numbers[-1, :] - quantile_numbers[-3, :]) / 2 # std

Expand Down Expand Up @@ -390,14 +390,19 @@ def t1_fuzzy_partitions_dataset(x0: np.array, n_partition=3, shape='trapezoid')
elif shape == 'gaussian':
fz_memberships = t1_n_gaussian_partition_parameters(x, n_partitions=n_partition)
else:
raise ValueError('Shape not recognized')
raise ValueError('Shape not recognized, it must be either trapezoid or gaussian')

res = []
for fz_parameter in range(fz_memberships.shape[0]):
fzs = [fs.FS(partition_names[ix], fz_memberships[fz_parameter, ix, :], [
mins[fz_parameter], maxs[fz_parameter]]) for ix in range(fz_memberships.shape[1])]
if shape == 'trapezoid':
fzs = [fs.FS(partition_names[ix], fz_memberships[fz_parameter, ix, :], [
mins[fz_parameter], maxs[fz_parameter]]) for ix in range(fz_memberships.shape[1])]
elif shape == 'gaussian':
fzs = [fs.gaussianFS(partition_names[ix], fz_memberships[fz_parameter, ix, :], [
mins[fz_parameter], maxs[fz_parameter]]) for ix in range(fz_memberships.shape[1])]
res.append(fs.fuzzyVariable(fv_names[fz_parameter], fzs))


return res


Expand Down Expand Up @@ -479,7 +484,7 @@ def gt2_fuzzy_partitions_dataset(x0: np.array, resolution_exp:int=2, n_partition
return res


def construct_partitions(X : np.array, fz_type_studied:fs.FUZZY_SETS=fs.FUZZY_SETS.t1, categorical_mask: np.array=None, n_partitions=3) -> list[fs.fuzzyVariable]:
def construct_partitions(X : np.array, fz_type_studied:fs.FUZZY_SETS=fs.FUZZY_SETS.t1, categorical_mask: np.array=None, n_partitions=3, shape='trapezoid') -> list[fs.fuzzyVariable]:
'''
Returns a list of linguistic variables according to the kind of fuzzy specified.
Expand All @@ -506,12 +511,13 @@ def construct_partitions(X : np.array, fz_type_studied:fs.FUZZY_SETS=fs.FUZZY_SE

if categorical_mask is None or sum(np.logical_not(categorical_mask)) > 0:
if fz_type_studied == fs.FUZZY_SETS.t1:
precomputed_partitions = t1_fuzzy_partitions_dataset(X_numerical, n_partitions)
precomputed_partitions = t1_fuzzy_partitions_dataset(X_numerical, n_partitions, shape)
elif fz_type_studied == fs.FUZZY_SETS.t2:
precomputed_partitions = t2_fuzzy_partitions_dataset(X_numerical, n_partitions)
precomputed_partitions = t2_fuzzy_partitions_dataset(X_numerical, n_partitions, shape)
elif fz_type_studied == fs.FUZZY_SETS.gt2:
precomputed_partitions = gt2_fuzzy_partitions_dataset(X_numerical, n_partitions)
precomputed_partitions = gt2_fuzzy_partitions_dataset(X_numerical, n_partitions, shape)
else:

raise ValueError('Fuzzy set type not recognized')


Expand Down
22 changes: 18 additions & 4 deletions ex_fuzzy/ex_fuzzy/vis_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,19 +245,33 @@ def plot_fuzzy_variable(fuzzy_variable: fs.fuzzyVariable) -> None:
fig = plt.figure()
ax = plt.axes(projection='3d')

memberships = [0, 1, 1, 0]
unit_resolution = 0.01
unit_range_sampled = np.arange(
0, 1 + unit_resolution, unit_resolution)

colors = ['b', 'r', 'g', 'orange', 'purple']
for ix, fuzzy_set in enumerate(fuzzy_variable.linguistic_variables):
name = fuzzy_set.name
initiated = False
fz_studied = fuzzy_set.type()
domain_sampled = unit_range_sampled * (fuzzy_set.domain[1] - fuzzy_set.domain[0]) + fuzzy_set.domain[0]
if fuzzy_set.shape() == 'gaussian':
memberships = fuzzy_set.membership(domain_sampled)
else:
memberships = [0, 1, 1, 0]


if fz_studied == fs.FUZZY_SETS.t1:
try:
ax.plot(fuzzy_set.membership_parameters,
memberships, colors[ix % len(colors)], label=name)
ax.fill_between(fuzzy_set.membership_parameters, memberships, alpha=0.3)
if fuzzy_set.shape() == 'gaussian':
ax.plot(unit_range_sampled,
memberships, colors[ix % len(colors)], label=name)
ax.fill_between(unit_range_sampled, memberships, alpha=0.3)
elif fuzzy_set.shape() == 'trapezoid':
ax.plot(fuzzy_set.membership_parameters,
memberships, colors[ix % len(colors)], label=name)
ax.fill_between(fuzzy_set.membership_parameters, memberships, alpha=0.3)

except AttributeError:
print('Error in the visualization of the fuzzy set: "' + name + '", probably because the fuzzy set is not a trapezoidal fuzzy set.')

Expand Down

0 comments on commit 2dc083d

Please sign in to comment.