Introduzione a Python

https://www.python.org

Potete trovare questa lezione (ed altre) sul mio sito github:

https://github.com/EnricoGiampieri/lezionipython

un ottimo tutorial online lo potete trovare alla pagina:

http://www.scipy-lectures.org/

Il Python è un linguaggio interpretato di alto livello.

Questa è una maniera complicata per dire che evita moltissimi dei dolori della programmazione classica: il fatto che sia interpretato significa che non sono necessari step di compilazione, rendendo più semplice il ciclo sviluppo - esecuzione - correzione

Python ha come principale linea guida il concetto di leggibilità, cercando il più possibile di rendere semplice agli sviluppatori scrivere librerie semplici ed intuitive.

Questo permette di utilizzare soltanto python per sviluppare i prototipi del codice fino ad arrivare al codice di produzione, semplificando e velocizzando l'intero processo che parte dall'idea che si vuole implementare fino ad ottenere il risultato finale.

Python supporta di base tutte le operazioni matematiche più comuni, compreso il supporto per la matematica complessa, e tutti i costrutti più comuni di programmazione (e molti altri) come:

  • if, elif, else
  • cicli for e while
  • definizione di funzioni e classi

Permette inoltre di programmare con molti approcci diversi:

  • procedurale
  • ad oggetti
  • funzionale
  • vettoriale

Faremo una breve introduzione alla programmazione in pyhton, senza entrare nel dettaglio delle caratteristiche del linguaggio, introducendo quindi solo una parte delle possibilità offerte da questo linguaggio e dalle sue librerie.

Conoscere un minimo di python e delle sue librerie di calcolo numerico ci permetterà di toccare con mano molti dei problemi che affronteremo lungo il corso.


Utilizzare Python

Esistono molti modi diversi di lavorare tramite Python.

Il fondamentale è tramite la shell di python, un terminale che esegue le righe di comando mano a mano che vengono inserite, ed è estremamente utile per testare il codice al volo prima di inserirlo dentro un programma. Il terminale di python si può lanciare da terminale digitando python.

>>> Dimostrazione

Il secondo metodo è scrivere uno (o più) script contenente i comandi che si vogliono eseguire, e farlo eseguire da python come un programma qualsiasi tramite il comando

python nomedelfile.py.

Le cose più interessanti di trovano però andando a cercare fra i vari programmi disponibili.

