=20]rgb0.95,0.97,1 0.2em20pt0.2em0.8pt4pt

# A Python Framework for Neutrosophic Sets and Mappings

Giorgio Nordo1,∗, Saeid Jafari2, Arif Mehmood3 and Bhimraj Basumatary4
1MIFT Department – Mathematical and Computer Science, Physical Sciences and
Earth Sciences
University of Messina, 98166 Sant’Agata, Messina, Italy;
<EMAIL_ADDRESS>
2Mathematical and Physical Science Foundation, 4200 Slagelse, Denmark;
<EMAIL_ADDRESS>
3Department of Mathematics, Institute of Numerical Sciences, Gomal University,
Dera Ismail Khan 29050, KPK, Pakistan<EMAIL_ADDRESS>
4Department of Mathematical Sciences, Bodoland University, Kokrajhar, BTAD,
India<EMAIL_ADDRESS>
∗Correspondence<EMAIL_ADDRESS>G., Jafari S., Mehmood A.,
Basumatary B., A Python Framework for Neutrosophic Sets and Mappings

###### Abstract.

In this paper we present an open source framework developed in Python and
consisting of three distinct classes designed to manipulate in a simple and
intuitive way both symbolic representations of neutrosophic sets over
universes of various types as well as mappings between them. The capabilities
offered by this framework extend and generalize previous attempts to provide
software solutions to the manipulation of neutrosophic sets such as those
proposed by Salama et al. [21], Saranya et al. [23], El-Ghareeb [7], Topal et
al. [29] and Sleem [26]. The code is described in detail and many examples and
use cases are also provided.
Keywords: neutrosophic set; neutrosophic mapping; Python; class; framework.
—————————————————————————————————————————–

##  1\. Introduction

Since the notion of neutrosophic set was introduced in 1999 by Smarandache
[27] as a generalization of both the notions of fuzzy set introduced by
Zadeh[31] in 1965 and intuitionistic fuzzy set proposed by Atanassov [4] in
1983, neutrosophic set theory had a rapid development and has been profitably
used in many fields of pure Mathematics [1, 12, 13, 15, 16] as well as in
several areas of applied sciences such as Graph Theory [5], Decision Making
[14], Medicine [6], Statistics [28, 10, 24], Image Analysis [9, 32] Machine
Learning [8, 25], etc.

In numerous instances, especially when dealing with applications stemming from
real-world issues, manually manipulating neutrosophic sets that possess a
finite yet consistent number of elements, along with their associated
mappings, can be quite laborious and challenging. Consequently, there exists a
significant demand for a system that can streamline the automation of key
neutrosophic operations, including union, intersection, neutrosophic
difference, and the calculation of neutrosophic images or counterimages by
mappings. Previous attempts to address this need were undertaken by Salama et
al., who initially employed tools like Microsoft Excel [20] and later
transitioned to using C# [21]. Another software application for processing
neutrosophic sets developed in C# was described by Saranya et al. [23]. More
recently, El-Ghareeb introduced a Python package designed to handle both
single and interval-valued neutrosophic numbers and sets [7]. Unfortunately,
however, in the latter paper the two classes concerning neutrosophic sets are
described incompletely and summarily than those concerning neutrosophic
numbers. Version 0.0.5 of this software that we consulted does not appear to
provide adequate functionality even for the main neutrosophic operations and
in any case the related repository on GitHub of the source code mentioned in
the article does not appear to be available. Furthermore, other Python-based
software solutions for handling neutrosophic numbers and matrices have been
proposed by Topal et al. [29] and Sleem [26]. However, the authors are not
aware of any other Python software specifically designed for the manipulation
of neutrosophic sets is currently known.

This underscores the ongoing requirement for a set of well-structured Python
classes, ideally available under an Open Source license, that enable automated
and interactive manipulation of symbolic representations of neutrosophic sets,
along with their associated mappings. Additionally, there is a need for
comprehensive documentation and user-friendly design to facilitate
straightforward integration for future implementations.

For this reason, we intended to design and develop a modern framework that
extends and generalizes the above software solutions overcoming some of their
limitations and offering greater flexibility in their use, including
interactive, aimed at the manipulation of neutrosophic sets and functions. The
structure of the entire framework has been carefully described by means of of
Unified Modeling Language (UML for short), a modeling and specification
description language very popular in Software Engineering. The underlying
given structures as well as the most significant methods of each of the
classes of which the the framework have been explained in detail in order to
allow for further future refinements of both a theoretical and applicative
nature.

We are confident that the necessity mentioned has been effectively tackled
through the Python framework outlined in this paper. The complete source code
for this framework has been released under the Open Source GNU General Public
License version 3.0 (or GPL-3.0) and is freely accessible at the url
github.com/giorgionordo/pythonNeutrosophicSets.

In particular, Section 2 describes the general structure of the framework, the
dependency relationships among the various classes that comprise it as well as
the reasons that suggested the use of the Puython language and the decision to
release the entire code produced under an Open Source license.

Section 3 introduces some useful notations for extending some data structures
typical of Python in order to create a flexible substandard for describing
neutrosophic sets and functions between them. In addition, some utility
functions are briefly called that later will be invoked by some classes in the
framework.

Section 4 contains a description of the properties and methods of the class
NSuniverse used to represent the universe sets on which the neutrosophic sets
will be defined.

Section 5 describes in great detail the properties and methods that make up
the NSset class, the main class of the framework, used for the representation
of neutrosophic sets and, in addition, numerous examples of practical use are
also provided both in both traditional and interactive environments.

Section 6 is devoted to the description of the class NSmapping by which
functions between two neutrosophic sets are represented. The properties and
methods of this class are described in detail and illustrated with several
practical examples.

Finally, some final remarks are made in Section 7, highlighting the strengths
of the framework presented in this paper and inviting other researchers to
continue, extend and improve the development of the code described here.

##  2\. The framework PYNS

The PYthon Neutrosophic Sets framework (PYNS for short) described in the
present paper consists of three classes designed to manage respectively
universe sets (the NSuniverse class), neutrosophic sets (the NSset class) and
functions between them (the NSmapping class. As is natural, the class NSset
depends on (i.e. uses) the class NSuniverse class) while the NSmapping class
uses the other two as described in the following UML diagram of classes.

where the dashed arrow means ”uses”.

These three classes are respectively contained in the Python files
ns_universe.py, ns_set.py and ns_mapping.py which are located in the package
directory pyns. The same directory contains also the file ns_util.py where are
defined some utility functions external to the classes but employed by them.
The structure of the package is described by the following diagram.

.1 /pyns. .2 ns_universe.py(contains the NSuniverse class). .2
ns_set.py(contains the NSset class). .2 ns_mapping.py(contains the NSmapping
class). .2 ns_util.py(contains common utility functions).

The choice of programming language is a crucial aspect in the development of a
scientific framework, since it determines the performance, flexibility and
ease of use of the entire system. In the specific case of our framework, the
choice to implement it using the Python language is based on several factors:

  * •

Clear and expressive syntax: Python is known for its simple and readable
syntax, which makes the code more intuitive to write and understand. This
feature is especially relevant for a scientific framework, as it facilitates
the creation and manipulation of complex data structures such as neutrosophic
sets and mappings between them.

  * •

Extensive standard library: Python offers an extensive standard library
covering multiple scientific and mathematical domains. This allows developers
to easily use existing functions and tools to implement complex algorithms and
optimize the performance of the framework.

  * •

Easy integration with other technologies: Python is known for its ability to
integrate with other programming languages and external libraries. This is
particularly useful in a scientific context, where it may be necessary to use
specialized libraries or existing computational tools.

  * •

Quick learning: Python is often considered one of the most accessible
languages even for programming novices. Its relatively smooth learning curve
allows students, researchers and less experienced developers to tackle the
framework with greater ease, thus encouraging its dissemination and adoption
in the scientific domain.

In summary, the choice of Python as the main language for the PYNS framework
was crucial in making the entire system more accessible, flexible, and
powerful. It allowed developers to focus more on scientific challenges and
mathematics specifics, rather than the complexities of the programming
language, thus accelerating the development and adoption of this important
research tool.

Just as the Python language is released under an open source license approved
by the Open Source Initiative (OSI), the framework described in this paper is
also made available as open code. This offers numerous benefits and incentives
for both developers and the scientific community as a whole, including:

  * •

Knowledge sharing: The release of the framework under an open source license
promotes the sharing of knowledge and scientific discoveries. By allowing
anyone to access the source code, developers and researchers can learn from
others, build on others’ work, and contribute improvements and new ideas.

  * •

Collaboration: The open source license encourages collaboration among experts
and researchers from from different academic institutions, organizations and
countries. This synergy can lead to faster developments, new discoveries, and
innovative solutions to complex problems.

  * •

Transparency and verifiability: The availability of source code allows for
greater transparency in the implementation of the framework. The scientific
community can verify and validate the results obtained, increasing confidence
towards the framework and the results obtained through it.

  * •

Adaptability and customization: Users can adapt the framework to their own
specifics and customize it to address unique problems. This flexibility
results in a greater number of possible applications and uses of the framework
in various scientific contexts.

  * •

Cost reduction: Releasing the framework as open source eliminates the costs
associated of purchasing licenses or copyrights. This allows academic
institutions and organizations with limited resources to free access to
advanced scientific analysis tools and uncertain data.

  * •

Community growth: The adoption of the open source license attracts a community
of developers, researchers and enthusiasts interested in the field of
neutrosophic sets that can contribute to the evolution of the framework by
providing feedback, reporting bugs, and participating in the development of
new features.

  * •

Continuity and longevity: The open source model can ensure greater longevity
of the framework, as it is not dependent on a single developer or institution.
The community can take care of the project over time, ensuring that it is
always updated and supported, even if there are changes in the original
organization.

In particular, our framework PYNS is available under GNU General Public
License version 3.0 (or GPL-3.0), a generic software license developed by the
Free Software Foundation (FSF) that provides users with a set of rights and
freedoms to use, modify, and distribute the software covered by the license.
More specifically, GPL-3.0 allows:

  * •

Freedom of Use: the software may be used for any purpose, whether personal or
commercial.

  * •

Freedom to Study and Modify: you can analyze and study the source code of the
software to understand how it works and make changes to it according to your
own needs.

  * •

Freedom of Distribution: you can distribute copies of modified or unmodified
software to anyone, while complying with the requirements of GPL-3.0.

  * •

Sharing of Changes: if you distribute modified software, you have an
obligation to make available the source code of your changes as well.

  * •

Compatibility with Derivative Works (copyleft): any derivative work based on
software covered by GPL-3.0 must also be released under GPL-3.0 or a
compatible license.

In conclusion, from the evaluation of all these aspects, it follows that
releasing the PYNSframework under GPL-3.0 license represents a strategic
choice that promotes innovation, collaboration and the dissemination of
knowledge in the field of neutrosophic theory, thus promoting the advancement
of scientific research in this area.

##  3\. Conventions and utility functions

In the following we will make extensive use of Python’s dict (dictionary) data
structure both for the internal representation of neutrosophic sets and for
the definition of functions between universe sets. To make it even easier and
more streamlined to use such structures both in interactive mode as well as in
writing client code based on such classes, it was chosen to also allow their
representation as a string and in free format, i.e., leaving the user free to:

  * •

indifferently use not only the usual symbol : (colon) but also alternatively
the strings -> (arrow) and |-> (maps-to) as separators between keys and values

  * •

indifferently use not only the usual symbol , (comma) but also ; (semicolon)
as separators of the value-key pairs

in any combination thereof, and we will refer to this type of representation
by the name extended dictionary. In other words, while a classical Python
dictionary has a form like:

$\left\\{\textit{key}_{1}:\textit{value}_{1},\textit{key}_{2}:\textit{value}_{2},\ldots\textit{key}_{n}:\textit{value}_{n}\right\\}\,,$

an extended dictionary can be expressed as strings of the type:

