# Fuzzy logic functions library with driver code

This file implements functions based on vectors/sets.

FuzzySetLibrary.h

#include <bits/stdc++.h>
using namespace std;

const int MAX_SIZE_ARRAY = 3;

namespace fuzzySet
{
vector<vector<float> > cartesianProduct(vector<float>const & array1, vector<float>const & array2)
{
vector< vector<float> > output(MAX_SIZE_ARRAY);
for (int i = 0; i < MAX_SIZE_ARRAY; ++i)
output[i].resize(MAX_SIZE_ARRAY);

for (int i = 0; i < MAX_SIZE_ARRAY; ++i)
for (int j = 0; j < MAX_SIZE_ARRAY; ++j)
output[i][j] = min(array1[i], array2[j]);

return output;
}

vector<float> fuzzyUnion(vector<float>const & array1, vector<float>const & array2)
{
vector<float> output(MAX_SIZE_ARRAY);
for (int i = 0; i < MAX_SIZE_ARRAY; ++i)
output[i] = max(array1[i], array2[i]);
return output;
}

vector<float> fuzzyIntersection(vector<float>const & array1, vector<float>const & array2)
{
vector<float> output(MAX_SIZE_ARRAY);
for (int i = 0; i < MAX_SIZE_ARRAY; ++i)
output[i] = min(array1[i], array2[i]);
return output;
}

vector<float> fuzzyComplement(vector<float>const & array)
{
vector<float> output(MAX_SIZE_ARRAY);
for (int i = 0; i < MAX_SIZE_ARRAY; ++i)
output[i] = 1 - array[i];
return output;
}

void display(vector<float> const & array)
{
for (int i = 0; i < MAX_SIZE_ARRAY; ++i)
cout<<array[i]<<" ";

cout<<"\n\n";
}

}


This library implements all the fuzzy functions that can be performed on fuzzy relations and matrices.

MatrixLibrary.h

#include <bits/stdc++.h>
using namespace std;

const int MAX_SIZE_MATRIX = 3;

namespace matrix
{
vector<vector<float> > fuzzyUnion(vector<vector<float> > const & matrix1, vector< vector<float> > const & matrix2)
{
vector< vector<float> > output(matrix1.size());

for (int i = 0; i < output.size(); ++i)
output[i].resize(output.size());

for (int i = 0; i < matrix1.size(); ++i)
for (int j = 0; j < matrix1[i].size(); ++j)
output[i][j] = max(matrix1[i][j], matrix2[i][j]);

return output;
}

vector<vector<float> > fuzzyIntersection(vector<vector<float> > const & matrix1, vector< vector<float> > const & matrix2)
{
vector< vector<float> > output(matrix1.size());

for (int i = 0; i < output.size(); ++i)
output[i].resize(output.size());

for (int i = 0; i < matrix1.size(); ++i)
for (int j = 0; j < matrix1[i].size(); ++j)
output[i][j] = min(matrix1[i][j], matrix2[i][j]);

return output;
}

vector<vector<float> > fuzzyComplement(vector<vector<float> > const & matrix1)
{
vector< vector<float> > output(matrix1.size());
for (int i = 0; i < MAX_SIZE_MATRIX; ++i)
output[i].resize(MAX_SIZE_MATRIX);

for (int i = 0; i < matrix1.size(); ++i)
for (int j = 0; j < matrix1[i].size(); ++j)
output[i][j] = 1 - matrix1[i][j];

return output;
}

vector< vector<float> > fuzzyComposition(vector<vector<float> >const & matrix1, vector<vector<float> >const & matrix2, int type)
{
vector< vector<float> > output(MAX_SIZE_MATRIX);
for (int i = 0; i < MAX_SIZE_MATRIX; ++i)
output[i].resize(MAX_SIZE_MATRIX);

for (int i = 0; i < MAX_SIZE_MATRIX; ++i)
{
for (int j = 0; j < MAX_SIZE_MATRIX; ++j)
{
float maxValue = 0.0;
float minValue = 1.1;
for (int k = 0; k < MAX_SIZE_MATRIX; ++k)
{
if(type == 0) // MaxMin Composition
{
float val = min(matrix1[i][k], matrix2[k][j]);
if(val > maxValue) maxValue = val;
}
else if(type == 1) // MinMax Composition
{
float val = max(matrix1[i][k], matrix2[k][j]);
if(val < minValue) minValue = val;
}
else if(type == 2) // MaxAverage Composition
{
float val = (matrix1[i][k] + matrix2[k][j])/2.0;
if(val > maxValue) maxValue = val;
}
else if(type == 3) // MinAverage Composition
{
float val = (matrix1[i][k] + matrix2[k][j])/2.0;
if(val < minValue) minValue = val;
}
}
if(type == 0 || type == 2) output[i][j] = maxValue;
else if(type == 1 || type == 3) output[i][j] = minValue;
}
}
return output;
}

void display(vector<vector<float> > const & matrix)
{
for(int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; ++j)
cout<<matrix[i][j]<<" ";
cout<<"\n";
}
cout<<"\n";
}

}


Main driver code that actually uses the aforementioned libraries and performs functions and displays the results.

Main.cpp

#include <bits/stdc++.h>
#include "MatrixLibrary.h"
#include "FuzzySetLibrary.h"
using namespace std;

