Repository: LovetheFrogs/PyCircTools (language: python)

Issue:
Conversor



Discussion / hints:

Fix patch:
diff --git a/PyCircTools/Exceptions/OperatorsExceptions.py b/PyCircTools/Exceptions/OperatorsExceptions.py
index 3202824..13732af 100644
--- a/PyCircTools/Exceptions/OperatorsExceptions.py
+++ b/PyCircTools/Exceptions/OperatorsExceptions.py
@@ -23,6 +23,33 @@ def __init__(self, method=None, addr_class=False):
             self.msg = "Method " + method + " not allowed for an instance of " + get_adder_type(addr_class)
 
 
+class NotControlList(OperatorException):
+    """
+    NotControlList is raised when a list of operation codes is not of type bool or is not a list at all.
+    """
+    def __init__(self, msg="Operation code is not a list or its contents are not of type bool."):
+        self.msg = msg
+        super().__init__(self.msg)
+
+
+class WrongSize(OperatorException):
+    """
+    WrongSize is raised when the list of operation codes does not have the required size.
+    """
+    def __init__(self, curr_size, req_size):
+        self.msg = "List of size " + str(curr_size) + ". Needs to be of size " + str(req_size) + "!"
+        super().__init__(self.msg)
+
+
+class WrongRange(OperatorException):
+    """
+    WrongRange is raised when the number of inputs is lower or equal than the number of inputs in certain modules.
+    """
+    def __init(self, obj):
+        self.msg = "Number of inputs of " + obj + " must be lower than the number of outputs."
+        super().__init__(self.msg)
+
+
 def get_adder_type(addr_class):
     """
     Method used to get the type of adder used.
diff --git a/PyCircTools/Exceptions/__init__.py b/PyCircTools/Exceptions/__init__.py
index 124a40d..5cc8af2 100644
--- a/PyCircTools/Exceptions/__init__.py
+++ b/PyCircTools/Exceptions/__init__.py
@@ -5,3 +5,4 @@
 from PyCircTools.Exceptions.CircuitToolsExceptions import *
 from PyCircTools.Exceptions.LogicGateExceptions import *
 from PyCircTools.Exceptions.LatchesExceptions import *
+from PyCircTools.Exceptions.OperatorsExceptions import *
diff --git a/PyCircTools/Operators/Adder.py b/PyCircTools/Operators/Adder.py
index 704807c..6e67d1d 100644
--- a/PyCircTools/Operators/Adder.py
+++ b/PyCircTools/Operators/Adder.py
@@ -32,7 +32,7 @@ def get_A(self):
 
     def get_B(self):
         """
-        Method get_A gets the value of the second summand.
+        Method get_B gets the value of the second summand.
 
         :return: Value of the second summand.
         :rtype: bool
@@ -61,7 +61,7 @@ def get_carryIn(self):
         """
         Method get_carryIn gets the value of the input carry. It can only be used on a Full-adder object.
 
-        :raises NotCorrectAdder: Raised when when a function is called and is not allowed for the instance of an adder used in.
+        :raises NotCorrectAdder: Raised when a function is called and is not allowed for the instance of an adder used in.
         :return: Value of the input carry.
         :rtype: bool
         """
@@ -82,7 +82,7 @@ def set_A(self, value):
             raise NotTruthValue
 
         self.A = value
-        self.__calculate_output()
+        self._calculate_output()
         return self
 
     def set_B(self, value):
@@ -97,7 +97,7 @@ def set_B(self, value):
             raise NotTruthValue
 
         self.B = value
-        self.__calculate_output()
+        self._calculate_output()
         return self
 
     def set_carryIn(self, value):
@@ -106,7 +106,7 @@ def set_carryIn(self, value):
 
         :param value: Desired value of the adder's input carry.
         :type value: bool
-        :raises NotCorrectAdder: Raised when when a function is called and is not allowed for the instance of an adder used in.
+        :raises NotCorrectAdder: Raised when a function is called and is not allowed for the instance of an adder used in.
         :raises NotTruthValue: Raised when a variable type is not bool.
         """
         if not self.full:
@@ -116,7 +116,7 @@ def set_carryIn(self, value):
             raise NotTruthValue
 
         self.carryIn = value
-        self.__calculate_output()
+        self._calculate_output()
         return self
 
     def convert(self):
@@ -126,17 +126,17 @@ def convert(self):
         if not self.full:
             self.full = not self.full
             self.carryIn = False
-            self.__calculate_output()
+            self._calculate_output()
         else:
             self.full = not self.full
             self.__delattr__(self.carryIn)
-            self.__calculate_output()
+            self._calculate_output()
 
         return self
 
-    def __calculate_output(self):
+    def _calculate_output(self):
         """
