Automate de Collatz – Règles simplifiées

Tableau des règles

28 mars 2025 | màj le 21 avril 2025
Règle
gauche-droite
Action
V-V Se déplace vers P + 1
V-F Se déplace vers P + 2 (voir règle V-F plus bas)
F-V Reste en place
F-F Reste en place et crée un nouveau pion à P + 1

Lien avec la conjecture de Collatz (ou de Syracuse)

L'algorithme de Collatz et l'automate donneront toujours strictement le même résultat impair, mais le second n'effectuera pour cela aucun calcul.

Mais que devient le cycle trivial dans cette histoire ? Nous avons dit que par convention les premier et dernier pions sont respectivement Vrai à gauche et Faux à droite, en raison de l'absence de voisin sur un côté. De ce fait, le pion unique obéit à la règle V-F, qui le fera indéfiniment avancer de deux cellules (P+2). Comme ce pion représente $2^0=1$, nous obtenons bien une répétition non-stop du 1 final.

Une infinité de possibilités

Si n est un entier impair non multiple de 3, nous savons qu'il possède une infinité de prédécesseurs impairs immédiats dans le contexte des suites de Collatz, ce qui signifie qu'une infinité d'entiers impairs ont n pour successeur immédiat. Une infinité de configurations de pions, ou états de l'automate, conduiront par conséquent à n'importe quelle configuration donnée à l'itération suivante. Voici un exemple illustrant le fait que 111, 445, 1781, 7125, 28501, 114005, ... sont des prédécesseurs de 167 :

État final

Il est important de comprendre ce qui à la dernière itération de l'automate provoque la suppression de tous les pions sauf un : l'avant-dernière itération laisse toujours plusieurs pions (le plus souvent 2) espacés deux à deux de 2 cellules (vous pouvez tester N = 349525). Cette configuration particulière est telle qu'à la prochaine itération, tous les pions sauf un seront éliminés. L'état de l'automate contenant 2 pions espacés de 2 cellules est n = 2^0+2^2 = 5. Avec 3 pions, l'automate est dans l'état n = 2^0+2^2+2^4 = 21. Avec 4 pions il sera dans l'état n = 2^0+2^2+2^4+2^6 = 85. Etc. On sait que 5, 21, 85, 341, ... sont des prédécesseurs impairs de 1 dans une suite de Collatz. À l'étape suivante ils deviendront 3n + 1 = 16, 64, 256, 1024, ..., des puissances de 2 paires qui descendront directement vers 1 à la suite d'une série de divisions par 2.

Tout en haut de la page de l'automate, tapez la liste de diffences 2,2,2,... et validez. Vous constaterez qu'à la première itération, tous ces pions, quel que soit leur nombre, seront supprimés (sauf bien sûr un). Plus important que le pion unique restant à la fin, c'est ce regroupement final des pions dont il faudrait comprendre la cause. L'automate vise ce regroupement, en quelque sorte ; il le construit étape par étape. Le 1 final est uniquement la conséquence de ce fait.

Liens

Mise en oeuvre des règles simplifiées dans une application Python (cliquez sur "Créer une copie" pour permettre son édition)

Version originale animée de l'automate

Représentation booléenne du voisinage d'un pion

