QFIE 1.1.0 Release

This notebook aims to illustrate the main changes applied to the QFIE package. As an example the lighting system control introduced in the previous notebook will be considered. Firstly, let us import the required libraries.

[1]:
import numpy as np
import skfuzzy as fuzz
import matplotlib.pyplot as plt
import QFIE.FuzzyEngines as FE

The system is a MISO composed of two input variables and one output variable. In detail:

Inputs:

  • Environment Light (env_light): three linguistic terms are considered: ‘Dark’, ‘Medium’, ‘Light’

  • Changing Rate (change_rate): three lingiuistic terms are considered: ‘Negative Small’, ‘Zero’, ‘Positive Small’

Output:

  • Dimmer Control (dimmer_ctrl): four linguistic terms are considered: ‘Very Small’, ‘Small’, ‘Big’, ‘Very Big’

By running the following cell, the fuzzy sets used are graphically shown.

[2]:
env_light = np.linspace(120, 220, 200)
changing_rate = np.linspace(-10, 10, 200)
dimmer_control = np.linspace(0, 10, 200)



l_dark = fuzz.trapmf(env_light, [120,120,130,150])
l_medium = fuzz.trapmf(env_light, [130,  150, 190,210])
l_light = fuzz.trapmf(env_light, [190,  210, 220, 220])

r_ns = fuzz.trimf(changing_rate, [-10,-10,0])
r_zero = fuzz.trimf(changing_rate, [-10,0,10])
r_ps = fuzz.trimf(changing_rate, [0,10,10])

dm_vs = fuzz.trapmf(dimmer_control, [0,0,2,4])
dm_s = fuzz.trimf(dimmer_control, [2,4,6])
dm_b = fuzz.trimf(dimmer_control, [4,6,8])
dm_vb = fuzz.trapmf(dimmer_control, [6,8,10,10])




# Visualize these universes and membership functions
fig, (ax0, ax1, ax2) = plt.subplots(nrows=3, figsize=(10, 12))


ax0.plot(env_light, l_dark, 'b', linewidth=1.5, label='dark')
ax0.plot(env_light, l_medium, 'g', linewidth=1.5, label='medium')
ax0.plot(env_light, l_light, 'r', linewidth=1.5, label='light')
ax0.set_title('Environment Light')
ax0.legend()

ax1.plot(changing_rate, r_ns, 'b', linewidth=1.5, label='negative small')
ax1.plot(changing_rate, r_zero, 'g', linewidth=1.5, label='zero')
ax1.plot(changing_rate, r_ps, 'r', linewidth=1.5, label='positive small')
ax1.set_title('Changing Rate')
ax1.legend()


ax2.plot(dimmer_control, dm_vs, 'b', linewidth=1.5, label='very small')
ax2.plot(dimmer_control, dm_s, 'g', linewidth=1.5, label='small')
ax2.plot(dimmer_control, dm_b, 'r', linewidth=1.5, label='big')
ax2.plot(dimmer_control, dm_vb, 'y', linewidth=1.5, label='very big')
ax2.set_title('Dimmer control')
ax2.legend()

# Turn off top/right axes
for ax in (ax0, ax1, ax2):
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()


plt.show()
_images/QFIE_v_1_1_0_3_0.png

The rules base of the system is composed of the following rules:

  • if env_light is dark and change_rate is pos_small then dimmer_ctrl is big

  • if env_light is dark and change_rate is zero then dimmer_ctrl is big

  • if env_light is dark and change_rate is neg_small then dimmer_ctrl is very_big

  • if env_light is medium and change_rate is pos_small then dimmer_ctrl is small

  • if env_light is medium and change_rate is zero then dimmer_ctrl is big

  • if env_light is medium and change_rate is neg_small then dimmer_ctrl is big

  • if env_light is light and change_rate is pos_small then dimmer_ctrl is very_small

  • if env_light is light and change_rate is zero then dimmer_ctrl is small

  • if env_light is light and change_rate is neg_small then dimmer_ctrl is big

By running the following two cells QFIE is properly initialized

[3]:
rules = ['if env_light is dark and change_rate is pos_small then dimmer_ctrl is big',
         'if env_light is dark and change_rate is zero then dimmer_ctrl is big',
         'if env_light is dark and change_rate is neg_small then dimmer_ctrl is very_big',
         'if env_light is medium and change_rate is pos_small then dimmer_ctrl is small',
         'if env_light is medium and change_rate is zero then dimmer_ctrl is big',
         'if env_light is medium and change_rate is neg_small then dimmer_ctrl is big',
         'if env_light is light and change_rate is pos_small then dimmer_ctrl is very_small',
         'if env_light is light and change_rate is zero then dimmer_ctrl is small',
         'if env_light is light and change_rate is neg_small then dimmer_ctrl is big']

Firstly, let us initialize the QuantumFuzzyEngine class defined in FE. By setting verbose=True we will get information about the inference during the computation. Set verbose=False if this information is unuseful in your application.

[4]:
qfie = FE.QuantumFuzzyEngine(verbose=True)

The way in which input and output variables are passed to QFIE remains unchanged:

[5]:
qfie.input_variable(name='env_light', range=env_light)
qfie.input_variable(name='change_rate', range=changing_rate)
qfie.output_variable(name='dimmer_ctrl', range=dimmer_control)