-        Method __calculate_output is a private method which calculates the value of both carryOut and output signals.
+        Method __calculate_output is a protected method which calculates the value of both carryOut and output signals.
         It is used for both full and half adders.
         """
         if not self.full:
diff --git a/PyCircTools/Operators/Alu.py b/PyCircTools/Operators/Alu.py
new file mode 100644
index 0000000..956ec07
--- /dev/null
+++ b/PyCircTools/Operators/Alu.py
@@ -0,0 +1,155 @@
+from PyCircTools import And, Or, Mux2to1, Mux4to1, NotTruthValue, NotControlList, WrongSize
+from PyCircTools.Operators import Adder, Subtractor
+
+
+class Alu:
+    """
+    Alu module. Has 3 inputs, A (first operand), B (second operand) and Operation (control signal;
+    it is a list of size 2 of bools) all initialised to False. This control signal is used to select the solution
+    needed. The following lines explain which signal selects which operation.
+    False, False -> A and B
+    True, False -> A or B
+    False, True -> A + B
+    True, True -> A - B
+    Note that the less significant value is the 0th position of the list and so on.
+    """
+    def __init__(self):
+        """
+        Constructor of the ALU module. For reference on how this class works, use help(Alu). It is used to build an Alu
+        with opCode = 00, A and B = False.
+        """
+        self.A = False
+        self.B = False
+        self.Operation = [False, False]
+        self.CarrySel = self.Operation[0]
+        self.conj = And()
+        self.disj = Or()
+        self.adder = Adder()
+        self.sub = Subtractor()
+        self.mux = Mux4to1()
+        self.carrSel = Mux2to1()
+        self.output = self.mux.get_output()
+        self.carryOut = self.carrSel.get_output()
+        self.__cal_modules()
+
+    def get_A(self):
+        """
+        Method get_A returns the value of the A input.
+
+        :return: Value of the first operator (A input).
+        :rtype: bool
+        """
+        return self.A
+
+    def get_B(self):
+        """
+        Method get_B returns the value of the B input.
+
+        :return: Value of the second operator (B input).
+        :rtype: bool
+        """
+        return self.B
+
+    def get_op(self):
+        """
+        Method get_op returns the list of control signals Operation.
+
+        :return: List of control signals of the ALU.
+        :rtype: list
+        """
+        return self.Operation
+
+    def get_output(self):
+        """
+        Method get_output returns the output of the ALU.
+
+        :return: Result of the operation.
+        :rtype: bool
+        """
+        return self.output
+
+    def get_carryOut(self):
+        """
+        Method get_carryOut returns the value of the carryOut signal. Useful in adding and subtracting.
+
+        :return: Value of the output carry.
+        :rtype: bool
+        """
+        return self.carryOut
+
+    def set_A(self, value):
+        """
+        Sets the value of the A input signal.
+
+        :param value: Value of the A signal.
+        :type value: bool
+        :raises NotTruthValue: Raised when value's type is not bool.
+        """
+        if type(value) is not bool:
+            raise NotTruthValue
+
+        self.A = value
+        self.__cal_modules()
+        return self
+
+    def set_B(self, value):
+        """Sets the value of the B input signal.
+
+        :param value: Value of the B signal.
+        :type value: bool
+        :raises NotTruthValue: Raised when value's type is not bool.
+        """
+        if type(value) is not bool:
+            raise NotTruthValue
+
+        self.B = value
+        self.__cal_modules()
+        return self
+
+    def set_op(self, op_code):
+        """
+        Method set_A sets the value of the Operation control signal. It also sets the value of the CarrySel signal.
+
+        :param op_code: List of operation codes. Must be a list of bool values.
+        :type op_code: list
+        :raises NotControlList: raised when a list of operation codes is not of type bool or is not a list at all
+        :raises WrongSize: raised when the list of operation codes does not have the required size
+        """
+        if type(op_code) is not list:
+            raise NotControlList
+
+        for val in op_code:
+            if type(val) is not bool:
+                raise NotControlList
+
+        if len(op_code) != 2:
+            raise WrongSize(len(op_code), 2)
+
+        # CarrySel control signal's value is the same as the less significant input from op_code.
+        self.Operation = op_code
+        self.CarrySel = op_code[0]
+        self.__cal_modules()
+        return self
+
+    def __cal_modules(self):
+        """
+        Private method __cal_modules calculates the inputs and outputs of each module inside the ALU, as well as the
+        ALU's output and carryOut.
+        """
+        self.conj.set_input(0, self.A).set_input(1, self.B)
+        self.disj.set_input(0, self.A).set_input(1, self.B)
+        self.adder.set_A(self.A).set_B(self.B)
+        self.sub.set_A(self.A).set_B(self.B)
+
+        for count, value in enumerate(self.Operation):
+            self.mux.set_set(count, value)
+
+        self.mux.set_input(0, self.conj.get_output()).set_input(1, self.disj.get_output())\
+            .set_input(2, self.adder.get_output()).set_input(3, self.sub.get_output())
+        self.output = self.mux.get_output()
+
+        self.carrSel.set_set(self.CarrySel)
+        self.carrSel.set_input(0, self.adder.get_carryOut()).set_input(1, self.sub.get_carryOut())
+        self.carryOut = self.carrSel.get_output()
+
+        return self
diff --git a/PyCircTools/Operators/Conversor.py b/PyCircTools/Operators/Conversor.py
new file mode 100644
index 0000000..87386e3
--- /dev/null
+++ b/PyCircTools/Operators/Conversor.py
@@ -0,0 +1,99 @@
+from PyCircTools import Not, NotControlList, WrongSize
+from PyCircTools.Operators.Adder import *
+
+
+class Conversor:
+    """
+    Module conversor is used to convert any input from pure binary to two's complement.
+    """
+    def __init__(self, length=4):
+        """
+        Constructor of the Conversor class. Needs the length of the number you want to have converted. (defaults to 4).
+
+        :param length: Lenght of the number to convert
+        :type length: int
+        """
+        self.input = [False] * length
+        self.length = length
+        self.output = [None]
+        self.__calculate_output()
+
+    def get_input(self):
+        """
+        Method get_input gets the input of the conversor.
+
+        :return: List containing the input value.
+        :rtype: list
+        """
+        return self.input
+
+    def get_length(self):
+        """
+        Method get_length gets the length of the conversor input.
+
+        :return: Length of the number that can be converted.
+        :rtype: int
+        """
+        return self.length
+
+    def get_output(self):
+        """
+        Method get_output gets the output of the conversor.
+
+        :return: List containing the output values.
+        :rtype: list
+        """
+        return self.output
+
+    def set_input(self, values):
+        """
+        Method set_input sets the input of the conversor to the list of bools 'values'
+
+        :param values: List of bools containing the values of the input
+        :type values: list
+        :raises NotControlList: raised when a list is not of type bool or is not a list at all
+        :raises WrongSize: raised when the list does not have the required size
+        """
+        if type(values) is not list:
+            raise NotControlList
+
+        for val in values:
+            if type(val) is not bool:
+                raise NotControlList
+
+        if len(values) > self.length:
+            raise WrongSize(len(values), self.length)
+
+        self.input = values
+        self.__calculate_output()
+        return self
+
+    def __calculate_output(self):
+        """
+        Method __calculate_output calculates the desired output of the coversor by calling the __build method.
+        """
+        inverted = []
+
+        for val in self.input:
+            inverted.append(Not().set_input(val).get_output)
+        self.output = self.__build(inverted)
+
+        return self
+
+    def __build(self, inverted):
+        """
+        Method __build creates a list with the needed adders to convert the number to two's complement.
+
+        :param inverted: Input of the gate inverted.
+        :type inverted: list
+        :return: List containing the output.
+        :rtype: list
+        """
+        addrs = []
+        for i in range(self.length):
+            if i == 0:
+                addrs.append(Adder().set_A(inverted[i]).set_B(True))
+            else:
+                addrs.append(Adder(True).set_carryIn(addrs[i - 1].get_carryOut()).set_A(inverted[i]))
+
+        return addrs
diff --git a/PyCircTools/Operators/Extender.py b/PyCircTools/Operators/Extender.py
new file mode 100644
index 0000000..d61900c
--- /dev/null
+++ b/PyCircTools/Operators/Extender.py
@@ -0,0 +1,142 @@
+from PyCircTools import NotTruthValue, NotControlList, WrongSize, WrongRange
+
+
+class Extender:
+    """
+    Extender module acts as a sign extender. It makes the output be the input with its most significant bit repeated. It
+    can be used for both, two's complement and pure binary.
+    """
+    def __init__(self, into=2, out=4, pure=True):
+        """
+        Constructor method creates an extender from into bits to out bits. The default is pure binary, but it can be
+        used for two's complement by specifying pure=False.
+
+        :param into: Number of inputs.
+        :type into: int
+        :param out: Number of bits of the output.
+        :type out: int
+        :param pure: Used to know if the input is in pure binary or two's complement.
+        :type pure: bool
+        """
+        if into >= out:
+            raise WrongRange("Extender")
+
+        self.numInto = into
+        self.numOut = out
+        self.pure = pure
+        self.input = [False] * into
+        self.output = [False] * out
+
+    def get_numIn(self):
+        """
+        Method get_numIn gets the number of inputs.
+
+        :return: Number of input signals of the extender.
+        :rtype: int
+        """
+        return self.numInto
+
+    def get_numOut(self):
+        """
+        Method get_numOut gets the number of output signals.
+
+        :return: Number of output signals of the extender.
+        :rtype: int
+        """
+        return self.numOut
+
+    def get_input(self):
+        """
+        Method get_input gets the input to extend.
+
+        :return: A list containing the input.
+        :rtype: list
+        """
+        return self.input
+
+    def get_output(self):
+        """
+        Method get_output gets the extended output.
+
+        :return: A list containing the output.
+        :rtype: list
+        """
+        return self.output
+
+    def get_pure(self):
+        """
+        Method get_pure gets whether an input is expressed in pure binary or two's complement.
+
+        :return: True if input is in pure binary, False otherwise.
+        :rtype: bool
+        """
+        return self.pure
+
+    def set_input(self, values, pure=True):
+        """
+        Method set_input is used to set the input of the extender to a certain list of values.
+
+        :param values: List of boolean values for the input of the extender
+        :type values: list
+        :param pure: Indicates if the list is expressed in pure binary. Defaults to True.
+        :type pure: bool
+        :raises NotTruthValue: Raised when value's type is not bool.
+        :raises NotControlList: raised when the contents of the input are not of type bool or is not a list at all
+        :raises WrongSize: raised when the list for the input does not have the required size
+        """
+        if type(pure) is not bool:
+            raise NotTruthValue
+
+        if type(values) is not list:
+            raise NotControlList
+
+        for item in values:
+            if type(item) is not bool:
+                raise NotControlList
+
+        if len(values) != self.numInto:
+            raise WrongSize(len(values), self.numInto)
+
+        self.input = values
+        self.__set_pure(pure)
+        self.__calculate_output()
+
+        return self
+
+    def __set_pure(self, value):
+        """
+        Private method __set_pure is used internally to set the value of the self.pure attribute.
+
+        :param value: Desired value of the 'pure' attribute
+        :type value: bool
+        """
+        if type(value) is not bool:
+            raise NotTruthValue
+
+        self.pure = value
+        return self
+
+    def __calculate_output(self):
+        """
+        Private method __calculate_output gets the expected output for the input introduced.
+
+        :return: Desired output of the extender.
+        :rtype: list
+        """
+        output = []
+        if self.pure:
+            for i in range(self.numOut):
+                if i < self.numInto:
+                    output.append(self.input[i])
+                else:
+                    output.append(False)
+
+        else:
+            for i in range(self.numOut):
+                if i < self.numInto:
+                    output.append(self.input[i])
+                else:
+                    output.append(self.input[self.numInto - 1])
+
+        self.output = output
+        return self
diff --git a/PyCircTools/Operators/Shifter.py b/PyCircTools/Operators/Shifter.py
new file mode 100644
index 0000000..856b097
--- /dev/null
+++ b/PyCircTools/Operators/Shifter.py
@@ -0,0 +1,165 @@
+from PyCircTools import DFlipflop, NotTruthValue, NotControlList, WrongSize
+# Copy is used to generate a copy of input so that it is not deleted when calculating output.
+import copy
+
+
+class Shifter:
+    """
+    Shifter module. Used to shift the position of the inputs left or right a given number of positions.
+    """
+    def __init__(self, num=4, pos=1, dirs=False):
+        """
+        Constructor of the Shifter module. Takes three arguments, num, pos and dir. It defaults to a shifter with 4
+        inputs that moves 1 position to the left.
+
+        :param num: Number of inputs of the shifter.
+        :type num: int
+        :param pos: Number of positions the shifter will move the input.
+        :type pos: int
+        :param dirs: Direction the shifter moves (Defaults to False which is shift right. True is shift left).
+        :type dirs: bool
+        """
+        self.num_of_inputs = num
+        self.positions = pos
+        self.D = dirs
+        self.input = [False] * num
+        self.clock = False
+        self.output = self.__calculate_output()
+
+    def get_numOfInputs(self):
+        """
+        Method get_numOfInputs returns the number of inputs of the shifter.
+
+        :return: Number of inputs of the shifter.
+        :rtype: int
+        """
+        return self.num_of_inputs
+
+    def get_positions(self):
+        """
+        Method get_positions returns the number of positions the shifter moves.
+
+        :return: Number of positions to shift.
+        :rtype: int
+        """
+        return self.positions
+
+    def get_D(self):
+        """
+        Method get_D returns the direction of the shifter.
+
+        :return: Direction the shifter moves.
+        :rtype: bool
+        """
+        return self.D
+
+    def get_input(self):
+        """
+        Method get_input returns the input of the shifter.
+
+        :return: Input of the shift register in form of a list.
+        :rtype: list
+        """
+        return self.input
+
+    def get_output(self):
+        """
+        Method get_output returns the output of the shifter.
+
+        :return: Output of the shift register in the form of a list.
+        :rtype: list
+        """
+        return self.output
+
+    def get_clock(self):
+        """
+        Method get_clock returns the value of the clock.
+
+        :return: Value of the clock.
+        :rtype: bool
+        """
+        return self.clock
+
+    def set_D(self, value):
+        """
+        Method set_D is used to set the direction the shifter moves, being False -> shift right and True -> shift left.
+
+        :param value: New value of the D attribute.
+        :type value: bool
+        :raises NotTruthValue: Raised when value's type is not bool.
+        """
+        if type(value) is not bool:
+            raise NotTruthValue
+
+        self.D = value
+        self.output = self.__calculate_output()
+        return self
+
+    def set_clock(self, value):
+        """
+        Method set_clock is used to set the value of the clock.
+
+        :param value: New value of the clock attribute.
+        :type value: bool
+        :raises NotTruthValue: Raised when value's type is not bool.
+        """
+        if type(value) is not bool:
+            raise NotTruthValue
+
+        self.clock = value
+        self.output = self.__calculate_output()
+        return self
+
+    def set_input(self, values):
+        """
+        Method set_input is used to set the input of the shifter to a list of bool.
+
+        :param values: List of values for the input.
+        :type values: list
+        :raises NotControlList: raised when a list of ovalues is not a list of bool or is not a list at all
+        :raises WrongSize: raised when the list of values does not have the required size
+        """
+        if type(values) is not list:
+            raise NotControlList
+
+        for val in values:
+            if type(val) is not bool:
+                raise NotControlList
+
+        if len(values) > self.num_of_inputs:
+            raise WrongSize(len(values), self.num_of_inputs)
+
+        self.input = values
+        self.output = self.__calculate_output()
+        return self
+
+    def __calculate_output(self):
+        """
+        Method __calculate_output is gets the value of the output of the shifter, depending on its direction, number of
+        positions to move and number of inputs. It uses the copy.copy method to create copies of the input and output
+        and avoid replacing the original values when not intended. The same method is used for both directions and all
+        possible combinations of number of inputs and positions to shift.
+
+        :return: Output the shifter will have.
+        :rtype: list
+        """
+        output = [False] * self.num_of_inputs
+        if self.clock:
+            output = copy.copy(self.input)
+            for _ in range(self.positions):
+                inp = copy.copy(output)
+                if not self.D:
+                    for i in range(self.num_of_inputs):
+                        if i == 0:
+                            output[i] = DFlipflop().set_D(inp[self.num_of_inputs - 1]).set_enable(True).get_Q()
+                        else:
+                            output[i] = DFlipflop().set_D(inp[i - 1]).set_enable(True).get_Q()
+
+                else:
+                    for i in range(self.num_of_inputs):
+                        if i == self.num_of_inputs - 1:
+                            output[i] = DFlipflop().set_D(inp[0]).set_enable(True).get_Q()
+                        else:
+                            output[i] = DFlipflop().set_D(inp[i + 1]).set_enable(True).get_Q()
+
+        return output
diff --git a/PyCircTools/Operators/Subtractor.py b/PyCircTools/Operators/Subtractor.py
new file mode 100644
index 0000000..8f06a86
--- /dev/null
+++ b/PyCircTools/Operators/Subtractor.py
@@ -0,0 +1,158 @@
+from PyCircTools import NotTruthValue, And, Xor, Not, Or
+from PyCircTools.Exceptions.OperatorsExceptions import NotCorrectAdder
+
+
+class Subtractor:
+    """
+    Subtractor module. The constructor can be used to specify whether a half-subtractor or a full-subtractor is being created.
+    """
+    def __init__(self, full=False):
+        """
+        Subtractor class constructor.
+
+        :param full: Defaults to False. Used to specify if the type of subtractor used. (False -> Half-subtractor, True -> Full-subtractor).
+        :type full: bool
+        """
+        self.A = False
+        self.B = False
+        self.carryOut = False
+        self.output = False
+        self.full = full
+        if full:
+            self.carryIn = False
+
+    def get_A(self):
+        """
+        Method get_A gets the value of the minuend.
+
+        :return: Value of the minuend.
+        :rtype: bool
+        """
+        return self.A
+
+    def get_B(self):
+        """
+        Method get_B gets the value of the subtrahend.
+
+        :return: Value of the subtrahend.
+        :rtype: bool
+        """
+        return self.B
+
+    def get_carryOut(self):
+        """
+        Method get_carryOut gets the value of the output carry.
+
+        :return: Value of the output carry.
+        :rtype: bool
+        """
+        return self.carryOut
+
+    def get_output(self):
+        """
+        Method get_output gets the value of the subtraction.
+
+        :return: Result of the sum.
+        :rtype: bool
+        """
+        return self.output
+
+    def get_carryIn(self):
+        """
+        Method get_carryIn gets the value of the input carry. It can only be used on a Full-subtractor object.
+
+        :raises NotCorrectAdder: Raised when a function is called and is not allowed for the instance of an adder used in.
+        :return: Value of the input carry.
+        :rtype: bool
+        """
+        if not self.full:
+            raise NotCorrectAdder('get_carryIn', False)
+
+        return self.carryOut
+
+    def set_A(self, value):
+        """
+        Method set_A sets the value of the minuend to the bool value.
+
+        :param value: Desired value of the minuend.
+        :type value: bool
+        :raises NotTruthValue: Raised when a variable type is not bool.
+        """
+        if type(value) is not bool:
+            raise NotTruthValue
+
+        self.A = value
+        self._calculate_output()
+        return self
+
+    def set_B(self, value):
+        """
+        Method set_B sets the value of the subtrahend to the bool value.
+
+        :param value: Desired value of the subtrahend.
+        :type value: bool
+        :raises NotTruthValue: Raised when a variable type is not bool.
+        """
+        if type(value) is not bool:
+            raise NotTruthValue
+
+        self.B = value
+        self._calculate_output()
+        return self
+
+    def set_carryIn(self, value):
+        """
+        Method set_carryIn sets the value of the carry input to the bool value.
+
+        :param value: Desired value of the subtractor's input carry.
+        :type value: bool
+        :raises NotCorrectAdder: Raised when a function is called and is not allowed for the instance of an adder used in.
+        :raises NotTruthValue: Raised when a variable type is not bool.
+        """
+        if not self.full:
+            raise NotCorrectAdder('set_carryIn', False)
+
+        if type(value) is not bool:
+            raise NotTruthValue
+
+        self.carryIn = value
+        self._calculate_output()
+        return self
+
+    def convert(self):
+        """
+        Method convert is used to transform a full-subtractor into a half-subtractor and vice-versa.
+        """
+        if not self.full:
+            self.full = not self.full
+            self.carryIn = False
+            self._calculate_output()
+        else:
+            self.full = not self.full
+            self.__delattr__(self.carryIn)
+            self._calculate_output()
+
+        return self
+
+    def _calculate_output(self):
+        """
+        Method _calculate_output is a protected method which calculates the value of both carryOut and output signals.
+        It is used for both full and half subtractors.
+        """
+        borrow = And().set_input(0, Not().set_input(self.A).get_output()).set_input(1, self.B).get_output()
+        difference = Xor().set_input(0, self.A).set_input(1, self.B).get_output()
+
+        if not self.full:
+            self.carryOut = borrow
+            self.output = difference
+            return self
+
+        self.output = Xor().set_input(0, difference).set_input(1, self.carryIn).get_output()
+
+        self.carryOut = Or().set_input(0,
+                                       And().set_input(0, self.carryIn).set_input(1,
+                                                                                  Not().set_input(difference)
+                                                                                  .get_output()).get_output())\
+            .set_input(1, borrow).get_output()
+
+        return self
diff --git a/PyCircTools/Operators/__init__.py b/PyCircTools/Operators/__init__.py
index f93ffb4..f16d97c 100644
--- a/PyCircTools/Operators/__init__.py
+++ b/PyCircTools/Operators/__init__.py
@@ -5,3 +5,8 @@
 """
 
 from PyCircTools.Operators.Adder import *