Voici le code Python permettant de transformer la liste des positions de chaque pion en la liste suivante dans son évolution vers une liste à un seul élément (en l'occurrence le 1 final). Vous pouvez utiliser le premier lien ci-dessus pour le tester.

def iterer(positions):
	"""
	Fonction destinée à l'automate utilisant les drapeaux gauche1/droite1
	(Vrai si voisin distant d'une cellule, Faux autrement).
	"""
	resultats = set()
	n = len(positions)

	for i in reversed(range(n)):	# on commence par le dernier pion
		pion = positions[i]
		# bord gauche : forcer True pour i == 0 (aucun voisin gauche), sinon test d'adjacence
		gauche1 = (i == 0) or (positions[i] - positions[i-1] == 1)
		# bord droit : forcer False pour i == n-1 (aucun voisin droite), sinon test d'adjacence.
		# Grâce au 'and', pas d’erreur pour i == n-1, le résultat sera Faux
		droite1 = (i < n-1) and (positions[i+1] - positions[i] == 1)
		
		if gauche1 and droite1: 			# cas V-V
			resultats.add(pion + 1)
		elif gauche1 and not droite1: 	# cas V-F
			cible = pion + 2
			while cible in resultats:
				resultats.discard(cible)
				cible += 1
			resultats.add(cible)
		elif not gauche1 and droite1: 	# cas F-V
			resultats.add(pion)
		else: 						# cas F-F
			resultats.update([pion, pion + 1])
	
	return sorted(resultats)

# Exemple d'entrée : positions = [0, 2, 12, 13, 15, 16] → 110597
# Résultat retourné : [0, 8, 12, 14] → 20737
# Dans une suite de Collatz, 20737 est bien le successeur impair de 110597
	

Un peu d'histoire

Pour mesurer l'évolution de cet algorithme depuis sa création en 2020, voici sa première approche fonctionnelle (en JavaScript). L'incroyable simplicité de la dernière version (en Python) en devient d'autant plus visible.

function transforme(S) {
	if (!Array.isArray(S)) return "Erreur";
	var L = S.length-1, b = false, c, d, i;

	// Insérer le nouveau terme S[L]+1 à l'indice L+1.
	function inserNouv() {
		if (!b) S.splice(L+1,0,S[L]+1);
	}

	// Règles 1 et 2.

	while (L > 1) {
		if (S[L] - S[L-1] == 1) {
			S[L] += (b ? 1 : 2); // b true ? oui, ajouter 1 : non, ajouter 2
			b = true
		} else {
			inserNouv();
			b = false
		}
		L--
	}

	inserNouv(); // L = 1, indice non traité par la boucle (non prise en compte de m = min(S)).

	// Règle 3. m = m+2, puis vérifier que min(S) est bien au début de la liste.
	// Si ce n'est pas le cas il est en seconde position --> inverser les 2 premiers termes.
	
	S[0] += 2;
	if (S[0] > S[1]) {
		[S[0],S[1]] = [S[1],S[0]]
	}

	// Règle 4. Suppression des doublons. Deux termes identiques étant toujours consécutifs,
	// leur différence est 0.

	d = S.slice(1).map((x,i) => x-S[i]); // Différences entre les termes de S.
	b = true;
	while (b) {
		i = d.lastIndexOf(0); // Indice du dernier 0 dans d. Renvoie -1 si aucun 0.
		if (i !== -1) {
			d.splice(i,1); // Supprimer ce 0
			// On boucle parce que les doublons peuvent être chaînés.
			c = true;
			while (c) {
				if (S[i] == S[i+1]) {
					S.splice(i,1); // Supprimer le terme de S à la position i.
					S[i]++ // Le terme suivant prend sa place. L'incrémenter.
				} else c = false
			}
		} else b = false
	}

	return S
}

// Soustraction de la valeur du premier terme (le minimum) de tous les termes
function reduire(arr) {
	const min = Math.min(...arr);
	return arr.map(v => v - min);
}

// Le paramètre de la fonction transforme est une liste triée d'au moins deux entiers naturels,
// tous distincts, le premier étant toujours 0. Voici un exemple :

console.log(reduire(transforme([0, 2, 12, 13, 15, 16])));
// Tout comme la fonction Python ci-dessus, affiche [0, 8, 12, 14]

Conclusion

Certains se demanderont à quoi peut bien servir cet automate. La réponse est simple : si quelqu'un parvient à démontrer que les règles qui le gouvernent le conduisent à supprimer tous ses éléments sauf un, alors la conjecture de Collatz sera elle aussi démontrée.