qfie.add_input_fuzzysets(var_name='env_light', set_names=['dark', 'medium', 'light'], sets=[l_dark, l_medium, l_light])
qfie.add_input_fuzzysets(var_name='change_rate', set_names=['neg_small', 'zero', 'pos_small'], sets=[r_ns, r_zero, r_ps])
qfie.add_output_fuzzysets(var_name='dimmer_ctrl', set_names=['very_small', 'small', 'big', 'very_big'],sets=[dm_vs, dm_s, dm_b, dm_vb])
qfie.set_rules(rules)


The main difference in the new version of QuantumFuzzyEngine is the fact that any backend can be used to compute the quantum circuit. Now the backend is passed as argument of the execute method as Qiskit Backend object, instead that as string.

Let see an example by running an inference process.

[6]:
el, cr = 140, -5
qfie.build_inference_qc({'env_light':el, 'change_rate':cr}, draw_qc=True, filename='qc_plot.png')

{'env_light': 140, 'change_rate': -5}
Input values  {'env_light': [0.5, 0.5, 0.0], 'change_rate': [0.5, 0.5, 0.0]}
/Users/rschiattarella/Projects/QFIE_Package/src/QFIE/FuzzyEngines.py:277: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.
  self.qc["full_circuit"].draw("mpl", filename=kwargs["filename"]).show()

By specifying the filename in the build_inference_qc method a png file containing the quantum circuit plot is created. This is particularly useful when the size of the quantum circuit is big and visualization problems during the execution arise. If filename isn’t specified the quantum circuit is shown but not saved.

a5286f6dc39146c7a4985684dcd21150

At this point the generated QC can be executed with the execute method. If not backend is specified then the qc is running by using the Qiskit local QasmSimulator. Any backend can be specified and used. As an example the following execution is carried out by using the noisy FakeMumbai() simulator.

[7]:
from qiskit.providers.fake_provider import FakeMumbai
qfie.execute(n_shots=1000,  backend=FakeMumbai())[0]
Running qc full_circuit on fake_mumbai
Output Counts {'0001': 0.09833333333333333, '0010': 0.176, '0100': 0.32766666666666666, '1000': 0.191}
[7]:
5.613499478403967

Distributed-QFIE (D-QFIE)

Another important change in the new release of QFIE package is the possibility of using the Distributed QFIE algorithm introduced in the paper submitted as proceeding for FUZZ-IEEE 2023’ Distributing Fuzzy Inference Engines on Quantum Computers - Acampora Giovanni, Massa Alfredo, Schiattarella Roberto, Vitiello Autilia’.

Here the inference process is distributed over more quantum circuits, one for each possible consequent of the system.

This part of the notebook is dedicated to see how D-QFIE can be used as part of the QFIE package.

In this particular control system the output variable is composed of four linguistic terms, therefore four quantum circuits will be created. To activate the D-QFIE inference process use the related flag in build_inference_qc method as follows:

[11]:
qfie = FE.QuantumFuzzyEngine(verbose=True)
qfie.input_variable(name='env_light', range=env_light)
qfie.input_variable(name='change_rate', range=changing_rate)
qfie.output_variable(name='dimmer_ctrl', range=dimmer_control)

qfie.add_input_fuzzysets(var_name='env_light', set_names=['dark', 'medium', 'light'], sets=[l_dark, l_medium, l_light])
qfie.add_input_fuzzysets(var_name='change_rate', set_names=['neg_small', 'zero', 'pos_small'], sets=[r_ns, r_zero, r_ps])
qfie.add_output_fuzzysets(var_name='dimmer_ctrl', set_names=['very_small', 'small', 'big', 'very_big'],sets=[dm_vs, dm_s, dm_b, dm_vb])
qfie.set_rules(rules)


qfie.build_inference_qc({'env_light':el, 'change_rate':cr}, distributed=True, draw_qc=True, filename='d_qc.png')
{'env_light': 140, 'change_rate': -5}
Input values  {'env_light': [0.5, 0.5, 0.0], 'change_rate': [0.5, 0.5, 0.0]}

By specifying the filename four quantum circuit figures will be saved at the path indicated.

53b50bbb9da54766b3ec14a9943136e5 055a4b83fe0a40de94e407e64ce07a71 1331f009f60c483982e789b8c5d0dc55 289956014b65463d8de1120d8b848ab2

By running the execute method the quantum circuits will be executed and the outputs aggregated in order to obtain the crisp output value. If not backend is specified, then all the quantum circuits will be simulated by means of the noiseless QasmSimulator.

[12]:
qfie.execute(n_shots=1000)[0]
Running qc very_small on qasm_simulator
Running qc small on qasm_simulator
Running qc big on qasm_simulator
Running qc very_big on qasm_simulator
Output Counts {'0001': 0.0, '0010': 0.0, '0100': 0.7519762845849802, '1000': 0.24802371541501977}
[12]:
6.657587913604732

Alternatively, a list of backend can be specified and the quantum circuits will be computed on them.

[13]:
from qiskit.providers.fake_provider import FakeMumbai, FakeMontreal
qfie.execute(n_shots=1000, backend=[FakeMontreal(), FakeMumbai()])[0]
Running qc very_small on fake_montreal
Running qc small on fake_mumbai
Running qc big on fake_montreal
Running qc very_big on fake_mumbai
Output Counts {'0001': 0.09771309771309772, '0010': 0.3277893277893278, '0100': 0.35135135135135137, '1000': 0.22314622314622315}
[13]:
5.468974659317126

The differences in output computation are related to the noise affecting the circuits simulations by using IBM Fake devices.

The usage of D-QFIE is strongly suggested when noisy devices are used to compute QFIE.