+from PyCircTools.Operators.Subtractor import *
+from PyCircTools.Operators.Alu import *
+from PyCircTools.Operators.Shifter import *
+from PyCircTools.Operators.Extender import *
+from PyCircTools.Operators.Conversor import *


Test patch:
diff --git a/tests/Operators_tests/test_alu.py b/tests/Operators_tests/test_alu.py
new file mode 100644
index 0000000..db36cf2
--- /dev/null
+++ b/tests/Operators_tests/test_alu.py
@@ -0,0 +1,100 @@
+from PyCircTools import Alu
+
+def test_alu_and():
+    alu = Alu()
+    errors = []
+
+    # Checking AND operation and results.
+    alu.set_op([False, False])
+    if alu.set_A(False).set_B(False).get_output():
+        errors.append("0 and 0 error!")
+
+    if alu.set_A(True).get_output():
+        errors.append("1 and 0 error!")
+
+    if alu.set_A(False).set_B(True).get_output():
+        errors.append("0 and 1 error!")
+
+    if not alu.set_A(True).get_output():
+        errors.append("1 and 1 error!")
+
+    assert not errors, "Errors occurred!\n{}".format("\n".join(errors))
+
+
+def test_alu_or():
+    alu = Alu()
+    errors = []
+
+    # Checking OR operation and results
+    alu.set_op([True, False])
+    if alu.set_A(False).set_B(False).get_output():
+        errors.append("0 or 0 error!")
+
+    if not alu.set_A(True).get_output():
+        errors.append("1 or 0 error!")
+
+    if not alu.set_A(False).set_B(True).get_output():
+        errors.append("0 or 1 error!")
+
+    if not alu.set_A(True).get_output():
+        errors.append("1 or 1 error!")
+
+    assert not errors, "Errors occurred!\n{}".format("\n".join(errors))
+
+
+def test_alu_add():
+    half = Alu()
+    errors = []
+
+    # Checking + operation and results
+    half.set_op([False, True])
+    if half.get_output():
+        errors.append("0 + 0 != 1!")
+
+    if half.set_A(True).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("1 + 0 != 0! || carry != 1!")
+
+    if not half.set_B(True).get_output() and half.get_carryOut():
+        pass
+    else:
+        errors.append("1 + 1 != 1! || carry != 0!")
+
+    if half.set_A(False).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("0 + 1 != 0! || carry != 1!")
+
+    assert not errors, "Errors occurred!\n{}".format("\n".join(errors))
+
+
+def test_alu_sub():
+    half = Alu()
+    errors = []
+
+    # Checking - operation and results
+    half.set_op([True, True])
+    if half.set_A(True).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("1 - 0 != 0! || carry != 1!")
+
+    if not half.set_B(True).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("1 - 1 != 1! || carry != 1!")
+
+    if half.set_A(False).get_output() and half.get_carryOut():
+        pass
+    else:
+        errors.append("0 - 1 != 0! || carry != 0!")
+
+    assert not errors, "Errors occurred!\n{}".format("\n".join(errors))
+
+
+if __name__ == '__main__':
+    test_alu_and()
+    test_alu_or()
+    test_alu_add()
+    test_alu_sub()
diff --git a/tests/Operators_tests/test_conversor.py b/tests/Operators_tests/test_conversor.py
new file mode 100644
index 0000000..233a2e0
--- /dev/null
+++ b/tests/Operators_tests/test_conversor.py
@@ -0,0 +1,10 @@
+from PyCircTools import Conversor
+
+
+def test_conversor():
+    conv = Conversor()
+    assert conv.set_input([True, False, True, False]).get_output() == [True, True, False, True]
+
+    _conv = Conversor(8)
+    assert _conv.set_input([False, True, True, True, False, False, False]) == [False, False, False, False, True, True,
+                                                                               True, True]
diff --git a/tests/Operators_tests/test_extender.py b/tests/Operators_tests/test_extender.py
new file mode 100644
index 0000000..e3d736b
--- /dev/null
+++ b/tests/Operators_tests/test_extender.py
@@ -0,0 +1,18 @@
+from PyCircTools import Extender
+
+
+def test_extender():
+    ext = Extender()
+
+    assert ext.set_input([True, True]).get_output() == [True, True, False, False]
+    assert ext.get_numIn() == 2
+    assert ext.get_numOut() == 4
+
+    _ext = Extender(4, 8)
+
+    assert _ext.numInto == 4
+    assert _ext.numOut == 8
+    assert _ext.set_input([False, False, True, False]).get_output() == [False, False, True, False, False, False, False,
+                                                                        False]
+    assert _ext.set_input([True, False, True, True], False).get_output() == [True, False, True, True, True, True, True,
+                                                                             True]
diff --git a/tests/Operators_tests/test_shifter.py b/tests/Operators_tests/test_shifter.py
new file mode 100644
index 0000000..7587b2e
--- /dev/null
+++ b/tests/Operators_tests/test_shifter.py
@@ -0,0 +1,30 @@
+from PyCircTools import Shifter
+
+
+def test_shifter():
+    shift = Shifter()
+
+    assert shift.set_input([True, False, False, False]).set_clock(True).get_output() == [False, True, False, False]
+    assert shift.set_D(True).get_output() == [False, False, False, True]
+    assert shift.set_input([True, True, False, False]).get_input() == [True, True, False, False]
+    assert shift.get_numOfInputs() == 4
+    assert shift.get_D() is True
+    assert shift.get_positions() == 1
+
+    _shift = Shifter(num=16).set_input([False, False, False, False, False, False, False, False, False, False, False,
+                                        False, False, False, False, True]).set_clock(True)
+
+    assert _shift.get_output() == [True, False, False, False, False, False, False, False, False, False, False, False,
+                                   False, False, False, False]
+    assert _shift.set_D(True).get_output() == [False, False, False, False, False, False, False, False, False, False,
+                                               False, False, False, False, True, False]
+
+    _shift3 = Shifter(pos=3).set_input([False, True, False, False]).set_clock(True)
+
+    assert _shift3.get_output() == [True, False, False, False]
+    assert _shift3.set_D(True).get_output() == [False, False, True, False]
+
+    _shift8_4 = Shifter(8, 4, True).set_input([False, False, False, False, False, False, False, True]).set_clock(True)
+
+    assert _shift8_4.get_output() == [False, False, False, True, False, False, False, False]
+    assert _shift8_4.set_D(False).get_output() == [False, False, False, True, False, False, False, False]
diff --git a/tests/Operators_tests/test_subtractor.py b/tests/Operators_tests/test_subtractor.py
new file mode 100644
index 0000000..01d45c0
--- /dev/null
+++ b/tests/Operators_tests/test_subtractor.py
@@ -0,0 +1,88 @@
+from PyCircTools import NotCorrectAdder, Subtractor
+
+
+def test_halfSubtractor():
+    errors = []
+    half = Subtractor()
+
+    if half.get_output():
+        errors.append("0 - 0 != 1!")
+
+    if half.set_A(True).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("1 - 0 != 0! || carry != 1!")
+
+    if not half.set_B(True).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("1 - 1 != 1! || carry != 1!")
+
+    if half.set_A(False).get_output() and half.get_carryOut():
+        pass
+    else:
+        errors.append("0 - 1 != 0! || carry != 0!")
+
+    try:
+        half.set_carryIn(False)
+        errors.append("Shouldn't allow to set carryIn for a half-subtractor!")
+    except NotCorrectAdder:
+        pass
+
+    assert not errors, "errors occured:\n{}".format("\n".join(errors))
+
+
+def test_fullSubtractor():
+    errors = []
+    half = Subtractor(True)
+
+    if half.get_output():
+        errors.append("0 - 0 != 1!")
+
+    if half.set_carryIn(True).get_output() and half.get_carryOut():
+        pass
+    else:
+        errors.append("0 - 0 - 1 error!")
+
+    if half.set_carryIn(False).set_B(True).get_output() and half.get_carryOut():
+        pass
+    else:
+        errors.append("0 - 1 - 0 error!")
+
+    if not half.set_carryIn(True).get_output() and half.get_carryOut():
+        pass
+    else:
+        errors.append("0 - 1 - 1 error!")
+
+    if half.set_carryIn(False).set_A(True).set_B(False).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("1 - 0 - 0 error!")
+
+    if not half.set_carryIn(True).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("1 - 0 - 1 error!")
+
+    if not half.set_carryIn(False).set_B(True).get_output() and not half.get_carryOut():
+        pass
+    else:
+        errors.append("1 - 1 - 0 error!")
+
+    if half.set_carryIn(True).get_output() and half.get_carryOut():
+        pass
+    else:
+        errors.append("1 - 1 - 1 error!")
+
+    try:
+        pass
+    except NotCorrectAdder:
+        half.set_carryIn(False)
+        errors.append("Should allow to set carryIn for a full-adder!")
+
+    assert not errors, "errors occured:\n{}".format("\n".join(errors))
+
+
+if __name__ == '__main__':
+    test_halfSubtractor()
+    test_fullSubtractor()
\ No newline at end of file