Fonctions booléennes
Les opérations ensemblistes
Proposition. Étant donné un ensemble fini
à éléments, et une énumération des éléments de , la fonction : définit une bijection de
dans .
En utilisant l’isomorphisme de la proposition, qui établit une bijection entre les mots binaires de longueur
-
Négation
: complémentaire d’un sous-ensemble , noté . . -
Conjonction
: l’intersection de deux sous-ensembles et . . -
Disjonction
: l’union de deux sous-ensembles et . . -
Implication (
) : l’union du complémentaire de avec .
. -
Équivalence (
) : l’union des parties où et ont les mêmes éléments (soit tous deux présents, soit tous deux absents).
. -
Disjonction exclusive (
) : la différence symétrique entre et , qui regroupe les éléments présents dans un seul des deux ensembles, mais pas dans les deux simultanément.
.
Fonctions bouléennes
Nombre d’opérations booléennes -aires et de fonctions
- Nombre d’opérations booléennes
-aires : Une opération booléenne -aire est une fonction , où est l’ensemble des valeurs booléennes. Le nombre total de telles fonctions est donné par le nombre d’assignations possibles de valeurs de vérité pour entrées (les combinaisons des variables booléennes) vers . Il y a donc fonctions booléennes -aires. - Une fonction de
vers associe à chaque entrée de une sortie dans . Ce qui équivaut à décrire fonctions indépendantes . Le nombre total de telles fonctions est alors .
Écriture de toute opération booléenne en termes des constantes 0, 1, , , et
Preuve :
Montrons que toute opération booléenne peut être exprimée en utilisant
On sait que toute fonction booléenne
-
Pour chaque combinaison
où , on construit un minterme :où chaque
est pris tel qu’il correspond à la valeur de la variable dans cette ligne de la table. -
La fonction
est exprimée comme une disjonction de ces mintermes :Les constantes
et représentent les cas triviaux où (fonction nulle, aucun minterme) ou (fonction toujours vraie).
Le -aire en utilisant fois le binaire
L’opération
Diviser les
Le nombre total d’applications nécessaires est donc la somme des termes d’une progression géométrique :
Peut-on faire mieux ?
Si
Codages binaires de longueur fixée
Quelques Définitions
-
l’ensemble des mots de longueur fixe sur l’alphabet :Par exemple si
et , alors . est utile pour représenter des messages ou codes de taille fixée, par exemple dans les codages à longueur fixe. -
est l’ensemble des mots de longueur arbitraire (y compris nulle) sur l’alphabet :Ce qui inclut:
- Les mots de longueur
, c’est-à-dire l’ensemble où est le mot vide. - Les mots de longueur
( simplement ). - Les mots de longueur
pour tout .
Par exemple : si
, alors . est plus général et utilisé pour représenter des messages de longueur variable, comme dans les codages préfixes. - Les mots de longueur
-
Soit
un ensemble fini. Une convention de codage sur bits des éléments de est définie par:- une fonction de codage
, et - une fonction partielle de décodage
, telles que :
Un code de
selon est n’importe quelle préimage telle que . La fonction sélectionne un de ces codes.-
o est l’identité sur , deux éléments distincts de ne peuvent avoir la même image par . Ce qui impose que est injective. n’est pas nécessairement surjective. Certains mots binaires de peuvent ne pas correspondre au codage d’un élément de .
-
Tout élément de
possède au moins un code, donc est surjective. n’est pas toujours totalement définie. Il peut exister des mots binaires dans qui ne décodent aucun élément de .- Un même élément de
peut être associé à plusieurs mots binaires par . La correspondance n’est donc pas forcément univoque pour la fonction de décodage.
- une fonction de codage
À quelle condition un ensemble peut-il admettre un codage sur bits ?
Un ensemble
En effet, un mot binaire de longueur
Dès que est non vide, toute convention de codage peut être étendue pour que la fonction de décodage soit totale.
Une fonction de décodage
est dite totale si elle est définie pour tous les mots binaires possibles de longueur (tous les éléments de )
Si
Cette redondance ne doit pas poser pas problème dans les situations où on ne demande pas d’unicité : par exemple, si l’on veut juste une correspondance valide pour décoder n’importe quel mot binaire vers un élément de
- La fonction de codage
reste injective (chaque élément de a un code unique).
Par exemple l’objectif peut être de garantir un décodage, même arbitraire, dans tous les cas possibles (comme dans certains systèmes d’encodage où le “reste des cas” mènent à une valeur “par défaut”).
- Le problème de duplication ne survient qu’au moment de définir une fonction de décodage totale
, qui ajoute des correspondances pour les mots binaires inutilisés.
À quelle condition un ensemble peut-il admettre un codage sur bits, avec une fonction de codage surjective (ou, de manière équivalente, une fonction de décodage totale et injective) ?
Une condition nécessaire est suffisante :
En effet, (
(
est injective car chaque code est associé à un unique élément de par . est totale car tout mot binaire dans a une préimage dans .
Un codage sur
Addition dans
En identifiant
Vérifions que la fonction
représente l’addition :
On a :
, .
La somme est donc :
La retenue entre
La somme des bits de poids fort inclut la retenue
Ce qui correspond exactement à
Donc la concaténation de ces deux résultats donne bien:
Donc, la fonction donnée calcule :
Exemple:
Dans
Additionnons : $$ \begin{array}{r@{}r@{}r@{}r} & ^1 & ^1 & \ & & 1 & 1\
- & & 1 & 1 \ \hline & 1 & 1 & 0 \ \end{array} $$
Ce qui donne
, donc on a bien
-
Les bits de poids faible sont les derniers bits (les plus à droite) :
- Bit faible de
: ,
En faisant l’addition modulo
(XOR, ) :Or, comme
en binaire, une retenue est générée : - Bit faible de
-
Les bits de poids fort sont les premiers bits (les plus à gauche) :
- Bit fort de
: ,
Nous ajoutons les bits forts, en tenant compte de la retenue générée par les bits faibles :
La concaténation des deux résultats donne :
- Bit fort de
Données séquentielles
Le monoïde des mots
3.1.8. Exercice (Généralités sur le monoïde des mots).
Non-commutativité du monoïde pour
Un mot
où
Comme
Morphisme de monoïdes de vers
La longueur d’un mot
-
Elément neutre : l’élément neutre de
est le mot vide . Par définition, , qui est l’élément neutre de . -
Opération : pour
, on a . Donc, , ce qui prouve que est un morphisme.Si
, chaque mot est de la forme pour . La longueur est une bijection entre et . Dans ce cas, est un isomorphisme. Si contient plusieurs symboles, il existe des mots distincts de même longueur (par exemple, et pour et ). Donc, n’est pas injective et donc pas un isomorphisme.
Dénombrabilité de
- Si
est fini ou dénombrable, , où est l’ensemble des mots de longueur . Chaque est une puissance cartésienne de , et un ensemble dénombrable de mots de longueur finie est une union dénombrable d’ensembles dénombrables, donc dénombrable. - Si
est non dénombrable, contient les mots de longueur 1 ( ), qui forment déjà un ensemble non dénombrable. donc, n’est pas dénombrable.
Donc,
Programmes élémentaires
fonction gonfle(s:str,k:int)
def gonfle(s: str, k: int) -> str:
#Retourne une chaîne où chaque caractère de "s" est répété "k" fois.
return "".join(char * k for char in s)
print(gonfle("ab", 3)) # Résultat : "aaabbb"
- Join est utilisée pour construire une nouvelle chaine en concaténant les répétitions de chaque caractère.
- char
génère copies pour chaque caractère.
On peut aussi faire à la main:
def gonfle(s,k):
retour = ""
for c in s:
for i in range(k):
retour = retour+c
return retour
ou bien comme k*c
retourne la concaténation de c
:
def gonfle(s,k):
retour = ""
for c in s:
retour = retour + k*c
return retour
fonction palindrome(u)
def palindrome(u) -> bool:
return u == u[::-1]
print(palindrome("radar")) # Résultat : True
print(palindrome("python")) # Résultat : False
- L’expression
retourne le mot renversé. - La comparaison
vérifie si le mot est identique à son inverse.
On peut faire aussi à la main:
def palindrome(u):
l = len(u)
for i in range(1//2):
If u[i] != u[l-i-1]:
return False
return True
ou alors:
def palindrome(u):
return all(u[i] == u[-i-1] for i in range(len(u)))
ou bien en utilisant la fonction reversed (la conversion en tuple des deux côtés de l’égalité est nécessaire pour obtenir des séquences du même type) :
def palindrome(u):
return tuple(reversed(u)) == tuple(u)
mais c’est moins efficace parce qu’on fait deux fois plus de tests (on parcourt toute la liste) ; ou bien avec un usage astucieux des tranches. :
def palindrome(u):
l = len(u)
return u[:1//2] == u[:-1-1//2:-1]
Codes de longueurs variables
Codages préfixes
Dans la théorie du codage et la représentation des données, les codages préfixes garantissent que les séquences de symboles encodés peuvent être décodées de manière unique. La propriété préfixe assure qu’aucun mot de code n’est le préfixe d’un autre, ce qui permet un décodage sans ambiguïté des codes concaténés. Cette propriété est utilisée dans des applications comme la compression de données (par exemple, le codage de Huffman) ou les encodages de caractères (comme UTF-8).
Soit
Vérification de l’injectivité de :
Soient
Définissons
Si
-
Si
alors . Si , alors également. -
Supposons que deux mots
et de sont tels que . Donc :Comme
est un codage préfixe, aucun code ne peut être un préfixe strict d’un autre code . donc ça garantit que le début de , c’est-à-dire , correspond nécessairement au début de , soit et vice versa. Par conséquent, on a :Puisque
est injectif, ça implique que:En supprimant la première lettre, on obtient deux nouveaux mots :
Comme
, il reste :Et ainsi de suite, par récurrence, on obtient
.
Codage de taille fixe est toujours un codage préfixe
Un codage de taille fixe
Fonction prefixe(u, v)
:
Voici une implémentation en Python d’une fonction qui retourne True
si le mot u
est préfixe de v
et False
sinon.
def prefixe(u, v):
return v.startswith(u)
Avec les deux versions qui suivent on accepte que des mots de types différents soient préfixe l’un de l’autre ou non prefixe("a", ["a", "b"]) == True
mais pas avec les autres versions (parce que pour Python une chaîne n’est jamais égale à une liste).
def prefixe(u,v):
l = len(u)
If l>len(v):
return False
for i in range(1):
If u[1] != v[1]:
return False
return True
def prefixe(u,v):
return len(u) <= len(v) and all(u[i] == v[i] for i in range(len(u)))
def prefixe(u,v):
return len(u) <= len(v) and u == v[:len(u)]
UTF-8 est un codage préfixe
Chaque caractère unicode est codé par une séquence de 1 à 4 octets, où la structure du premier octet détermine la longueur totale de la séquence :
- 1 octet :
(ASCII, où représente des bits). - 2 octets :
. - 3 octets :
. - 4 octets :
.
Tous les octets non initiaux commencent par
Les séquences à 1 octet (
Les octets internes (
Par exemple, le code UTF-8 pour un caractère ASCII est
Aucun suffixe strict n’est un préfixe
Un suffixe strict d’un code UTF-8 est une partie terminale d’un code, ne contenant pas son premier octet. Les suffixes stricts contiennent uniquement des octets non initiaux, qui ont la forme
Les octets non initiaux (
Représenter les nombres
Théorème (Existence et unicité de l’écriture en base
). Si on fixe
, alors tout entier admet une unique écriture sous la forme
avec $0 \leq c_i
Démonstration:
-
Existence:
Cas de base
: Si , alors , et l’écriture est immédiate. Étape de récurrence : Supposons que le théorème soit vrai pour . Pour , considérons comment peut être décomposé :Ici :
est le reste de la division euclidienne de par (le chiffre des unités).- La partie restante,
, est le quotient écrit en base avec termes.
Par récurrence, l’existence et l’unicité de l’écriture du quotient garantissent celles de
-
Unicité :
Les coefficients
sont déterminés par le processus de division euclidienne: est le reste obtenu en divisant par .- Les coefficients suivants proviennent des divisions successives du quotient par
.
Écriture en base 𝐵 en Python
Exemple d’une fonction representation(n,B)
qui renvoie la liste des valeur( c, B)
qui calcule la somme étant donnée la liste c des coefficients et la base B .
def representation(n, B, k=None):
"""
n (int): Le nombre entier à convertir.
B (int): La base dans laquelle effectuer la conversion.
en option : k (int): Longueur de l'écriture si spécifiée.
"""
if n == 0:
res = [0]
else:
res = []
while n > 0:
res.append(n % B)
n //= B
res.reverse()
if k is None:
return res
elif k >= len(res):
#Retourne: list[int]: Liste des chiffres de n en base B.
return [0] * (k - len(res)) + res
else:
#Si k est fourni et est inférieur à la taille minimale.
raise ValueError("La longueur k est inférieure à la taille minimale |n|_B.")
def valeur(c, B):
# Retourne: int: La valeur entière.
return sum(d * (B ** i) for i, d in enumerate(reversed(c)))
def conversion(c, B1, B2):
"""
Convertit une écriture d'une base B1 à une base B2.
c (list[int]): Liste des chiffres en base B1.
"""
n = valeur(c, B1)
#Retourne:list[int]: Liste des chiffres en base B2.
return representation(n, B2)