$\texttt{"}\textit{key}_{1}\texttt{->}\textit{value}_{1}\texttt{,}\textit{key}_{2}\texttt{|->}\textit{value}_{2}\texttt{;}\ldots\textit{key}_{n}\texttt{->}\textit{value}_{n}\texttt{"}\,.$

The already mentioned file NS_util.py contains some general utility functions
that will be used repeatedly in the classes we will describe later. More
specifically, these functions are:

  * •

NSreplace(text, sostituz) which performs a series of substitutions on the
string text by replacing each key in the sostituz dictionary with its
corresponding value; in particular, if that value is the null string "" the
effect will be to remove all occurrences of the key,

  * •

NSstringToTriplesList(text) which converts the string text containing a list
of triples into the corresponding data structure by using the function findall
contained in the module re (regular expression) and the function literal_eval
contained in the module ast (Abstract Syntax Trees) which allows interpreting
data expressions contained in a string,

  * •

NSisExtDict(obj) that checks whether the object obj passed as parameter is a
string representing an extended dictionary and returns the Boolean value True
if it is,

  * •

NSstringToDict(text) which converts the string text containing an extended
dictionary in a real Python dictionary,

  * •

NSsplitText(text, max_length) which returns the string text splitted into
multiple lines of length not exceeding the value max_length.

The complete code for these functions is given in the following listing.

⬇

1from re import findall

2from ast import literal_eval

4def NSreplace(text, sostituz):

5 for k in sostituz:

6 text = text.replace(k, sostituz[k])

7 return text

9def NSstringToTriplesList(text):

10 pattern = r’\\[.*?\\]|\\(.*?\\)’

11 str_list = findall(pattern, text)

12 tpl_list = [tuple(literal_eval(s)) for s in str_list]

13 return tpl_list

15def NSisExtDict(obj):

16 result = False

17 if type(obj) == str:

18 result = (":" in obj) or ("->" in obj)

20def NSstringToDict(text):

21 sostituz = {"’": "", ’"’: "", "(": "", ")": "", "[": "", "]": "",

22 "{": "", "}": "", " ": ",", ";": ",", ",,": ",",

23 "|->": ":", "->": ’:’}

24 text = NSreplace(text, sostituz)

25 listcouples = text.split(’,’)

26 diz = dict()

27 for couple in listcouples:

28 key, value = couple.split(’:’)

29 diz[key] = value

30 return diz

32def NSsplitText(text, max_length):

33 words = text.split()

34 lines = []

35 current_line = ""

36 for word in words:

37 if len(current_line) + len(word) <= max_length:

38 current_line += word + " "

39 else:

40 lines.append(current_line.strip())

41 current_line = word + " "

42 lines.append(current_line.strip())

43 result = "\n".join(lines)

44 return result

##  4\. The NSuniverse class

The universe set is the fundamental notion on which the definition of a
neutrosophic set is founded on. We have chosen to represent it by means of a
list of strings.
The corresponding class which implements such a notion is shortly described in
the following UML class diagram.

$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$==$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$!=$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$

In order to ensure maximum usability and versatility in the use of this class,
the constructor method accepts string, lists, tuples, lists of elements of any
length or another object NSuniverse and proceeds to transform them into
strings and store them in a list. The basic steps of this method, expressed in
pseudo-code, are described in the following algorithm.

Function  _$\\_\hskip 0.2pt\\_$ init$\\_\hskip 0.2pt\\_$(_args_)_:

Get the length of args

if  _length $=0$_ then

Raise an Exception

else if  _length $=1$_ then

if  _args is a list, a tuple or an object of the class_ then

Converts args appropriately and stores it in universe

else if  _args is a string_ then

Removes parentheses, commas and semicolons from args, splits and gets a list
of strings to store in universe

else if  _args is a set_ then

Raise an Exception

else

Converts args to string and creates a list with only this element to be stored
in universe

else

Converts args to a list of strings to be stored in universe

if  _universe has repeated elements_ then

Raise an Exception

Stores universe in the property $\\_\hskip 0.2pt\\_$universe

Algorithm 1 Constructor method of the class NSuniverse

The corresponding Python code of the constructor method of the NSuniverse
class is given below.

⬇

1from .ns_util import NSreplace

3class NSuniverse:

5 def $\\_\hskip 0.2pt\\_$init$\dunder$(self, *args):

6 universe = list()

7 length = len(args)

8 if length == 0:

9 raise IndexError("the universe set must contain at least an element")

10 elif length == 1:

11 elem = args[0]

12 if type(elem) in [list, tuple]:

13 universe = [str(e) for e in elem]

14 elif type(elem) == NSuniverse:

15 universe = elem.get()

16 elif type(elem) == str:

17 sostituz = { "{":"", "}":"", "[":"", "]":"", "(":"", ")":"",

18 ",":" ", ";":" " }

19 universe = NSreplace(elem, sostituz).split()

20 elif type(elem) == set:

