from GBA import *

#Entrée : une formule sous forme de liste de littéraux (ie une variable ou sa négation)
#Vérifie que cette formule est consistente cad qu'elle ne contient pas à la fois une variable et sa négation
def is_consistent(formula: Iterable[str]):
	for l in formula:
		if "~" + l in formula:
			return False
	return True

#Entrées : 2 automates de buchi généralisés
#Sortie : le produit synchrone de ces automates
def product[T, U](gba1: GBA[T], gba2: GBA[U]):
	states = {(state1, state2) for state1 in gba1.all_states for state2 in gba2.all_states}
	initials = {(state1, state2) for state1 in gba1.initial_states for state2 in gba2.initial_states}
	formulas = {f1.union(f2) for f1 in gba1.formulas for f2 in gba2.formulas}
	ap = gba1.ap.union(gba2.ap)
	edges = list[edge]()

	#à compléter
	product_impl(gba1, gba2, edges)

	accepting = list[frozenset[tuple[state[T], state[U]]]]()
	for acc in gba1.accepting_states:
		accepting.append(frozenset({(state1, state2) for state1 in acc for state2 in gba2.all_states}))
	for acc in gba2.accepting_states:
		accepting.append(frozenset({(state1, state2) for state1 in gba1.all_states for state2 in acc}))
	return GBA(states, initials, ap, edges, accepting)


def product_impl[T, U](gpa_left: GBA[T], gba_right: GBA[U], edges: list[edge[tuple[state[T], state[U]]]]):
		for (state_l, form_l), nexts_l in gpa_left.next_states.items():
			for (state_r, form_r), nexts_r in gba_right.next_states.items():
				for next_l in nexts_l:
					for next_r in nexts_r:
						formula = form_l.union(form_r)
						if is_consistent(formula):
							edges.append(((state_l, state_r), formula, (next_l, next_r)))


if __name__ == "__main__":
	gba1 =GBA([0,1],[0,1],["a"],[(0,[],0),(0,["a"],1),(1,["a"],1)],[[1]])
	gba2 =GBA([0,1],[0,1],["b"],[(0,[],0),(0,["b"],1),(1,["b"],1)],[[1]])
	produitTest = product(gba1,gba2)
	produitTest.export("produitTest")
	produit = GBA([0,1,2,3],[0,1,2,3],["a", "b"],[(0,[],0),(0,["a","b"],3),(0,["a"],1),(1,["a"],1),(0,["b"],2),(1,["a","b"],3),(2,["b"],2), (2,["a","b"],3), (3,["a","b"],3)],[[1,3],[2,3]])
	produit.export("produit")