Uno degli editor più famosi per il calcolo scientifico in python è Spyder (http://code.google.com/p/spyderlib/), che fornisce un'interfaccia molto simile a quella di Matlab. È unprogramma molto solido e funzionale, ed è un'ottima piattaforma su cui lavorare.

Un'altro approccio è l'utilizzo di un IDE (Integrated Development Environment) completo, quale PyCharm, Wing o Eclipse. Il mio personale preferito, molto più semplice ma con tutte le funzioni che mi servono è Ninja (http://ninja-ide.org/).

Fra tutti lo strumento però in assoluto più potente è sicuramente Jupyter (http://jupyter.org/). Jupyter fornisce tre programmi:

  • la IPython shell, che è descrivibile come un terminale python sotto steroidi, che può tranquillamente sostituire la shell di sistema
  • La QTConsole, che contiene un ibrido fra una shell ed un sistema di gestione tramite GUI, e permette l'utilizzo dei grafici inline invece che in finestre separate.
  • Il Notebook, ovvero quello che stò usando in questo momento, che è un'interfaccia web ad un serve di esecuzione che permette di mescolare testo, codice, grafica e formule in un unico insieme. In particolare quello che stò usando in questo momento è la versione 3.6 di IPython

Procurarsi python

Python arriva di base installato con un gran numero di librerie sia sotto linux che sotto macOSX, mentre invece và installato da zero su windows.

Installare nuove librerie è molto semplice sfruttando il programma pip, che permette di dire a python quale libreria si desidera e lui la scaricherà ed installerà sul sistema. Il programma è a riga di comando e quasi tutte le librerie numeriche richiedono però la presenza di un compilatore, quindi potrebbe non essere comodo per chi non è abituato a lavorare da terminale.

Una comoda alternativa sono le librerie all-inclusive. Queste sono normalmente a pagamento, ma arrivano con python e tantissime librerie preinstallate e configurate per il sistema in uso. Fra le principali ci sono:

  • Anaconda, concorrente moderno della EPD, è gratuita e forse la migliore disponibile al momento
  • Python(x, y), gratuito e ben testato, ma purtroppo presente solo per windows
  • Sage, completamente gratuito, che comprende oltre a python anche un gran numero di programmi per la matematica accessibili da tramite python

Se invece non volete installarlo nel vostro computer ma solo provarlo online (tipicamente sono piani a pagamento o gratuiti in modo ristretto):

se volete tenervi aggiornati sulle novità del mondo Python, due buone newletters sono:

Andremo a visualizzare parte del nostro codice anche sul sito Python Tutor, che ci aiuterà a capire cosa sta succedendo


Basi del linguaggio

Vediamo subito il primo programma di default, Hello World:

In [35]:
print("not Hello, World!")
not Hello, World!

Ok, questo era facile. Possiamo usare la funzione print per stampare (quasi) qualsiasi cosa:intanto lo usiamo per vedere i risultati di alcune operazioni matematiche

In [36]:
print(1)
print(1 + 2)
print((4 + 5j) * (2 + 3j))
print(4 ** 4)
1
3
(-7+22j)
256

Nelle vecchie versioni di Python (2.7 o inferiori) la divisione fra numeri interi restituiva un intero (come in C). Nella nuova versione (python 3, quello che utilizzeremo per queste lezioni) questo comportamento è stato modificato, ed ora la divisione fra numeri restituisce il valore decimale come ci si attenderebbe

In [37]:
2 / 3
Out[37]:
0.6666666666666666

Per avere la divisione intera si utilizza un operatore specifico, usando il doppio segno di divisione.

In [38]:
2 // 3
Out[38]:
0

Per ottenere le stesso comportamento nelle vecchie versioni si può utilizzare il comando:

from __future__ import division
In [ ]:
from __future__ import division, print_function

Per utilizzare funzioni matematiche più avanzate abbiamo bisogno di utilizzare una delle librerie che arrivano con python, la libreria math, che ci mette a disposizione una lunga lista di funzioni. per utilizzare math basta scrivere

In [1]:
import math
There's an app for that!

Ed ora abbiamo accesso a tutte le funzioni necessarie. Se avessimo bisogno di lavorare con i numeri complessi, esiste una libreria gemella chiamata cmath.

Per avere più informazioni sulla libreria che andiamo ad usare possiamo utilizzare due comandi molto utili, dir per sapere quali siano le sue funzioni, ed help per averne una descrizione. Visto che il risultato di help(math) è piuttosto lungo, eviterò di mostrarlo.

In [3]:
print(dir(math))
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']

dir mi ritorna una lista con i nomi di tutte le funzioni presenti dento math. Per usarle basta scrivere

nomelibreria.nomefunzione
In [41]:
math.exp(1)
Out[41]:
2.718281828459045

Se voglio sapere cosa faccia di preciso una di quelle funzioni basta usare la funzione help

In [42]:
help(math.log1p)
Help on built-in function log1p in module math:

log1p(...)
    log1p(x)
    
    Return the natural logarithm of 1+x (base e).
    The result is computed in a way which is accurate for x near zero.

In [43]:
print(math.pi)
print(math.log1p(math.pi))
3.141592653589793
1.4210804127942926
In [44]:
math.log( math.pi + 1.0 )
Out[44]:
1.4210804127942926

Se avete bisogno di poche funzioni e non volete digitare ogni volta il nome della libreria potete importare solo una parte dei nomi, che saranno poi disponibili senza bisogno di fare riferimenti alla librerie.

In [45]:
from math import radians, log1p, modf

print(log1p(1.0))
0.6931471805599453

Potreste trovare alcuni tutorial su internet che propongono di importare le funzioni da una libreria con il seguente comando:

from math import *

Evitatelo come la peste.

Questo comando importa infatti tutti i nomi di funzioni dalla libreria, sovrascrivendo possibili funzioni già esistenti. Questo comportamento potrebbe riservarvi delle sorprese molto spiacevoli, e di cui è difficile rendersi conto!

Inclusi nel linguaggio di base arrivano anche molte strutture dati estremanente utili. Una lista non esaustiva include:

  • liste
  • stringhe
  • set
  • dizionari
  • deque
  • heap

Una menzione particolare la meritano i dizionari, che permettono di memorizzare dei dati in modalità random (ovvero non sequenziale) accedendovi tramite nomi esplicativi

In [46]:
rubrica = dict()
rubrica['Ludovico Fabbri'] = ('334-5678901', 
                              'Via Larga 34, Bo')
print(rubrica['Ludovico Fabbri'])
('334-5678901', 'Via Larga 34, Bo')

Se provo a cercare un elemento assente, Python si lamenta in modo rumoroso.

Questo è un design intenzionale, meglio fallire presto in modo chiaro che non dare risultati inaspettati!

In [48]:
rubrica['enrico giampieri']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-48-353ef568a7d1> in <module>()
----> 1 rubrica['enrico giampieri']

KeyError: 'enrico giampieri'
In [47]:
try:
    print(rubrica['enrico giampieri'])
except KeyError:
    print("non trovato")
non trovato

funzioni

È possibile definire le proprie funzioni tramite il comando def. In questo caso creerò una funzione che prende due oggetti e ne restituisce la somma.

A python non interessa di che oggetti di tratti, fintantochè sia definita fra di loro una somma. Posso usare questa funzione per sommare indifferentemente fra di loro numeri, stringhe, liste o distribuzioni di probabilità.

In [50]:
def mia_funzione(a, b):
    return a+b

print(mia_funzione(1, 2))
print(mia_funzione('hello ', 'world!'))
print(mia_funzione([1, 2, 3], [4, 5, 6]))
3
hello world!
[1, 2, 3, 4, 5, 6]

iterazioni

Python supporta le iterazioni sia con il costrutto while che con il for. Il for in pyhton è un ciclo speciale estremamente potente, ed è quindi il modo principale di scrivere cicli.

Nel classico modo di scrivere cicli, per scorrere una lista di oggetti devo fare un ciclo sopra gli indici della lista, stando attento a trovare bene i bordi, e poi operare sul mio oggetto. Prendiamo ad esempio il caso di voler stampare tutto il contenuto di una lista.

In [ ]:
lista_ingredienti = ['pane', 'pomodori', 'farina', 'acqua', 'sale', 'mozzarella']
lunghezza = len(lista_ingredienti)
idx = 0
while idx < lunghezza:
    print(lista_ingredienti[idx])
    idx += 1

Due delle linee di questo codice (trovare la lunghezza della lista e ricavarne l'elemento) sono sempre presenti. Per ovviare a queste linee superflue, il python permette di usare il ciclo for per scorrere direttamente gli elementi della lista

In [51]:
lista_ingredienti = ("acqua", "farina")
for ingrediente in lista_ingredienti:
    print(ingrediente)
acqua
farina

una funzione usata molto comunemente all'interno dei cicli è la funzione zip, che serve per fare il ciclo contemporaneamente su due liste/stringhe allo stesso momento.

In [36]:
nome = 'enrico'

for ch1, ch2 in zip(nome, nome[1:]):
    print(ch1, ch2)
e n
n r
r i
i c
c o

Se voglio leggere un file ho a disposizione la funzione open.

Questa funzione può essere usata per delimitare un blocco di codice all'interno del quale il file è aperto. Al termine delle operazioni, questo verrò chiuso in modo automatico e sicuro, evitando che rimanga aperto e venga corrotto da altri processi

In [1]:
%%file prova.txt
tonno
mandibola
rum
pinocchio
sigmoide
Writing prova.txt
In [4]:
with open('prova.txt') as file: #commento
    for line in file:
        print(repr(line))
        print(len(line))
'tonno\n'
6
'mandibola\n'
10
'rum\n'
4
'pinocchio\n'
10
'sigmoide'
8
In [5]:
import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Automi cellulari

Proviamo a sviluppare un semplice automa cellulare, basato sui metodi delinieati da Wolfram.

Il nostro sistema è una stringa di bit uno e zero, con delle regole di evoluzione basate sullo stato del bit e dei suoi vicini.

Useremo la regola 30, ispirato da questo blog

In [56]:
rule30 = {"000": ' ',
          "00 ": ' ',
          "0 0": ' ',
          "   ": ' ',
          "0  ": '0',
          " 00": '0',
          " 0 ": '0',
          "  0": '0',
         }
In [57]:
stato = '                    0                    '
In [58]:
result = []
for a,b,c in zip(stato[:-2], stato[1:-1], stato[2:]):
    abc = a+b+c
    r = rule30[abc]
    result.append(r)
print(''.join(result))
                  000                  
In [59]:
len(stato), len(result)
Out[59]:
(41, 39)
In [60]:
def avanza(stato, regola):
    risultato = []
    stato = ' '+stato+' '
    for a,b,c in zip(stato[:-2], stato[1:-1], stato[2:]):
        abc = a+b+c
        r = rule[abc]
        risultato.append(r)
    return ''.join(risultato)

avanza(stato, rule30)
Out[60]:
'                   000                   '
In [61]:
iniziale = '                    0                    '
stato = iniziale
for i in range(50):
    print(stato.replace('0', '\u2588'))
    stato = avanza(stato, rule30)
                    █                    
                   ███                   
                  ██  █                  
                 ██ ████                 
                ██  █   █                
               ██ ████ ███               
              ██  █    █  █              
             ██ ████  ██████             
            ██  █   ███     █            
           ██ ████ ██  █   ███           
          ██  █    █ ████ ██  █          
         ██ ████  ██ █    █ ████         
        ██  █   ███  ██  ██ █   █        
       ██ ████ ██  ███ ███  ██ ███       
      ██  █    █ ███   █  ███  █  █      
     ██ ████  ██ █  █ █████  ███████     
    ██  █   ███  ████ █    ███      █    
   ██ ████ ██  ███    ██  ██  █    ███   
  ██  █    █ ███  █  ██ ███ ████  ██  █  
 ██ ████  ██ █  ██████  █   █   ███ ████ 
██  █   ███  ████     ████ ███ ██   █   █
█ ████ ██  ███   █   ██    █   █ █ ███ ██
█ █    █ ███  █ ███ ██ █  ███ ██ █ █   █ 
█ ██  ██ █  ███ █   █  ████   █  █ ██ ███
█ █ ███  ████   ██ █████   █ █████ █  █  
█ █ █  ███   █ ██  █    █ ██ █     █████ 
█ █ ████  █ ██ █ ████  ██ █  ██   ██    █
█ █ █   ███ █  █ █   ███  ████ █ ██ █  ██
█ █ ██ ██   ████ ██ ██  ███    █ █  ████ 
█ █ █  █ █ ██    █  █ ███  █  ██ ████   █
█ █ ████ █ █ █  █████ █  ██████  █   █ ██
█ █ █    █ █ ████     ████     ████ ██ █ 
█ █ ██  ██ █ █   █   ██   █   ██    █  ██
█ █ █ ███  █ ██ ███ ██ █ ███ ██ █  █████ 
█ █ █ █  ███ █  █   █  █ █   █  ████    █
█ █ █ ████   █████ █████ ██ █████   █  ██
█ █ █ █   █ ██     █     █  █    █ █████ 
█ █ █ ██ ██ █ █   ███   ██████  ██ █    █
█ █ █ █  █  █ ██ ██  █ ██     ███  ██  ██
█ █ █ ███████ █  █ ███ █ █   ██  ███ ███ 
█ █ █ █       ████ █   █ ██ ██ ███   █  █
█ █ █ ██     ██    ██ ██ █  █  █  █ █████
█ █ █ █ █   ██ █  ██  █  ██████████ █    
█ █ █ █ ██ ██  ████ ██████          ██   
█ █ █ █ █  █ ███    █     █        ██ █  
█ █ █ █ ████ █  █  ███   ███      ██  ██ 
█ █ █ █ █    ███████  █ ██  █    ██ ███ █
█ █ █ █ ██  ██      ███ █ ████  ██  █   █
█ █ █ █ █ ███ █    ██   █ █   ███ ████ ██
█ █ █ █ █ █   ██  ██ █ ██ ██ ██   █    █ 
In [62]:
def avanza(stato, regola, bordo='circolare'):
    risultato = []
    if bordo=='circolare':
        stato = stato[-1]+stato+stato[0]
    elif bordo=='riflettente':
        stato = stato[0]+stato+stato[-1]
    else:
        stato = borso+stato+bordo
    for a,b,c in zip(stato[:-2], stato[1:-1], stato[2:]):
        abc = a+b+c
        r = rule[abc]
        risultato.append(r)
    return ''.join(risultato)
In [63]:
iniziale = '                    0                    '
stato = iniziale
for i in range(50):
    print(stato.replace('0', '\u2588'))
    stato = avanza(stato, rule30)
                    █                    
                   ███                   
                  ██  █                  
                 ██ ████                 
                ██  █   █                
               ██ ████ ███               
              ██  █    █  █              
             ██ ████  ██████             
            ██  █   ███     █            
           ██ ████ ██  █   ███           
          ██  █    █ ████ ██  █          
         ██ ████  ██ █    █ ████         
        ██  █   ███  ██  ██ █   █        
       ██ ████ ██  ███ ███  ██ ███       
      ██  █    █ ███   █  ███  █  █      
     ██ ████  ██ █  █ █████  ███████     
    ██  █   ███  ████ █    ███      █    
   ██ ████ ██  ███    ██  ██  █    ███   
  ██  █    █ ███  █  ██ ███ ████  ██  █  
 ██ ████  ██ █  ██████  █   █   ███ ████ 
██  █   ███  ████     ████ ███ ██   █   █
  ████ ██  ███   █   ██    █   █ █ ███ ██
███    █ ███  █ ███ ██ █  ███ ██ █ █   █ 
█  █  ██ █  ███ █   █  ████   █  █ ██ ██ 
███████  ████   ██ █████   █ █████ █  █  
█      ███   █ ██  █    █ ██ █     ██████
 █    ██  █ ██ █ ████  ██ █  ██   ██     
███  ██ ███ █  █ █   ███  ████ █ ██ █    
█  ███  █   ████ ██ ██  ███    █ █  ██  █
 ███  ████ ██    █  █ ███  █  ██ ████ ███
 █  ███    █ █  █████ █  ██████  █    █  
█████  █  ██ ████     ████     ████  ███ 
█    ██████  █   █   ██   █   ██   ███   
██  ██     ████ ███ ██ █ ███ ██ █ ██  █ █
  ███ █   ██    █   █  █ █   █  █ █ ███ █
███   ██ ██ █  ███ █████ ██ █████ █ █   █
   █ ██  █  ████   █     █  █     █ ██ ██
█ ██ █ ██████   █ ███   ██████   ██ █  █ 
█ █  █ █     █ ██ █  █ ██     █ ██  ████ 
█ ████ ██   ██ █  ████ █ █   ██ █ ███    
█ █    █ █ ██  ████    █ ██ ██  █ █  █  █
  ██  ██ █ █ ███   █  ██ █  █ ███ ███████
███ ███  █ █ █  █ █████  ████ █   █      
█   █  ███ █ ████ █    ███    ██ ███    █
 █ █████   █ █    ██  ██  █  ██  █  █  ██
 █ █    █ ██ ██  ██ ███ ██████ █████████ 
██ ██  ██ █  █ ███  █   █      █        █
   █ ███  ████ █  ████ ███    ███      ██
█ ██ █  ███    ████    █  █  ██  █    ██ 
█ █  ████  █  ██   █  ████████ ████  ██  
In [64]:
def avanza(stato, regola, bordo='circolare'):
    if bordo=='circolare':
        stato = stato[-1] + stato + stato[0]
    elif bordo=='riflettente':
        stato = stato[0] + stato + stato[-1]
    else:
        stato = bordo[0] + stato + bordo[0]
    
    space = zip(stato[:-2], stato[1:-1], stato[2:])
    risultato = [rule[a+b+c] for a,b,c in space]
    return ''.join(risultato)
In [65]:
iniziale = '                    0                    '
stato = iniziale
for i in range(50):
    print(stato.replace('0', '\u2588'))
    stato = avanza(stato, rule30, bordo='riflettente')
                    █                    
                   ███                   
                  ██  █                  
                 ██ ████                 
                ██  █   █                
               ██ ████ ███               
              ██  █    █  █              
             ██ ████  ██████             
            ██  █   ███     █            
           ██ ████ ██  █   ███           
          ██  █    █ ████ ██  █          
         ██ ████  ██ █    █ ████         
        ██  █   ███  ██  ██ █   █        
       ██ ████ ██  ███ ███  ██ ███       
      ██  █    █ ███   █  ███  █  █      
     ██ ████  ██ █  █ █████  ███████     
    ██  █   ███  ████ █    ███      █    
   ██ ████ ██  ███    ██  ██  █    ███   
  ██  █    █ ███  █  ██ ███ ████  ██  █  
 ██ ████  ██ █  ██████  █   █   ███ ████ 
██  █   ███  ████     ████ ███ ██   █   █
  ████ ██  ███   █   ██    █   █ █ ███ ██
 ██    █ ███  █ ███ ██ █  ███ ██ █ █   █ 
██ █  ██ █  ███ █   █  ████   █  █ ██ ███
   ████  ████   ██ █████   █ █████ █  █  
  ██   ███   █ ██  █    █ ██ █     █████ 
 ██ █ ██  █ ██ █ ████  ██ █  ██   ██    █
██  █ █ ███ █  █ █   ███  ████ █ ██ █  ██
  ███ █ █   ████ ██ ██  ███    █ █  ████ 
 ██   █ ██ ██    █  █ ███  █  ██ ████   █
██ █ ██ █  █ █  █████ █  ██████  █   █ ██
   █ █  ████ ████     ████     ████ ██ █ 
  ██ ████    █   █   ██   █   ██    █  ██
 ██  █   █  ███ ███ ██ █ ███ ██ █  █████ 
██ ████ █████   █   █  █ █   █  ████    █
   █    █    █ ███ █████ ██ █████   █  ██
  ███  ███  ██ █   █     █  █    █ █████ 
 ██  ███  ███  ██ ███   ██████  ██ █    █
██ ███  ███  ███  █  █ ██     ███  ██  ██
   █  ███  ███  ██████ █ █   ██  ███ ███ 
  █████  ███  ███      █ ██ ██ ███   █  █
 ██    ███  ███  █    ██ █  █  █  █ █████
██ █  ██  ███  ████  ██  ██████████ █    
   ████ ███  ███   ███ ███          ██   
  ██    █  ███  █ ██   █  █        ██ █  
 ██ █  █████  ███ █ █ ██████      ██  ██ 
██  ████    ███   █ █ █     █    ██ ███ █
  ███   █  ██  █ ██ █ ██   ███  ██  █   █
 ██  █ █████ ███ █  █ █ █ ██  ███ ████ ██
██ ███ █     █   ████ █ █ █ ███   █    █ 
In [ ]:
RULES = {30: {"111": '0', "110": '0', "101": '0', "000": '0',
              "100": '1', "011": '1', "010": '1', "001": '1'},

         90: {"111": "0", "110": "1", "101": "0", "100": "1",
              "011": "1", "010": "0", "001": "1", "000": "0"},

         110: {"111": '0', "110": '1', "101": '1', "100": '0',
               "011": '1', "010": '1', "001": '1', "000": '0'},

         184: {"111": "1", "110": "0", "101": "1", "100": "1",
               "011": "1", "010": "0", "001": "0", "000": "0"}
         }