21 raise ValueError("type set is not suitable because the elements of the
universe set must be assigned in a specific order")

22 else:

23 universe = [str(elem)]

24 else:

25 for i in range(length):

26 universe.append(str(args[i]))

27 univset = set(universe)

28 if len(universe) != len(univset):

29 raise ValueError("the universe set cannot contain repeated elements")

30 self.$\\_\hskip 0.2pt\\_$universe = universe

The constructor method also intercepts potential error situations in the
definition of universe sets such as attempting to define an empty set by
calling it without any parameters or that of inserting repeated elements
(which conflicts with the usual set definition) and in each of these cases
raises an appropriate exception.

Let us observe that the flexibliity of the constructor method allows us to
define a universe set using various formats such as lists, tuples, strings, or
simple enumerations of elements without worrying about maintaining a rigid or
uniform notation, which is particularly useful to facilitate usability in
interactive use. For example, the universe set $\mathbbmss{U}=\\{1,2,3,4,5\\}$
can be defined as an object of the class NSuniverse in any of the following
ways mutually equivalent:

  * •

U=NSuniverse([1,2,3,4,5]) as a list,

  * •

U=NSuniverse((1,2,3,4,5)) as a tuple,

  * •

U=NSuniverse("1,2,3,4,5") as a string of elements comma separated,

  * •

U=NSuniverse("1;2;3;4;5") as a string of elements separated by semicolon,

  * •

U=NSuniverse("1 2 3 4 5") as a string of elements separated by spaces,

  * •

U=NSuniverse("1,2 3 4;5") as a string of elements separated in various ways,

  * •

U=NSuniverse("{1,2,3,4,5}") as a string representing a set,

  * •

U=NSuniverse("[1,2,3,4,5]") as a string representing a list,

  * •

U=NSuniverse("(1,2,3,4,5)") as a string representing a tuple,

  * •

U=NSuniverse("(1;2;3;4;5)") using semicolon as separator,

  * •

U=NSuniverse(1,2,3,4,5) as a listing of numerical values only,

  * •

U=NSuniverse("1",2,"3",4,"5") in a mixed form,

as well as in different combinations of them.
However, it is not allowed to define a universe set by means of the set type
of the Python language (i.e., expressions such as NSuniverse({1,2,3,4,5}) are
not accepted) since it is an unordered data collection and for a precise
design choice the elements must be listed in a specific order, feature this
will prove valuable in simplifying and making consistent definitions of both
neutrosophic sets and mappings between them.

The class NSuniverse is equipped with very few basic methods, that is get()
which returns the list of strings corresponding to the instance of the
universe set exactly as it is stored internally in the class and cardinality()
which returns the number of elements present in the object instantiated by the
class.

⬇

1 def get(self):

2 return self.$\\_\hskip 0.2pt\\_$universe

4 def cardinality(self):

5 return len(self.$\\_\hskip 0.2pt\\_$universe)

The method isSubset() checks whether the current universe set is contained in
a second universe set passed as parameter and returns the Boolean value True
in the positive case.

⬇

1 def isSubset(self, unv):

2 setself = set(self.get())

3 setunv = set(unv.get())

4 result = setself.issubset(setunv)

5 return result

To facilitate the comparison of two objects of type NSuniverse, the equality
== and diversity != operators have been overloaded using their corresponding
special methods.

⬇

1 def $\\_\hskip 0.2pt\\_$eq$\dunder$(self, unv):

2 equal = (self.get() == unv.get())

3 return equal

5 def $\\_\hskip 0.2pt\\_$ne$\dunder$(self, unv):

6 different = not (self == unv)

7 return different

In order to be able to easily print on the screen objects of type NSuniverse
in text format and to provide a complete representation of them, the special
methods $\\_\hskip 0.2pt\\_$str$\\_\hskip 0.2pt\\_$() and $\\_\hskip
0.2pt\\_$repr$\\_\hskip 0.2pt\\_$() were defined as follows by using the
overloading.

⬇

1 def $\\_\hskip 0.2pt\\_$str$\dunder$(self):

2 list_string_elements = [str(e) for e in self.$\\_\hskip 0.2pt\\_$universe]

3 s = "{ " + ", ".join(list_string_elements) + " }"

4 return s

6 def $\\_\hskip 0.2pt\\_$repr$\dunder$(self):

7 return f"Universe set: {str(self)}"

As an example, we show how the methods and operators described above can be
used not only in a client code, but also in the interactive mode by means of
the Python console:

⬇

>>> from pyns.ns_universe import NSuniverse

>>> U = NSuniverse("1", 2, 3, "4")

>>> print(U)

{ 1, 2, 3, 4 }

>>> print( U != NSuniverse([1,3,5]))

True

>>> V = NSuniverse(" ( a b c , d ; e )")

>>> print(V.cardinality())

5

>>> print(V.get())

[’a’, ’b’, ’c’, ’d’, ’e’]

>>> print(V)

{ a, b, c, d, e }

Since in the following we will also need to make formatted prints of objects
of the universe set type according to a certain format specifier, it is also
necessary to redefine by overloading the special method $\\_\hskip
0.2pt\\_$format$\\_\hskip 0.2pt\\_$().

⬇

1 def $\\_\hskip 0.2pt\\_$format$\dunder$(self, spec):

2 unvstr = str(self)

3 result = f"{unvstr:{spec}}"

4 return result

Finally, to simplify the code of other classes devoted to neutrosophic sets
and mappings, it is useful to establish an iterator over the objects of the
NSuniverse class. This iterator should sequentially provide all and only the
elements within a given universe set. This is achieved by introducing a new
property, $self.$$\\_\hskip 0.2pt\\_$$i$, to serve as the internal index for
the current element and redefining by overloading the special methods
$\\_\hskip 0.2pt\\_$iter$\\_\hskip 0.2pt\\_$() and $\\_\hskip
0.2pt\\_$next$\\_\hskip 0.2pt\\_$() which are respectively intended to
initialize the index of the iterator and yield the element associated with the
current index.

⬇

1 def $\\_\hskip 0.2pt\\_$iter$\dunder$(self):

2 self.$\\_\hskip 0.2pt\\_$i = 0

3 return self

5 def $\\_\hskip 0.2pt\\_$next$\dunder$(self):

6 if self.$\\_\hskip 0.2pt\\_$i < len(self.$\\_\hskip 0.2pt\\_$universe):

7 elem = self.$\\_\hskip 0.2pt\\_$universe[self.$\\_\hskip 0.2pt\\_$i]

8 self.$\\_\hskip 0.2pt\\_$i +=1

9 return elem

10 raise StopIteration

Thanks to the introduction of the iterator on the class NSuniverse it will be,
for example, possible to handle loops directly on objects of type universe
set, exactly as happens with other standard Python types such as lists and
tuples. This approach will contribute to make the syntax of our code leaner
and more understandable, as highlighted in the following example.

⬇

1from pyns.ns_universe import NSuniverse

3U = NSuniverse(" ( a b c , d ; e )")

4for i, u in enumerate(U):

5 print(f"- the {i}-th element is {u}")

which produces output of the type:

⬇

- the 0-th element is a

- the 1-th element is b

- the 2-th element is c

- the 3-th element is d

- the 4-th element is e

##  5\. The NSset class

The representation of neutrosophic sets on a given universe set is done by
means of the NSset class which, obviously, uses the NSuniverse class.

The original definition of neutrosophic set, given in 1999 by Smarandache
[27], refers to the interval $]0^{-},1^{+}[$ of the nonstandard real numbers
and although it is consistent from a philosophical point of view,
unfortunately, it is not suitable to be used for approaching real-world
problems. For such a reason, in 2010, the same author, jointly with Wang,
Zhang and Sunderraman [30], also introduced the notion of single valued
neutrosophic set which, referring instead to the unit interval $[0,1]$ of the
usual set of real numbers $\mathbb{R}$, can be usefully used in scientific and
engineering applications. In the following we will refer exclusively to single
valued neutrosophic sets.

######  Definition 5.1.

[30] Let $\mathbbmss{U}$ be an universe set and $A\subseteq\mathbbmss{U}$, a
single valued neutrosophic set over $\mathbbmss{U}$ (SVN-set for short),
denoted by
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$,
is a set of the form:

$\widetilde{A}=\left\\{\left(u,\mu_{A}\left(u\right),\sigma_{A}\left(u\right),\omega_{A}\left(u\right)\right):\,u\in\mathbbmss{U}\right\\}$

where $\mu_{A}:\mathbbmss{U}\to I$, $\sigma_{A}:\mathbbmss{U}\to I$ and
$\omega_{A}:\mathbbmss{U}\to I$ are the membership function, the indeterminacy
function and the non-membership function of $A$, respectively and $I=[0,1]$ be
the unit interval of the real numbers. For every $u\in\mathbbmss{U}$,
$\mu_{A}\left(u\right)$, $\sigma_{A}\left(u\right)$ and
$\omega_{A}\left(u\right)$ are said the degree of membership, the degree of
indeterminacy and the degree of non-membership of $u$, respectively.

######  Definition 5.2.

[27, 30] Let
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$
and
$\widetilde{B}=\left\langle\mathbbmss{U},\mu_{B},\sigma_{B},\omega_{B}\right\rangle$
be two SVN-sets over the universe set $\mathbbmss{U}$, we say that
$\widetilde{A}$ is a neutrosophic subset (or simply a subset) of
$\widetilde{B}$ and we write $\widetilde{A}\mathrel{\ooalign{\raise
0.86108pt\hbox{$\Subset$}\cr\raise-1.07639pt\hbox{\rule[0.0pt]{5.6pt}{0.4pt}}\cr}}\widetilde{B}$
if, for every $u\in\mathbbmss{U}$, it results
$\mu_{A}\left(u\right)\leq\mu_{B}\left(u\right)$,
$\sigma_{A}\left(u\right)\leq\sigma_{B}\left(u\right)$ and
$\omega_{A}\left(u\right)\geq\omega_{B}\left(u\right)$. We also say that
$\widetilde{A}$ is contained in $\widetilde{B}$ or that $\widetilde{B}$
contains $\widetilde{A}$ and we write $\widetilde{B}\mathrel{\ooalign{\raise
0.86108pt\hbox{$\Supset$}\cr\raise-1.07639pt\hbox{\rule[0.0pt]{5.6pt}{0.4pt}}\cr}}\widetilde{A}$
to denote that $\widetilde{B}$ is a neutrosophic superset of $\widetilde{A}$.

######  Definition 5.3.

[27, 30] Let
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$
and
$\widetilde{B}=\left\langle\mathbbmss{U},\mu_{B},\sigma_{B},\omega_{B}\right\rangle$
be two SVN-sets over the universe set $\mathbbmss{U}$. We say that
$\widetilde{A}$ is a neutrosophically equal (or simply equal) to
$\widetilde{B}$ and we write $\widetilde{A}\mathrel{\ooalign{\raise
0.43057pt\hbox{$=$}\cr\hskip 0.6pt\raise
0.86108pt\hbox{\rule{6.6pt}{0.35pt}}\cr\raise
4.52083pt\hbox{{\rule{6.6pt}{0.32pt}}}\cr}}\widetilde{B}$ if
$\widetilde{A}\mathrel{\ooalign{\raise
0.86108pt\hbox{$\Subset$}\cr\raise-1.07639pt\hbox{\rule[0.0pt]{5.6pt}{0.4pt}}\cr}}\widetilde{B}$
and $\widetilde{B}\mathrel{\ooalign{\raise
0.86108pt\hbox{$\Subset$}\cr\raise-1.07639pt\hbox{\rule[0.0pt]{5.6pt}{0.4pt}}\cr}}\widetilde{A}$.

######  Notation 1.

Let $\mathbbmss{U}$ be a set, $I=[0,1]$ the unit interval of the real numbers,
for every $r\in I$, with $\underline{r}$ we denote the constant mapping
$\underline{r}:\mathbbmss{U}\to I$ defined by $\underline{r}(u)=r$, for every
$u\in\mathbbmss{U}$.

######  Definition 5.4.

[30] The SVN-set
$\left\langle\mathbbmss{U},\underline{0},\underline{0},\underline{1}\right\rangle$
is said to be the neutrosophic empty set over $\mathbbmss{U}$ and it is
denoted by $\widetilde{\emptyset}$, or more precisely by
$\widetilde{\emptyset}_{\mathbbmss{U}}$ in case it is necessary to specify the
corresponding universe set.

######  Definition 5.5.

[30] The SVN-set
$\left\langle\mathbbmss{U},\underline{1},\underline{1},\underline{0}\right\rangle$
is said to be the neutrosophic absolute set over $\mathbbmss{U}$ and it is
denoted by $\widetilde{\mathbbmss{U}}$.

In our class, the data structure used to represent a SVN-set is a dictionary
(also called associative array) which uses the elements of the universe set as
keys and associates them with a list of three floating-point numbers
corresponding to the degrees of membership, indeterminacy and non-membership
respectively. This dictionary, referred as the $\\_\hskip
0.2pt\\_$neutrosophicset property, is stored in conjunction with the universe
set, referred as the $\\_\hskip 0.2pt\\_$universe property, to which it is
inseparably linked. Indeed, it is no coincidence that the class NSuniverse
does not provide any method for allowing modifications (such as insertions or
removals) of the elements of an object of type universe set since such
operations could disrupt the consistency of the SVN-sets defined on it. The
NSset class is described by the following UML diagram.

$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$==$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$!=$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$+$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$\&$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\sim$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$-$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$<=$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$>=$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$

The constructor method of this class accepts one or two parameters and allows
us to define a SVN-set in several different ways:

  * •

in the form NSset(universe set) assigning to it as its only parameter the
universe set (expressed as a list, tuple, or string) over which it is defined
and thus creating an empty SVN-set $\widetilde{\emptyset}$,

  * •

in the form NSset($\textit{{universe set}},\textrm{{values}}$) passing two
parameters, the first of which is a universe set and the second an enumeration
(expressed as a list, tuple, or string) of triples of real values representing
the degree of membership, indeterminacy and non-membership of all the elements
of the universe set, or

  * •

in the form NSset(neutrosophic set) by copying another object of the type
NSset.

The basic steps of this method, expressed in pseudo-code, are described in the
following algorithm.

Function  _$\\_\hskip 0.2pt\\_$ init$\\_\hskip 0.2pt\\_$(_args_)_:

Create a dictionary neutrosophicset

Get the length of args

if  _length $=1$_ then

if  _args is a list, a tuple, a string or an object of the class NSuniverse_
then

Create universe from args and set neutrosophicset empty

else if  _args is an object of the class NSset_ then

Get universe and neutrosophicset from args

else

Raise an Exception

else if  _length $=2$_ then

Use the same constructor with the first parameter of args to obtain an object
of type NSset from which to derive universe and set the list values equal to
the second parameter of args

if  _values is a list or a tuple_ then

if  _length of values is different from the length of universe_ then

Raise an Exception

Assigns to each element of universe the values of the corresponding triple of
values

else if  _args is a string_ then

Converts args to a list of triples and uses the same constructor with universe
and such a list to obtain an object of type NSset from which to take
neutrosophicset

else

Raise an Exception

else

Raise an Exception

Stores universe and neutrosophicset in the properties $\\_\hskip
0.2pt\\_$universe and $\\_\hskip 0.2pt\\_$neutrosophicset respectively

Algorithm 2 Constructor method of the class NSset

Note how every possible error condition – such as, for example, attempting to
pass a variable of type other than NSuniverse or a list of values not
consisting of triples of real numbers included in the $[0,1]$ interval or,
again, using it with fewer than one or more than two parameters – is
intercepted in the code and reported to the client by raising an appropriate
exception.

The Python code corresponding to the constructor method of the NS_set class is
given below.

⬇

1from .ns_universe import NSuniverse

2from .ns_util import NSreplace, NSstringtoTriplesList, NSsplitText

4class NSset:

6 degreename = ["membership", "indeterminacy", "non-membership"]

7 reprmaxlength = 64

9 def $\\_\hskip 0.2pt\\_$init$\dunder$(self, *args):

10 neutrosophicset = dict()

11 length = len(args)

12 if length == 1:

13 element = args[0]

14 if type(element) in [list, tuple, str, NSuniverse]:

15 universe = NSuniverse(element)

16 for e in universe.get():

17 neutrosophicset[e] = [0,0,1]

18 elif type(element) == NSset:

19 universe = element.getUniverse()

20 for e in universe:

21 neutrosophicset[e] = element.getElement(e)

22 else:

23 raise ValueError("value not compatible with the type universe set")

24 elif length == 2:

25 nset = NSset(args[0])

26 universe = nset.getUniverse()

27 values = args[1]

28 if type(values) in [list ,tuple]:

29 if len(values) != len(universe):

30 raise IndexError("the number of value triples does not correspond with the
number of elements")

31 for i in range(len(universe)):

32 elem = universe[i]

33 t = values[i]

34 if type(t) not in [tuple,list] or len(t) !=3:

35 raise IndexError("the second parameter of the constructor method must
contain only triple")

36 t = [float(t[j]) for j in range(3)]

37 for j in range(3):

38 if not 0 <= t[j] <= 1:

39 raise ValueError(f"incompatible {self.degreename[j]} degree value")

40 neutrosophicset[elem] = t

41 elif type(values) == str:

42 tpl_list = NSstringtoTriplesList(values)

43 nset = NSset(universe, tpl_list)

44 neutrosophicset = nset.get()

45 else:

46 raise ValueError("the second parameter of the constructor method must
contain a list of triples of real numbers")

47 else:

48 raise IndexError("the number of parameters do not match those of the
constructor method")

49 self.$\\_\hskip 0.2pt\\_$universe = NSuniverse(universe)

50 self.$\\_\hskip 0.2pt\\_$neutrosophicset = neutrosophicset

Let us observe that to enable the parsing of strings containing triples with
the values of membership degrees, indeterminacy and non-membership, variously
expressed, were used the function NSstringToTriplesList contained in the
utility file NS_util.py.

Similar to what we have seen previously for objects of type universe set, the
constructor method of the class NSset also allows for a multiplicity of
expressions thanks to which we can define neutrosophic sets with a direct and
informal notation by means of lists, tuples or strings of elements separated
indifferently by commas or semicolons.
For example, the SVN-set
$\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$ over
the universe set $\mathbbmss{U}=\\{a,b,c\\}$ defined by:

$\left\langle\frac{a}{(0.5,0.3,0.2)},\frac{b}{(0.6,0.2,0.3)},\frac{c}{(0.4,0.2,0.7)}\right\rangle$

can be defined as an object of the class NSset in any of the following ways
mutually equivalent:

  * •

A=NSset("a,b,c",[(0.5,0.3,0.2),(0.6,0.2,0.3),(0.4,0.2,0.7)]) as a list of
tuples,

  * •

A=NSset("a,b,c",[[0.5,0.3,0.2],[0.6,0.2,0.3],[0.4,0.2,0.7]]) as a list of
lists,

  * •

A=NSset("a,b,c",[[0.5,0.3,0.2],(0.6,0.2,0.3),[0.4,0.2,0.7]]) as a mixed list
of lists and tuples,

  * •

A=NSset("a,b,c",([0.5,0.3,0.2],[0.6,0.2,0.3],[0.4,0.2,0.7])) as a tuple of
lists,

  * •

A=NSset("a,b,c",((0.5,0.3,0.2),(0.6,0.2,0.3),(0.4,0.2,0.7))) as a tuple of
tuples,

  * •

A=NSset("a,b,c",((0.5,0.3,0.2),[0.6,0.2,0.3],(0.4,0.2,0.7))) as a mixed tuple
of tuples and lists,

  * •

A=NSset("a,b,c","[0.5,0.3,0.2],(0.6,0.2,0.3);[0.4,0.2,0.7]") as a string
containing lists and tuples

where the universe set can also be expressed in any equivalent form as
U=NSuniverse("{a,b,c}"), U=NSuniverse("[a,b;c]") or U=NSuniverse("(a;b,c)") so
that it can be used later in the definition of the SVN-set in the form:

  * •

A=NSset(U,"[0.5,0.3,0.2],(0.6,0.2,0.3);[0.4,0.2,0.7]")

A SVN-set
$\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$ already
defined over a universe set $\mathbbmss{U}$ can be subsequently modified by
assigning to each of its generic elements $u\in\mathbbmss{U}$ its degrees of
membership $\textit{mu}=\mu_{A}\left(u\right)$, indeterminacy
$\textit{sigma}=\sigma_{A}\left(u\right)$ and non-membership
$\textit{omega}=\omega_{A}\left(u\right))$ separately through the methods:

  * •

setMembership(self,u,mu)

  * •

setIndeterminacy(self,u,sigma), and

  * •

setNonMembership(self,u,omega)

or by assigning in one shot the entire
$\textit{triple}=\left(\mu_{A}\left(u\right),\sigma_{A}\left(u\right),\omega_{A}\left(u\right)\right)$
of values using the method:

  * •

setElement(self,u,triple)

all of which are based on the private method $\\_\hskip
0.2pt\\_$setDegree(self,u,i,v) that assigns the value $v$ to the $i$-th degree
(for $i=0,1,2$, which correspond in the order to membership, indeterminacy and
non-membership degree) of a given element $u$ of the current SVN-set.
Obviously, in the latter method we take into account the fact that the element
$u$ must belong to the corresponding universe set and that the membership
degrees must be real values included in the unit interval $I$ and if not,
appropriate exceptions will be raised.

⬇

1 def $\\_\hskip 0.2pt\\_$setDegree(self, u, i, r):

2 u = str(u)

3 if u not in self.getUniverse():

4 raise IndexError(’non-existent element’)

5 r = float(r)

6 if not (0 <= r <= 1):

7 raise ValueError(f"incompatible {self.degreename[i]} degree value")

8 self.$\\_\hskip 0.2pt\\_$neutrosophicset[u][i] = r

10 def setMembership(self, u, mu):

11 self.$\\_\hskip 0.2pt\\_$setDegree(u, 0, mu)

13 def setIndeterminacy(self, u, sigma):

14 self.$\\_\hskip 0.2pt\\_$setDegree(u, 1, sigma)

16 def setNonMembership(self, u, omega):

17 self.$\\_\hskip 0.2pt\\_$setDegree(u, 2, omega)

19 def setElement(self, u, triple):

20 if type(triple) == str:

21 sostituz = { "(":"", ")":"", ",":" ", ";":" " }

22 triple = NSreplace(triple, sostituz).split()

23 else:

24 triple = list(triple)

25 if len(triple) != 3:

26 raise ValueError(’error in the number of parameters passed’)

27 triple = [float(e) for e in triple]

28 for i in range(3):

29 self.$\\_\hskip 0.2pt\\_$setDegree(u, i, triple[i])

Three basic methods called getUniverse(), get() and getElement(u) respectively
return to us the universe set of a given SVN-set as a string list of its
elements, the neutrosophic set itself as a dictionary having for keys the
elements of the universe and for values the triples of the degrees of
membership, indeterminacy and non-membership as well as the triple of the
degrees of a given element $u\in\mathbbmss{U}$.

⬇

1 def getUniverse(self):

2 return self.$\\_\hskip 0.2pt\\_$universe.get()

4 def get(self):

5 return self.$\\_\hskip 0.2pt\\_$neutrosophicset

7 def getElement(self, u):

8 u = str(u)

9 if u not in self.getUniverse():

10 raise IndexError(’non-existent element’)

11 return self.$\\_\hskip 0.2pt\\_$neutrosophicset[u]

Given a SVN-set
$\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$ over a
universe set $\mathbbmss{U}$, The values of the degrees of membership
$\mu_{A}\left(u\right)$, indeterminacy $\sigma_{A}\left(u\right)$ and non-
membership $\omega_{A}\left(u\right)$ of a generic element $u\in\mathbbmss{U}$
can be obtained by the methods:

  * •

getMembership(u),

  * •

getIndeterminacy(u), and

  * •

getNonMembership(u)

which are all based on the private method $\\_\hskip
0.2pt\\_$getDegree(self,u,i) that returns the value of the $i$-th degree (for
$i=0,1,2$, which correspond in the order to membership, indeterminacy and non-
membership degree) of a given element $u$ of the current SVN-set. Let us note
that in the latter method, we consider the prerequisite that the element $u$
must belong to the corresponding universe set and if this condition is not
satisfied a suitable exception will be raised.

⬇

1 def $\\_\hskip 0.2pt\\_$getDegree(self, u, i):

2 u = str(u)

3 if u not in self.getUniverse():

4 raise IndexError(’non-existent element’)

5 return self.$\\_\hskip 0.2pt\\_$neutrosophicset[u][i]

7 def getMembership(self, u):

8 return self.$\\_\hskip 0.2pt\\_$getDegree(u, 0)

10 def getIndeterminacy(self, u):

11 return self.$\\_\hskip 0.2pt\\_$getDegree(u, 1)

13 def getNonMembership(self, u):

14 return self.$\\_\hskip 0.2pt\\_$getDegree(u, 2)

In case we need the empty neutrosophic set $\widetilde{\emptyset}$ or the
neutrosophic absolute set $\widetilde{\mathbbmss{U}}$ over an universe set
$\mathbbmss{U}$ we can refer to the methods setEmpty() and setAbsolute(),
respectively.

⬇

1 def setEmpty(self):

2 for e in self.$\\_\hskip 0.2pt\\_$universe.get():

3 self.$\\_\hskip 0.2pt\\_$neutrosophicset[e] = [0, 0, 1]

5 def setAbsolute(self):

6 for e in self.$\\_\hskip 0.2pt\\_$universe.get():

7 self.$\\_\hskip 0.2pt\\_$neutrosophicset[e] = [1, 1, 0]

The on-screen printing in text format of objects of type NSset as well as
their complete representation is achieved by overloading the special methods
$\\_\hskip 0.2pt\\_$str$\\_\hskip 0.2pt\\_$ and $\\_\hskip
0.2pt\\_$repr$\\_\hskip 0.2pt\\_$ as follows.

⬇

1 def $\\_\hskip 0.2pt\\_$str$\dunder$(self, tabularFormat=False):

2 if tabularFormat == True:

3 (dashes, elemwidth, valwidth) = ("-"*64, 10, 14)

4 s = "\n | membership | indeterminacy | non-membership |\n" + dashes + "\n"

5 for e in self.getUniverse():

6 (mu, sigma, omega) = self.getElement(e)

7 s += f" {str(e):{elemwidth}} | {mu:{valwidth}} | {sigma:{valwidth}} | {omega:{valwidth}} |\n"

8 s += dashes + "\n"

9 else:

10 elems = []

11 for e in self.getUniverse():

12 (mu, sigma, omega) = self.getElement(e)

13 elems.append(f"{e}/({mu},{sigma},{omega})")

14 s = "< " + ", ".join(elems) + " >"

15 s = NSsplitText(s, self.reprmaxlength)

16 return s

18 def $\\_\hskip 0.2pt\\_$repr$\dunder$(self):

19 return f"Neutrosophic set: {str(self)}"

In particular, the special method $\\_\hskip 0.2pt\\_$str$\\_\hskip 0.2pt\\_$
allow us to print on the screen a SVN-set in both the simplified
representation (which is the default option) and in the clearer and more
extensive tabular representation.

Furthermore, in order to be able to choose to print a SVN-set in the
simplified representation or in the tabular one even in interactive use or
writing client code, it was chosen to redefine the special method $\\_\hskip
0.2pt\\_$format$\\_\hskip 0.2pt\\_$ so that it recognizes the new custom
format specifier t that corresponds to printing in tabular format objects of
type NSset.

⬇

1 def $\\_\hskip 0.2pt\\_$format$\dunder$(self, spec):

2 if spec == "t":

3 result = self.$\\_\hskip 0.2pt\\_$str$\dunder$(tabularFormat=True)

4 else:

5 result = self.$\\_\hskip 0.2pt\\_$str$\dunder$(tabularFormat=False)

6 return result

Thanks to the redefinition by overloading of the special methods $\\_\hskip
0.2pt\\_$eq$\\_\hskip 0.2pt\\_$ and $\\_\hskip 0.2pt\\_$ne$\\_\hskip 0.2pt\\_$
we can use the operators of equality == and diversity != directly to objects
of type NSset.

⬇

1 def $\\_\hskip 0.2pt\\_$eq$\dunder$(self, nset):

2 if self.getUniverse() != nset.getUniverse():

3 raise ValueError("the two neutrosophic sets cannot be defined on different
universe sets")

4 equal = self.isNSsubset(nset) and nset.isNSsubset(self)

5 return equal

7 def $\\_\hskip 0.2pt\\_$ne$\dunder$(self, nset):

8 if self.getUniverse() != nset.getUniverse():

9 raise ValueError("the two neutrosophic sets cannot be defined on different
universe sets")

10 different = not (self == nset)

11 return different

In order to better illustrate how the above methods are used, let us consider
the following example of code executed interactively in the Python console.

⬇

>>> from pyns.ns_universe import NSuniverse

>>> from pyns.ns_set import NSset

>>> U = NSuniverse("a,b,c")

>>> A = NSset(U)

>>> A.setElement(’a’, (0.8,0.2,0.1))

>>> A.setElement(’c’, (0.3,0.2,0.4))

>>> A.getMembership(’a’)

0.8

>>> A.getNonMembership(’c’)

0.4

>>> print(A.getElement(c))

[0.3, 0.2, 0.4]

>>> A.setIndeterminacy(’b’,0.9)

>>> print(A)

< a/(0.8,0.2,0.1), b/(0.0,0.9,1.0), c/(0.3,0.2,0.4) >

>>> print(f"{A:t}")

| membership | indeterminacy | non-membership |

\----------------------------------------------------------------

a | 0.8 | 0.2 | 0.1 |

b | 0 | 0.9 | 1 |

c | 0.3 | 0.2 | 0.4 |

\----------------------------------------------------------------

>>> A.setAbsolute()

>>> print(A)

< a/(1,1,0), b/(1,1,0), c/(1,1,0) >

From the example above, one might assume that creating universe sets and SVN-
sets requires manual definition. However, the open structure of our framework
actually enables us to define objects of type NSuniverse and NSset dynamically
within the code, commonly referred to as defining them ’on the fly’. This
dynamic approach is especially advantageous when dealing with SVN-sets of
considerable cardinality, as illustrated in the following Python code.

⬇

1from pyns.ns_universe import NSuniverse

2from pyns.ns_set import NSset

3from random import random

5lst = [(i,j) for i in range(1,6) for j in range(1,4)]

7U = NSuniverse(lst)

8A = NSset(U)

10for u in U.get():

11 triple = [round(random(), 2) for k in range(3)]

12 A.setElement(u, triple)

14print(f"The following SVNS-set has cardinality {A.cardinality()}: {A:t}")

which produces output of the type:

⬇

The following SVNS-set has cardinality 15:

| membership | indeterminacy | non-membership |

\----------------------------------------------------------------

(1, 1) | 0.55 | 0.1 | 0.5 |

(1, 2) | 0.39 | 0.92 | 0.09 |

(1, 3) | 0.33 | 0.29 | 0.25 |

(2, 1) | 0.16 | 0.9 | 0.43 |

(2, 2) | 0.71 | 0.52 | 0.33 |

(2, 3) | 0.65 | 0.38 | 0.04 |

(3, 1) | 0.95 | 0.14 | 0.94 |

(3, 2) | 0.74 | 0.02 | 0.01 |

(3, 3) | 0.77 | 0.63 | 0.19 |

(4, 1) | 0.18 | 0.75 | 0.15 |

(4, 2) | 0.49 | 0.92 | 0.75 |

(4, 3) | 0.34 | 0.17 | 0.88 |

(5, 1) | 0.88 | 0.6 | 0.83 |

(5, 2) | 0.5 | 0.56 | 0.8 |

(5, 3) | 0.38 | 0.47 | 0.2 |

\----------------------------------------------------------------

To verify that a SVN-set expressed as an object of type NSset is
neutrosophically contained in another SVN-set, we may resort to the method
isNSsubset(nset) which, similarly to the built-in issubset() method available
for objects of type set, returns the Boolean value True if the current SVN-set
is neutrosophically contained in the second SVN-set nset passed as a parameter
or the value False otherwise.

⬇

1 def isNSsubset(self, nset):

2 if self.getUniverse() != nset.getUniverse():

3 raise ValueError("the two neutrosophic sets cannot be defined on different
universe sets")

4 if self.getUniverse() != nset.getUniverse():

5 return False

6 else:

7 result = True

8 for e in self.getUniverse():

9 (muA, sigmaA, omegaA) = self.getElement(e)

10 (muB, sigmaB, omegaB) = nset.getElement(e)

11 if (muA > muB) or (sigmaA > sigmaB) or (omegaA < omegaB):

12 result = False

13 break

14 return result

Based on isNSsubset, it is then immediate to define the method
isNSsuperset(nset) (analogous to the built-in issuperset method) which returns
True if the current SVN-set neutrosophically contains the second SVN-set nset
passed as a parameter or False otherwise.

⬇

1 def isNSsuperset(self, nset):

2 if self.getUniverse() != nset.getUniverse():

3 raise ValueError("the two neutrosophic sets cannot be defined on different
universe sets")

4 return nset.isNSsubset(self)

In both cases, it is preliminarily verified that the two SVN-sets are defined
on the same universe set and if not an appropriate exception is raised.

The following code executed in interactive mode in the Python console
illustrates the use of the methods just described.

⬇

>>> from pyns.ns_universe import NSuniverse

>>> from pyns.ns_set import NSset

>>> A = NSset("a, b, c", "(0.3,0,0.5), (0.7,0.2,0.2), (0.1,0.5,0.4)")

>>> print(A)

< a/(0.3,0.0,0.5), b/(0.7,0.2,0.2), c/(0.1,0.5,0.4) >

>>> B = NSset("a, b, c", "(0.4,0.2,0.3), (0.8,0.3,0.1), (0.2,0.5,0.2)")

>>> print(B)

< a/(0.4,0.2,0.3), b/(0.8,0.3,0.1), c/(0.2,0.5,0.2) >

>>> print(A.isNSsubset(B))

True

>>> print(A.isNSsuperset(B))

False

######  Definition 5.6.

[19] The neutrosophic union of two SVN-sets
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$
and
$\widetilde{B}=\left\langle\mathbbmss{U},\mu_{B},\sigma_{B},\omega_{B}\right\rangle$,
denoted by $\widetilde{A}\Cup\widetilde{B}$, is the neutrosophic set defined
by
$\left\langle\mathbbmss{U},\mu_{A}\vee\mu_{B},\sigma_{A}\vee\sigma_{B},\omega_{A}\wedge\omega_{B}\right\rangle$.

######  Definition 5.7.

[19] The neutrosophic intersection of two SVN-sets
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$
and
$\widetilde{B}=\left\langle\mathbbmss{U},\mu_{B},\sigma_{B},\omega_{B}\right\rangle$,
denoted by $\widetilde{A}\Cap\widetilde{B}$, is the neutrosophic set defined
by
$\left\langle\mathbbmss{U},\mu_{A}\wedge\mu_{B},\sigma_{A}\wedge\sigma_{B},\omega_{A}\vee\omega_{B}\right\rangle$.

######  Definition 5.8.

[30] Let
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$
and
$\widetilde{B}=\left\langle\mathbbmss{U},\mu_{B},\sigma_{B},\omega_{B}\right\rangle$
be two SVN-sets over $\mathbbmss{U}$. We say that $\widetilde{A}$ and
$\widetilde{B}$ are neutrosophically disjoint if
$\widetilde{A}\Cap\widetilde{B}\mathrel{\ooalign{\raise
0.43057pt\hbox{$=$}\cr\hskip 0.6pt\raise
0.86108pt\hbox{\rule{6.6pt}{0.35pt}}\cr\raise
4.52083pt\hbox{{\rule{6.6pt}{0.32pt}}}\cr}}\widetilde{\emptyset}$. On the
contrary, if $\widetilde{A}\Cap\widetilde{B}\not\mathrel{\ooalign{\raise
0.43057pt\hbox{$=$}\cr\hskip 0.6pt\raise
0.86108pt\hbox{\rule{6.6pt}{0.35pt}}\cr\raise
4.52083pt\hbox{{\rule{6.6pt}{0.32pt}}}\cr}}\widetilde{\emptyset}$ we say that
$\widetilde{A}$ neutrosophically meets $\widetilde{B}$ (or that
$\widetilde{A}$ and $\widetilde{B}$ neutrosophically meet each other).

Within our NSset class, the neutrosophic union and neutrosophic intersection
were implemented through the methods NSunion() and NSintersection(),
respectively. These methods mirror the built-in Python methods union e
intersection for objects of type set and they are both based on the private
method $\\_\hskip 0.2pt\\_$NSoperation(self, nset, fm,fs, fo) corresponding to
a generic operation and that returns the neutrosophic set obtained from the
current SVN-set and the second SVN-set nset by applying the three functions
fm, fs, fo passed as parameters to their membership, indeterminacy and non-
membership degrees respectively.

⬇

1 def $\\_\hskip 0.2pt\\_$NSoperation(self, nset, fm, fs, fo):

2 if self.getUniverse() != nset.getUniverse():

3 raise ValueError("the two neutrosophic sets cannot be defined on different
universe sets")

4 if callable(fm) == False or callable(fs) == False or callable(fo) == False:

5 raise ValueError("the last three parameters must be functions")

6 C = NSset(self.$\\_\hskip 0.2pt\\_$universe)

7 for e in self.getUniverse():

8 (muA, sigmaA, omegaA) = self.getElement(e)

9 (muB, sigmaB, omegaB) = nset.getElement(e)

10 triple = [fm(muA, muB), fs(sigmaA, sigmaB), fo(omegaA, omegaB)]

11 C.setElement(e, triple)

12 return C

14 def NSunion(self, nset):

15 C = self.$\\_\hskip 0.2pt\\_$NSoperation(nset, max, max, min)

16 return C

18 def NSintersection(self, nset):

19 C = self.$\\_\hskip 0.2pt\\_$NSoperation(nset, min, min, max)

20 return C

We illustrate the above methods with an example of code executed interactively
in the Python console.

⬇

>>> from pyns.ns_universe import NSuniverse

>>> from pyns.ns_set import NSset

>>> U = NSuniverse("a, b, c")

>>> A = NSset(U,"(0.3,0,0.5), (0.7,0.2,0.2), (0.1,0.5,0.4)")

>>> print(A)

< a/(0.3,0.0,0.5), b/(0.7,0.2,0.2), c/(0.1,0.5,0.4) >

>>> B = NSset(U,"(0.4,0.2,0.3), (0.8,0.3,0.1), (0.2,0.5,0.2)")

>>> print(B)

a/(0.4,0.2,0.3), b/(0.8,0.3,0.1), c/(0.2,0.5,0.2) >

>>> C = A.NSunion(B)

>>> print(C)

< a/(0.4,0.2,0.3), b/(0.8,0.3,0.1), c/(0.2,0.5,0.2) >

>>> D = A.NSintersection(B)

>>> print(D)

< a/(0.3,0.0,0.5), b/(0.7,0.2,0.2), c/(0.1,0.5,0.4) >

The method isNSdisjoint(nset) returns the Boolean value True if the current
SVN-set is neutrosophically disjoint from the second SVN-set passed as
parameter or the value False otherwise.

⬇

1 def isNSdisjoint(self, nset):

2 nsempty = NSset(self.$\\_\hskip 0.2pt\\_$universe)

3 disjoint = self.NSintersection(nset) == nsempty

4 return disjoint

An example of the use of this method is provided in the following code
executed in the console Python interactive.

⬇

>>> from pyns.ns_universe import NSuniverse

>>> from pyns.ns_set import NSset

>>> A = NSset("a, b, c", "(0.3,0,0.5), (0.7,0,1), (0,0.5,1)")

>>> B = NSset("a, b, c", "(0,0.8,1), (0,0.1,0.2), (0.1,0.0,0.4)")

>>> print(A.isNSdisjoint(B))

True

######  Definition 5.9.

[27, 30] Let
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$
be a SVN-set over the universe set $\mathbbmss{U}$, the neutrosophic
complement (or, simply, the complement) of $\widetilde{A}$, denoted by
$\widetilde{A}^{\hskip
0.45206pt\ooalign{\hbox{\scalebox{0.8}{$\complement$}}\cr\hskip
1.6pt\hbox{\rule[0.2pt]{0.6pt}{6.6pt}}}}$, is the SVN-set
$\widetilde{A}^{\hskip
0.45206pt\ooalign{\hbox{\scalebox{0.8}{$\complement$}}\cr\hskip
1.6pt\hbox{\rule[0.2pt]{0.6pt}{6.6pt}}}}=\left\langle\mathbbmss{U},\omega_{A},\underline{1}-\sigma_{A},\mu_{A}\right\rangle$
that is $\widetilde{A}^{\hskip
0.45206pt\ooalign{\hbox{\scalebox{0.8}{$\complement$}}\cr\hskip
1.6pt\hbox{\rule[0.2pt]{0.6pt}{6.6pt}}}}=\left\\{\left(u,\omega_{A}\left(u\right),1-\sigma_{A}\left(u\right),\mu_{A}\left(u\right)\right):u\in\mathbbmss{U}\right\\}$.

Although the neutrosophic difference of two SVN-sets $\widetilde{A}$ and
$\widetilde{B}$ can be defined (in analogy with ordinary sets) as the
neutrosophic intersection of the first set with the neutrosophic complement of
the second set, that is, as $\widetilde{A}\Cap\widetilde{B}^{\hskip
0.45206pt\ooalign{\hbox{\scalebox{0.8}{$\complement$}}\cr\hskip
1.6pt\hbox{\rule[0.2pt]{0.6pt}{6.6pt}}}}$, for our purposes it is preferable
to provide an explicit and operational definition.

######  Definition 5.10.

The neutrosophic difference of two SVN-sets
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$
and
$\widetilde{B}=\left\langle\mathbbmss{U},\mu_{B},\sigma_{B},\omega_{B}\right\rangle$,
denoted by $\widetilde{A}\setminus\setminus\hskip 1.00006pt\widetilde{B}$, is
the neutrosophic set defined by
$\left\langle\mathbbmss{U},\mu_{A}\wedge\omega_{B},\sigma_{A}\wedge(\underline{1}-\sigma_{B}),\omega_{A}\vee\mu_{B}\right\rangle$.

The latter operations have also been implemented in the class NSset through
the methods NScomplement() and NSdifference().

⬇

1 def NScomplement(self):

2 C = NSset(self.$\\_\hskip 0.2pt\\_$universe)

3 for e in self.getUniverse():

4 (muA, sigmaA, omegaA) = self.getElement(e)

5 triple = [omegaA, 1 - sigmaA, muA]

6 C.setElement(e, triple)

7 return C

9 def NSdifference(self, nset):

10 if self.getUniverse() != nset.getUniverse():

11 raise ValueError("the two neutrosophic sets cannot be defined on different
universe sets")

12 C = NSset(self.$\\_\hskip 0.2pt\\_$universe)

13 for e in self.getUniverse():

14 (muA, sigmaA, omegaA) = self.getElement(e)

15 (muB, sigmaB, omegaB) = nset.getElement(e)

16 triple = [min(muA,omegaB), min(sigmaA,1-sigmaB), max(omegaA,muB)]

17 C.setElement(e, triple)

18 return C

The following code example executed interactively in the Python console
illustrates the use of the two methods that have been just described.

⬇

>>> from pyns.ns_universe import NSuniverse

>>> from pyns.ns_set import NSset

>>> U = NSuniverse(’a’,’b’,’c’)

>>> A = NSset(U, "(0.5,0.3,0.2), (0.6,0.2,0.3), (0.4,0.2,0.7)")

>>> print(A)

< a/(0.5,0.3,0.2), b/(0.6,0.2,0.3), c/(0.4,0.2,0.7) >

>>> B = NSset(U, "(0.2,0.2,0.2), (0.4,0.1,0.6), (0.8,0.3,0.1)")

>>> print(B)

< a/(0.2,0.2,0.2), b/(0.4,0.1,0.6), c/(0.8,0.3,0.1) >

>>> C = A.NScomplement()

>>> print(C)

< a/(0.2,0.7,0.5), b/(0.3,0.8,0.6), c/(0.7,0.8,0.4) >

>>> D = A.NSdifference(B)

>>> print(D)

< a/(0.2,0.3,0.2), b/(0.6,0.2,0.4), c/(0.1,0.2,0.8) >

To facilitate even more streamlined and intuitive use of neutrosophic set
operations, especially in the interactive use of the framework, overloading
was then used to redefine the special methods $\\_\hskip
0.2pt\\_$add$\\_\hskip 0.2pt\\_$, $\\_\hskip 0.2pt\\_$and$\\_\hskip 0.2pt\\_$,
$\\_\hskip 0.2pt\\_$invert$\\_\hskip 0.2pt\\_$, $\\_\hskip
0.2pt\\_$sub$\\_\hskip 0.2pt\\_$, $\\_\hskip 0.2pt\\_$le$\\_\hskip 0.2pt\\_$,
and $\\_\hskip 0.2pt\\_$ge$\\_\hskip 0.2pt\\_$, respectively referred to the
operators $+$, $\&$, $\sim$, $-$, $<=$, and $>=$ for use with objects of type
NSset by making them coincide with the methods NSunion(), NSintersection(),
NScomplement(), NSdifference(), isNSsubset() and isNSsuperset(), thus
obtaining the correspondence summarized in the following table.

|  class method | symbol | operator
---|---|---|---
neutrosophic union | NSunion() | $\Cup$ | $+$
neutrosophic intersection | NSintersection() | $\Cap$ | $\&$
neutrosophic complement | NScomplement() |  ${{\,}^{\hskip 0.45206pt\ooalign{\hbox{\scalebox{0.8}{$\complement$}}\cr\hskip 1.6pt\hbox{\rule[0.2pt]{0.6pt}{6.6pt}}}}}^{\phantom{-}}$ | $\sim$
neutrosophic difference | NSdifference() | $\,\setminus\\!\\!\\!\\!\setminus$ | $-$
neutrosophic subset | isNSsubset() | $\mathrel{\ooalign{\raise 0.86108pt\hbox{$\Subset$}\cr\raise-1.07639pt\hbox{\rule[0.0pt]{5.6pt}{0.4pt}}\cr}}$ | $<=$
neutrosophic superset | isNSsuperset() | $\mathrel{\ooalign{\raise 0.86108pt\hbox{$\Supset$}\cr\raise-1.07639pt\hbox{\rule[0.0pt]{5.6pt}{0.4pt}}\cr}}$ | $>=$

The following example illustrates how the methods and operators defined above
can be easily and profitably used in the interactive mode by means of the
Python console.

⬇

>>> from pyns.ns_universe import NSuniverse

>>> from pyns.ns_set import NSset

>>> U = NSuniverse(’a’,’b’,’c’)

>>> A = NSset(U, "(0.5,0.3,0.2), (0.6,0.2,0.3), (0.4,0.2,0.7)")

>>> print(A)

< a/(0.5,0.3,0.2), b/(0.6,0.2,0.3), c/(0.4,0.2,0.7) >

>>> B = NSset(U, "(0.2,0.2,0.2), (0.4,0.1,0.6), (0.8,0.3,0.1)")

>>> print(B)

< a/(0.2,0.2,0.2), b/(0.4,0.1,0.6), c/(0.8,0.3,0.1) >

>>> print(A + B)

< a/(0.5,0.3,0.2), b/(0.6,0.2,0.3), c/(0.8,0.3,0.1) >

>>> print(A & B)

< a/(0.2,0.2,0.2), b/(0.4,0.1,0.6), c/(0.4,0.2,0.7) >

>>> print(~A)

< a/(0.2,0.7,0.5), b/(0.3,0.8,0.6), c/(0.7,0.8,0.4) >

>>> F = A - B

>>> print(F)

< a/(0.2,0.3,0.2), b/(0.6,0.2,0.4), c/(0.1,0.2,0.8) >

>>> print(F <= A)

True

>>> print(F == A & ~B)

True

##  6\. The NSmapping class

The mappings between two universe sets and the main operations involving them
are represented and handled through the NSmapping class that uses both the
NSuniverse class and the NSset class.

For every mapping $f:\mathbbmss{U}\to\mathbbmss{V}$, the class stores the
domain $\mathbbmss{U}$ and the codomain $\mathbbmss{V}$ as objects of type
NSuniverse in the properties $\\_\hskip 0.2pt\\_$domain and $\\_\hskip
0.2pt\\_$codomain respectively, as well as the correspondence between each
generic element $u\in\mathbbmss{U}$ and its value $f(u)\in\mathbbmss{V}$ by a
dictionary corresponding to the property $\\_\hskip 0.2pt\\_$map = {u: f(u)
for u in$\quad\mathbbmss{U}$}.
The class is briefly described in the following UML diagram.

$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip
0.2pt\\_$$==$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$!=$$\\_\hskip
0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$$\\_\hskip 0.2pt\\_$

The constructor method accepts one or three arguments and allows us to define
a mapping in several different ways:

  * •

in the form NSmapping(domain, codomain, values) where domain and codomain are
both universe sets expressed in any of the ways already seen above, namely as
tuples, lists, strings, or instances of the class NSuniverse, while values is
an enumeration of codomain values neatly corresponding to domain values which
can be expressed indifferently as a tuple, list, string, dictionary or
extended dictionary,

  * •

in the form NSmapping(values) where values is either a regular Python
dictionary or an extended dictionary; in this case the universe sets related
to the domain and codomain will be created automatically by collecting
respectively the keys and values of the dictionary passed as parameter,
without repeating their values and checking that no error condition occurs,

  * •

in the form NSmapping(mapping) by copying another object of the type
NSmapping.

The basic steps of this method are described in the following algorithm.

Function  _$\\_\hskip 0.2pt\\_$ init$\\_\hskip 0.2pt\\_$(_args_)_:

Create a dictionary map

Get the length of args

if  _length $=0$_ then

Raise an Exception

else if  _length $=1$_ then

if  _args is an object of type NSmapping_ then

Copies the properties in the current object

else if  _args is a dictionary_ then

Copy args to map and gets domain and codomain as keys and values of args,
respectively

else if  _args is an extended dictionary_ then

Gets the dictionary from the string and passes it to the same constructor to
obtain an object of type NSmapping from which to derive domain, codomain and
the dictionary of correspondence map

else if  _length $=3$_ then

Attempts to take the first three parameters of args to assign them
respectively to the universe sets domain, codomain and the object values

if  _values is a dictionary or an extended dictionary_ then

Passes values to the same constructor to obtain an object of type NSmapping
and, if its domain and codomain are compatible with those passed as
parameters, derive the dictionary of correspondences map

else if  _values is a list, a tuple or a string_ then

if  _values is a list or a tuple_ then

Converts values to a list of strings;

else

Split values and turns it into a string list;

if  _the length of values $\neq$ cardinality of the domain_ then

Raise an Exception

if  _the set of values is not contained in the codomain_ then

Raise an Exception

Neatly stores the elements of values as values of the map dictionary whose
keys are the elements of the domain

else

Raise an Exception

else

Raise an Exception

Stores domain, domain and map in the properties $\\_\hskip 0.2pt\\_$domain,
$\\_\hskip 0.2pt\\_$codomain and $\\_\hskip 0.2pt\\_$map respectively

Algorithm 3 Constructor method of the class NSmapping

Let us note how every possible error condition – such as recalling it with
only one parameter that is not an object NSmapping, with a number of
parameters other than one and three or, again, passing parameters that are not
the two universe sets and a list of values however expressed – is intercepted
in the code and reported to the client by raising an appropriate exception.

The Python code corresponding to the constructor method of this class is given
below.

⬇

1from .ns_universe import NSuniverse

2from .ns_set import NSset

3from .ns_util import NSreplace, NSstringToDict, NSisExtDict

5class NSmapping:

7 def $\\_\hskip 0.2pt\\_$init$\dunder$(self, *args):

8 map = dict()

9 length = len(args)

10 if length == 0:

11 raise ValueError("constructor method must have at least one parameter")

12 elif length == 1:

13 if type(args[0]) == NSmapping:

14 domain = args[0].getDomain()

15 codomain = args[0].getDomain()

16 map = args[0].getMap()

17 elif type(args[0]) == dict:

18 map = args[0]

19 domain = NSuniverse(list(map.keys()))

20 codomain = NSuniverse(list(set(map.values())))

21 elif type(args[0]) == str:

22 try:

23 map_dict = NSstringToDict(args[0])

24 except:

25 raise ValueError("invalid parameter")

26 nsmap = NSmapping(map_dict)

27 domain = nsmap.getDomain()

28 codomain = nsmap.getCodomain()

29 map = nsmap.getMap()

30 else:

31 raise ValueError("the type of the parameter do not match those of the
constructor method")

32 elif length == 3:

33 try:

34 domain = NSuniverse(args[0])

35 except:

36 raise ValueError("the first parameter of the constructor method must be a
universe set")

37 try:

38 codomain = NSuniverse(args[1])

39 except:

40 raise ValueError("the second parameter of the constructor method must be a
universe set")

41 values = args[2]

42 card_domain = domain.cardinality()

43 if type(values)==dict or NSisExtDict(values)==True:

44 nsmap = NSmapping(values)

45 if set(nsmap.getDomain()) != set(domain):

46 raise ValueError("the indicated domain is incompatible with the definition
of the mapping")

47 if nsmap.getCodomain().isSubset(codomain) == False:

48 raise ValueError("the indicated codomain is incompatible with the
definition of the mapping")

49 map = nsmap.getMap()

50 elif type(values) in [list, tuple, str]:

51 if type(values) in [list, tuple]:

52 values = [str(e) for e in values]

53 else:

54 sostituz = {"[": "", "]": "", "(": "", ")": "",

55 ",": " ", ";": " "}

56 values = NSreplace(values, sostituz).split()

57 if len(values) != card_domain:

58 raise IndexError("the number of values passed does not coincide with the
cardinality of the declared domain")

59 values_set = set(values)

60 codomain_set = set(codomain.get())

61 if not values_set.issubset(codomain_set):

62 raise ValueError("one or more values do not belong to the declared
codomain")

63 for i in range(card_domain):

64 map[domain.get()[i]] = values[i]

65 else:

66 raise ValueError("the third parameter of the constructor method must
express a obj match")

67 else:

68 raise IndexError("the number of parameters do not match those of the
constructor method")

69 self.$\\_\hskip 0.2pt\\_$domain = domain

70 self.$\\_\hskip 0.2pt\\_$codomain = codomain

71 self.$\\_\hskip 0.2pt\\_$map = map

Note that, as in the case of the definition of the universe set constructor
method, it is excluded that the third parameter, corresponding to the
enumeration of values can be an object of type set since by its nature as an
unordered collection of data would provide an ambiguous formulation of the
mapping.

As in the case of the objects NSuniverse and NSset, for the mappings
represented by objects of the type NSmapping much attention was paid to the
usability and flexibility of the syntax which allows us to define mappings
between universe sets in a variety of possible forms.
For example, the mappings $f:\mathbbmss{U}\to\mathbbmss{V}$ between the
universe sets $\mathbbmss{U}=\\{a,b,c\\}$ and $\mathbbmss{V}=\\{1,2\\}$ and
such that $f(a)=f(c)=2$ and $f(b)=1$ can be defined as an object of the class
NSmapping in any of the following ways mutually equivalent:

  * •

NSmapping([’a’,’b’,’c’], [1,2], [2,1,2]) by using lists,

  * •

NSmapping((’a’,’b’,’c’), (1,2), (2,1,2)) by using tuples,

  * •

NSmapping("a,b,c", "1;2", "2,1,2") by using strings,

  * •

NSmapping("(a,b,c)", "{1,2}", "(2;1;2)") by using strings containing lists or
tuples,

  * •

NSmapping([’a’,’b’,’c’], (1,2), "2,1,2")) in a mixed form of lists, tuples and
strings,

  * •

NSmapping({’a’:2, ’b’:1, ’c’:2}) by using dictionaries,

  * •

NSmapping("’a’:2, ’b’:1, ’c’:2") by using a string that contains a matching of
values in a dictionary format,

  * •

NSmapping("a->2, b->1, c->2") by using an extended dictionary with the arrow
notation,

  * •

NSmapping("a|->2, b|->1, c|->2") by using an extended dictionary with the the
”maps to” notation,

  * •

NSmapping("’a’->2, b|->1; (c->2)") by using an extended dictionary in a mixed
form,

  * •

NSmapping("a,b,c", "1,2", "a->2, b->1, c->2") by declaring domain and codomain
and using an extended dictionary,

  * •

NSmapping("a,b,c", "1,2", "c->2, a|->2; b|->1") by declaring domain and
codomain and using an extended dictionary in a mixed form and without a
precise order,

as well as in different combinations of them or, again, by preliminarily
defining one or both of the universe sets in any of the forms already seen
above, by setting, for example, U=NSuniverse("{a,b,c}") and
V=NSuniverse((1,2)")", so that they can be used later in the definition of the
mapping in the form like:

  * •

NSmapping(U, V, [2,1,2]), or

  * •

NSmapping(U, V, "a->2, b->1, c->2").

Three basic methods called getDomain(), getCodomain() and getMap()
respectively return us the domain and codomain of the mapping as objects of
type NSuniverse as well as the dictionary containing all the element-value
pairs that define the mapping.

⬇

1 def getDomain(self):

2 return self.$\\_\hskip 0.2pt\\_$domain.get()

4 def getCodomain(self):

5 return self.$\\_\hskip 0.2pt\\_$codomain.get()

7 def getMap(self):

8 return self.$\\_\hskip 0.2pt\\_$map

The method setValue(u,v) assigns a single value $v$ by the current mapping to
a specific element $u$ of the domain.

⬇

1 def setValue(self, u, v):

2 u = str(u)

3 v = str(v)

4 if u not in self.$\\_\hskip 0.2pt\\_$domain.get():

5 raise IndexError(’non-existent element in the domain of the mapping’)

6 if v not in self.$\\_\hskip 0.2pt\\_$codomain.get():

7 raise IndexError(’non-existent element in the codomain of the mapping’)

8 self.$\\_\hskip 0.2pt\\_$map[u] = v

Instead, the method getValue(u) returns the value corresponding to an element
$u$ of the domain by the current mapping.

⬇

1 def getValue(self, u):

2 u = str(u)

3 if u not in self.$\\_\hskip 0.2pt\\_$domain.get():

4 raise IndexError(’non-existent element in the domain of the mapping’)

5 return self.$\\_\hskip 0.2pt\\_$map[u]

In order to be able to easily print on the screen objects of type NSmapping in
text format and to provide a complete representation of them, the special
methods $\\_\hskip 0.2pt\\_$str$\\_\hskip 0.2pt\\_$ and $\\_\hskip
0.2pt\\_$repr$\\_\hskip 0.2pt\\_$ were overloaded as follows.

⬇

1 def $\\_\hskip 0.2pt\\_$str$\dunder$(self):

2 unvwidth = 28

3 totwidth = unvwidth*2 + 8

4 s = f"\n {str(self.$\\_\hskip 0.2pt\\_$domain):>{unvwidth}} ->
{str(self.$\\_\hskip 0.2pt\\_$codomain):<{unvwidth}}\n"+"-"*totwidth+"\n"

5 for e in self.$\\_\hskip 0.2pt\\_$domain:

6 s += f" {e:>{unvwidth}} |-> {self.$\\_\hskip 0.2pt\\_$map[e]:<{unvwidth}}\n"

7 return s

9 def $\\_\hskip 0.2pt\\_$repr$\dunder$(self):

10 return f"Neutrosophic mapping: {str(self)}"

Thanks to the redefinition by overloading of the special methods $\\_\hskip
0.2pt\\_$eq$\\_\hskip 0.2pt\\_$ and $\\_\hskip 0.2pt\\_$ne$\\_\hskip 0.2pt\\_$
we can apply the operators of equality == and diversity != directly to objects
of type NSmapping.

⬇

1 def $\\_\hskip 0.2pt\\_$eq$\dunder$(self, g):

2 if self.getDomain() != g.getDomain() or self.getCodomain() !=
g.getCodomain():

3 return False

4 else:

5 equal = True

6 for e in self.getDomain():

7 if self.getValue(e) != g.getValue(e):

8 equal = False

9 break

10 return equal

12 def $\\_\hskip 0.2pt\\_$ne$\dunder$(self, g):

13 different = not (self == g)

14 return different

The following code executed in interactive mode in the Python console
illustrates the use of the methods just described.

⬇

>>> from pyns.ns_universe import NSuniverse

>>> from pyns.ns_set import NSset

>>> from pyns.ns_mapping import NSmapping

>>> U = NSuniverse("a,b,c")

>>> V = NSuniverse(1,2)

>>> f = NSmapping(U,V, (2,1,2))

>>> print(f)

{ a, b, c } -> { 1, 2 }

\----------------------------------------------------------------

a |-> 2

b |-> 1

c |-> 2

>>> print(f.getValue(’a’))

2

>>> g = NSmapping("a->2 b->1 c->2")

>>> print( f==g )

True

>>> print(g)

{ a, b, c } -> { 1, 2 }

\----------------------------------------------------------------

a |-> 2

b |-> 1

c |-> 2

>>> print(h.getDomain())

{ a, b, c }

>>> print(h.getCodomain())

{ 1, 2 }

>>> print(f.getMap())

{’a’: ’2’, ’b’: ’1’, ’c’: ’2’}

>>> h = NSmapping("a,b,c", "1,2", "a->2 b->1 c->2")

>>> print( f==h )

True

The method getFibre(v) returns the fibre of an element $v$ of the codomain by
the current mapping $f:\mathbbmss{U}\to V$, that is, the set of all elements
of the domain whose value is $v$, i.e.
$f^{-1}\left(\\{v\\}\right)=\left\\{u\in\mathbbmss{U}:\,f(u)=v\right\\}$. The
corresponding code is given below.

⬇

1 def getFibre(v):

2 v = str(v)

3 if v not in self.$\\_\hskip 0.2pt\\_$codomain.get():

4 raise IndexError(’non-existent element in the codomain of the mapping’)

5 fibre = list()

6 for e in self.$\\_\hskip 0.2pt\\_$map:

7 if self.$\\_\hskip 0.2pt\\_$map[e] == v:

8 fibre.append(e)

9 return fibre

######  Definition 6.1.

[11, 22] Let $f:\mathbbmss{U}\to\mathbbmss{V}$ be a mapping between two
universe sets $\mathbbmss{U}$ and $\mathbbmss{V}$, and
$\widetilde{A}=\left\langle\mathbbmss{U},\mu_{A},\sigma_{A},\omega_{A}\right\rangle$
be a SVN-set over $\mathbbmss{U}$. The neutrosophic image of $\widetilde{A}$
by $f$, denoted by $\widetilde{f}\left(\widetilde{A}\right)$, is the SVN-set
over $\mathbbmss{V}$ defined by:

$\widetilde{f}\left(\widetilde{A}\right)=\left\langle\mathbbmss{V},\mu_{f(A)},\sigma_{f(A)},\omega_{f(A)}\right\rangle$

where the mappings $\mu_{f(A)}:\mathbbmss{V}\to I$,
$\sigma_{f(A)}:\mathbbmss{V}\to I$ and $\omega_{f(A)}:\mathbbmss{V}\to I$ are
defined respectively by:

$\begin{array}[]{ll}\mu_{f(A)}(v)&=\left\\{\begin{array}[]{ll}{\displaystyle\sup_{u\in{f}^{-1}\left(\left\\{v\right\\}\right)}\mu_{A}\left(u\right)}&\text{if
}{f}^{-1}\left(\left\\{v\right\\}\right)\neq\emptyset\\\\[11.38109pt]
1&\text{otherwise}\end{array}\right.,\\\\[22.76219pt]
\sigma_{f(A)}(v)&=\left\\{\begin{array}[]{ll}{\displaystyle\sup_{u\in{f}^{-1}\left(\left\\{v\right\\}\right)}\sigma_{A}\left(u\right)}&\text{if
}{f}^{-1}\left(\left\\{v\right\\}\right)\neq\emptyset\\\\[11.38109pt]
1&\text{otherwise}\end{array}\right.,\\\\[22.76219pt]
\omega_{f(A)}(v)&=\left\\{\begin{array}[]{ll}{\displaystyle\inf_{u\in{f}^{-1}\left(\left\\{v\right\\}\right)}\omega_{A}\left(u\right)}&\text{if
}{f}^{-1}\left(\left\\{v\right\\}\right)\neq\emptyset\\\\[11.38109pt]
0&\text{otherwise}\end{array}\right.\end{array}$

for every $v\in\mathbbmss{V}$.

The method NSimage(self, nset) returns the image of a SVN-set nset over the
domain by the current mapping. The corresponding code is given below.

⬇

1 def NSimage(self, nset):

2 result = NSset(self.$\\_\hskip 0.2pt\\_$codomain)

3 for v in self.getCodomain():

4 fibre = self.getFibre(v)

5 if fibre == []:

6 triple = [1,1,0]

7 else:

8 mu_values = list()

9 sigma_values = list()

10 omega_values = list()

11 for u in fibre:

12 mu_values.append(nset.getMembership(u))

13 sigma_values.append(nset.getIndeterminacy(u))

14 omega_values.append(nset.getNonMembership(u))

15 triple = [max(mu_values),max(sigma_values),min(omega_values)]

16 result.setElement(v, triple)

17 return result

######  Definition 6.2.

[11, 22] Let $f:\mathbbmss{U}\to\mathbbmss{V}$ be a mapping between two
universe sets $\mathbbmss{U}$ and $\mathbbmss{V}$, and
$\widetilde{B}=\left\langle\mathbbmss{V},\mu_{B},\sigma_{B},\omega_{B}\right\rangle$
be a SVN-set over $\mathbbmss{V}$. The neutrosophic inverse image of
$\widetilde{B}$ by $f$, denoted by
${\widetilde{f}}^{-1}\\!\left(\widetilde{B}\right)$, is the SVN-set over
$\mathbbmss{U}$ defined by:

${\widetilde{f}}^{-1}\\!\left(\widetilde{B}\right)=\left\langle\mathbbmss{U},\mu_{f^{-1}(B)},\sigma_{f^{-1}(B)},\omega_{f^{-1}(B)}\right\rangle$

where the mappings $\mu_{f^{-1}(B)}:\mathbbmss{U}\to I$,
$\sigma_{f^{-1}(B)}:\mathbbmss{U}\to I$ and
$\omega_{f^{-1}(B)}:\mathbbmss{U}\to I$ are defined respectively by:

$\mu_{f^{-1}(B)})=\mu_{B}\circ f,\quad\sigma_{f^{-1}(B)}=\sigma_{B}\circ
f,\quad\text{and}\quad\omega_{f^{-1}(B)}=\omega_{B}\circ f\,.$

The method NScounterimage(self, nset) returns the counter image of a SVN-set
nset over the codomain by the current mapping. The corresponding code is
provided below.

⬇

1 def NScounterimage(self, nset):

2 result = NSset(self.$\\_\hskip 0.2pt\\_$domain)

3 for u in self.getDomain():

4 value = self.getValue(u)

5 triple = nset.getElement(value)

6 result.setElement(u, triple)

7 return result

The following code executed in interactive mode in the Python console
summarizes and explicates the use of the methods just described along with
those already seen in the other two classes.

⬇

>>> U = NSuniverse("a,b,c,d,e")

>>> V = NSuniverse(1,2,3,4)

>>> f = NSmapping(U, V, (1,3,1,2,1))

>>> print(f)

{ a, b, c, d, e } -> { 1, 2, 3, 4 }

\----------------------------------------------------------------

a |-> 1

b |-> 3

c |-> 1

d |-> 2

e |-> 1

>>> A = NSset(U, "(0.7,0.3,0.1), (0.4,0.6,0.9), (0,0,1), (0.1,0.4,0.5),
(0.2,0.2,0.3)")

>>> print(f"{A:t}")

| membership | indeterminacy | non-membership |

\----------------------------------------------------------------

a | 0.7 | 0.3 | 0.1 |

b | 0.4 | 0.6 | 0.9 |

c | 0.0 | 0.0 | 1.0 |

d | 0.1 | 0.4 | 0.5 |

e | 0.2 | 0.2 | 0.3 |

\----------------------------------------------------------------

>>> B = f.NSimage(A)

>>> print(B)

< 1/(0.7,0.3,0.1), 2/(0.1,0.4,0.5), 3/(0.4,0.6,0.9),

4/(1.0,1.0,0.0) >

>>> C = f.NScounterimage(B)

< a/(0.7,0.3,0.1), b/(0.4,0.6,0.9), c/(0.7,0.3,0.1),

d/(0.1,0.4,0.5), e/(0.7,0.3,0.1) >

>>> print(A.isNSsubset(C))

True

##  7\. Conclusions

In this paper we have presented PYNS, an open source framework developed in
Python and consisting of three distinct classes designed to manipulate in a
simple and intuitive way symbolic representations of neutrosophic sets over
universes of various types as well as mappings between them.

The codebase of this framework, currently comprising approximately $1200$
lines of code, empowers us with the capability to seamlessly define,
represent, and manipulate universe sets, neutrosophic sets, and functions
operating between neutrosophic sets. This is facilitated through a
comprehensive set of operations, including neutrosophic union, neutrosophic
intersection, neutrosophic difference, as well as the computation of image and
back-image of a neutrosophic set by means of a function, among others. These
operations operate at various levels, impacting the values of the membership,
indeterminacy and non-membership degree of each individual element.

The capabilities offered by this framework extend and generalize previous
attempts to provide software solutions for the manipulation of neutrosophic
sets already undertaken in recent years by several authors such as. Salama et
al. [21], Saranya et al. [23], El-Ghareeb [7], Topal et al. [29] and Sleem
[26].

Furthermore, the modular structure of PYNS not only facilitates interactive
usage for experimentation and counterexample searches within the neutrosophic
domain, making efficient use of a simple and intuitive notation, but also
enables easy integration into more complex Python projects that can take
advantage of robust and extensively tested methods for operations on
neutrosophic sets that this framework provides.

Both the code and the underlying data structures of the three classes
NSuniverse, NSset and NSmapping with particular regard to their properties and
methods have been explained in detail in the previous sections and also
concrete examples of using the introduced objects and methods have been given.

The attention given to the usability of these classes and the extensive
documentation provided with a rich assortment of examples and use cases, gives
us confidence that, in addition to being used for the exploration of uncertain
data and practical applications, it can be the subject of further study and
expansion opening up new research perspectives in various scientific and
applied disciplines that use the tools of neutrosophic set theory. In
particular, the authors believe that interesting developments in the medical
field may come from the application and extension of this framework to
neutrosophic hypersoft mappings that have proven to be useful in the diagnosis
of hepatitis [17] or its eventual adaptation to fuzzy hypersoft mappings [2]
which have proven to be useful in the diagnosis of HIV and tuberculosis [3,
18].

The complete Python framework PYNS including the source code of all the
classes described in this paper as well as a selection of example programs
that use them are available at the url
github.com/giorgionordo/pythonNeutrosophicSets.

## Acknowledgment

This research was supported by Gruppo Nazionale per le Strutture Algebriche,
Geometriche e le loro Applicazioni (G.N.S.A.G.A.) of Istituto Nazionale di
Alta Matematica (INdAM) ”F. Severi”, Italy.

## References

  * 1. Abobala M., Hatip A. An Algebraic Approach to Neutrosophic Euclidean Geometry. Neutrosophic Sets and Systems 43 (1), pp. 114-123, 2021.
  * 2. Ahsan M., Saeed M., Rahman A.U. A Theoretical and Analytical Approach for Fundamental Framework of Composite mappings on Fuzzy Hypersoft Classes. Neutrosophic Sets and Systems 45, pp. 268-285, 2021.
  * 3. Ahsan M., Saeed M., Mehmood A., Saeed M.H., Asad J. The Study of HIV Diagnosis Using Complex Fuzzy Hypersoft Mapping and Proposing Appropriate Treatment. IEEE Access, 9, pp. 104405-104417, 2021.
  * 4. Atanassov K.T. Intuitionistic Fuzzy Sets. Fuzzy Sets and Systems 20 (1), pp. 87-96, 1986.
  * 5. Broumi S., Talea M., Bakali A., Smarandache F. Single valued neutrosophic graphs. Journal of New theory 10, pp. 86-101, 2016.
  * 6. Broumi S., Dhar M., Bakhouyi A., Bakali A., Talea M. Medical Diagnosis Problems Based on Neutrosophic Sets and Their Hybrid Structures: A Survey. Neutrosophic Sets and Systems 49 (1), pp. 1-18, 2022.
  * 7. El-Ghareeb H.A. Novel Open Source Python Neutrosophic Package. Neutrosophic Sets and Systems 25, pp. 136-160, 2019.
  * 8. Elhassouny A., Idbrahim S., Smarandache F. Machine learning in Neutrosophic Environment: A Survey. Neutrosophic Sets and Systems 28 (1), pp. 58–68, 2019.
  * 9. Guo Y., Cheng H.D. New neutrosophic approach to image segmentation. Pattern Recognition 42, pp. 587-595, 2009.
  * 10. Kunwar D., Singh J., Smarandache F. Neutrosophic statistical techniques to find migration pattern in Jaipur. Octogon Mathematical Magazine 26 (2), pp. 583-592, 2018.
  * 11. Latreche A., Barkat O., Milles S., Ismail F. Single valued neutrosophic mappings defined by single valued neutrosophic relations with applications. Neutrosophic Sets and Systems 32, pp. 203-220, 2020.
  * 12. Mehmood A., Nadeem F., Nordo G., Zamir M., Park C.,Kalsoom H., Jabeen S., Khan M.Y. Generalized neutrosophic separation axioms in neutrosophic soft topological spaces. Neutrosophic Sets and Systems 32 (1), pp. 38–51, 2020.
  * 13. Mehmood A., Nadeem F., Park C., Nordo G., Kalsoom H., Rahim Khan M., Abbas N. Neutrosophic soft alpha-open set in neutrosophic soft topological spaces. Journal of Algorithms and Computation 52, pp. 37–66, 2020.
  * 14. Mondal K, Pramanik S. Neutrosophic Decision Making Model of School Choice. Neutrosophic Sets and Systems 7 (1), pp. 62-68, 2015.
  * 15. Nordo G., Mehmood A., Broumi S. Single Valued Neutrosophic Filters. International Journal of Neutrosophic Science 6, pp. 8-21, 2020.
  * 16. Saber Y., Alsharari F., Smarandache F. On Single-Valued Neutrosophic Ideals in Şostak Sense. Symmetry 12 (2):193, 2020.
  * 17. Saeed M., Ahsan M., Saeed M.H., Mehmood A., Abdeljawad T. An Application of Neutrosophic Hypersoft Mapping to Diagnose Hepatitis and Propose Appropriate Treatment. IEEE Access, 9, pp. 70455-70471, 2021.
  * 18. Saeed M., Ahsan M., Saeed M.H., Rahman A.U., Mazin A.M., Nedoma J., Martinek R. An algebraic modeling for tuberculosis disease prognosis and proposed potential treatment methods using fuzzy hypersoft mappings. Biomedical Signal Processing and Control, 80 (1), 104267, 2023.
  * 19. Salama A.A., Alagamy H. Neutrosophic Filters. International Journal of Computer Science Engineering and Information Technologt Research 3 (1), pp. 307-312, 2013.
  * 20. Salama A., El-Ghareeb H.A.. Manie A.M., Smarandache F. Introduction to develop some software programs for dealing with neutrosophic sets. Neutrosophic Sets and Systems 3, pp. 51-52, 2019.
  * 21. Salama A., Abd el-Fattah M., El-Ghareeb H.A.. Manie A.M. Design and Implementation of Neutrosophic Data Operations Using Object Oriented Programming. International Journal of Computer Application 4 (5), pp. 163-175, 2014.
  * 22. Salama A.A., Smarandache F., Kromov V. Neutrosophic Closed Set and Neutrosophic Continuous Functions. Neutrosophic Sets and Systems 4, pp. 4-8, 2014.
  * 23. Saranya S., Vigneshwaran M., Jafari S. C# Application to Deal with Neutrosophic $g\alpha$-Closed Sets In Neutrosophic Topology. Application and Applied Mathematics 15 (1), pp. 226-239, 2020.
  * 24. Schweizer P. Uncertainty: two probabilities for the three states of neutrosophy. International Journal of Neutrosophic Science 2 (1), pp. 18-26, 2020.
  * 25. Sharma M., Kandasamy I., Vasantha W.B. Comparison of neutrosophic approach to various deep learning models for sentiment analysis. Knowledge-Based Systems 223, pp. 1-14, 2021.
  * 26. Sleem A., Abdel-Baset M., El-henawy I. PyIVNS: A python based tool for Interval-valued neutrosophic operations and normalization. SoftwareX 12, pp. 1-7, 2020.
  * 27. Smarandache F. A Unifying Field in Logics. Neutrosophy: Neutrosophic Probability, Set and Logic. Rehoboth: American Research Press, 1999.
  * 28. Smarandache F. Introduction to Neutrosophic Statistics. USA: Sitech & Education Publishing, 2014.
  * 29. Topal S., Broumi S., Bakali A., Talea M., Smarandache F. A Python Tool for Implementations on Bipolar Neutrosophic Matrices. Neutrosophic Sets and Systems 28, pp. 138-161, 2019.
  * 30. Wang H., Smarandache F., Zhang Y.Q., Sunderraman R. Single Valued Neutrosophic Sets. Technical Sciences and Applied Mathematics, pp. 10-14, 2012.
  * 31. Zadeh L.A. Fuzzy Sets, Information and Control 8 (3), pp. 338-353, 1965.
  * 32. Zhang M., Zhang L. Cheng H.D. A neutrosophic approach to image segmentation based on watershed method. Signal Processing 90, pp. 1510-1517, 2010.

Received: date / Accepted: date