int main()
{
srand(time(NULL));
std::cout << std::setprecision(1) << std::fixed;
vector< vector<float> > input1(MAX_SIZE_MATRIX);
vector< vector<float> > input2(MAX_SIZE_MATRIX);
vector<float> arrayInput1(MAX_SIZE_ARRAY);
vector<float> arrayInput2(MAX_SIZE_ARRAY);
vector< vector<float> > unionOutput(MAX_SIZE_MATRIX),
interOutput(MAX_SIZE_MATRIX), compleOutput(MAX_SIZE_MATRIX), maxMinOutput(MAX_SIZE_MATRIX),
cartesianOutput(MAX_SIZE_MATRIX);
for (int i = 0; i < MAX_SIZE_MATRIX; ++i)
{
input1[i].resize(MAX_SIZE_MATRIX);
input2[i].resize(MAX_SIZE_MATRIX);
unionOutput[i].resize(MAX_SIZE_MATRIX);
interOutput[i].resize(MAX_SIZE_MATRIX);
compleOutput[i].resize(MAX_SIZE_MATRIX);
maxMinOutput[i].resize(MAX_SIZE_MATRIX);
cartesianOutput[i].resize(MAX_SIZE_MATRIX);
}

for(int i = 0; i < MAX_SIZE_MATRIX; i++)
{
arrayInput1[i] = (rand()%10)*0.1;
arrayInput2[i] = (rand()%10)*0.1;

for (int j = 0; j < MAX_SIZE_MATRIX; ++j)
{
input1[i][j] = (rand()%10)*0.1;
input2[i][j] = (rand()%10)*0.1;
}
}

unionOutput = matrix::fuzzyUnion(input1, input2);
interOutput = matrix::fuzzyIntersection(input1, input2);
compleOutput = matrix::fuzzyComplement(input1);
maxMinOutput = matrix::fuzzyComposition(input1, input2, 0);
cartesianOutput = fuzzySet::cartesianProduct(arrayInput1, arrayInput2);

matrix::display(input1);
matrix::display(input2);

fuzzySet::display(arrayInput1);
fuzzySet::display(arrayInput2);
matrix::display(unionOutput);
matrix::display(interOutput);
matrix::display(compleOutput);
matrix::display(maxMinOutput);
matrix::display(cartesianOutput);
return 0;
}


I would like to know if my code writing style is good and is it professional grade or it still looks like some newbie wrote it. Any improvements regarding the style of function declarations, variable usage or function usage, constant usage.

And please let me know how can I actually improve logic and make code more readable and have better control over the overall structure.

• I can see that this implements "functions based on vectors/sets", but it's hard to review if I don't understand what those functions are for. I find the names aren't descriptive enough on their own, and the test program doesn't really elucidate the intent either. Would you be able to edit your description to help us understand the purpose? Thanks. Jun 16 '17 at 14:09

<bits/stdc++.h> isn't in any standard; even on those platforms where it exists, it's probably a poor choice if it includes the whole of the Standard Library. Instead, include (only) the standard library headers that declare the types that are required for the header.

# Avoid using namespace in headers

A header file should provide the definitions that the including program requires. If it brings all of std into the global namespace, that's a far-reaching side-effect that can make correct programs much harder to write.

Although there are differing opinions, I would extend this advice to program files too.

# Namespace hygiene

The constants MAX_SIZE_ARRAY and MAX_SIZE_MATRIX would be better within their respective namespaces, rather than in the global namespace. I'm not entirely sure why we have those fixed limits at all, but that may be because I don't understand the real-world problem this code attempts to solve.

# Interface design

Is there a strong reason that std::vector should be the only supported container? And that float should be the only supported element type?

If not, then it's likely that the methods should be templated on those types. You may want to encapsulate the data type and methods into a class; alternatively (if you want to be more general), you might want to keep the procedural interface, but pass appropriate input and output iterators rather than containers.

# Options to reduce duplication

Much of the matrix implementation is repeated application of the list implementation over the rows of the matrix. I think there's scope to simply call the list methods from within the matrix ones. It may well be worth moving the definitions out from the headers, leaving only the declarations in the headers (as usual for non-template code).

# Allow output to any stream

Instead of embedding the use of std::cout in display(), it's better to pass a std::ostream as parameter, to allow output where it's needed (e.g. standard error, file or socket).

If you create a class (or pair of classes), you'll probably want to write a stream operator:

std::ostream& operator<<() const

• Thank you that's really helpful. I will try to keep these things in mind and improve over this. And I fixed most of the errors mentioned here using Google CPPLINT python program but apart from that everything you mentioned is pure gem. Thanks. Jun 19 '17 at 14:04

first thing first, do not use using namespace std; This i a bad practice that will hurt you eventually due to namespace collisions/pollution.

You might want to have a look at std::transfrom especially its binary form.

That way you can for example write

vector<vector<float> > cartesianProduct(vector<float>const & array1, vector<float>const & array2)
{
vector< vector<float> > output(MAX_SIZE_ARRAY, std::vector<float>(MAX_SIZE_ARRAY));

std::transfrom(array1.begin(), array1.end(), array2.begin(),
[](const float& a, const float& b) { return std::min(a,b);});
return output;
}


The same applies for the other algorithms