Równania napisów
Przyjrzyjmy się problemowi równań napisów: dla ustalonego alfabetu, np. piszemy równania używające liter z tegoż alfabetu oraz zmiennych, które będziemy oznaczać przez Dla uproszczenia pomyślmy o jednym równaniu, np. Rozwiązaniem będą takie napisy, złożone z liter alfabetu, że po podstawieniu pod zmienne uzyskamy takie same napisy....
W naszym przykładzie podstawienie jest rozwiązaniem. Innym przykładem jest równanie którego rozwiązaniem jest np. Równania tego typu rozważane były od lat 60. XX wieku, z jednej strony ze względu na związki z 10. problemem Hilberta, z drugiej ze względu na związki z teorią grup… Ale obie te historie to tematy na osobne artykuły.
Pierwszy sposób rozwiązywania tego typu równań podał G. Makanin w 1977 roku, w roku 1999 inne, dużo prostsze podejście zaproponował W. Plandowski. My przyjrzymy się dziś rozwiązaniu upraszczającemu drugie z nich, na podstawie mojego artykułu Recompression: A Simple and Powerful Technique for Word Equations, (Journal of the ACM, 2016 63:1, art. 4).
Zanim przystąpimy do prezentacji sposobu rozwiązywania takich równań, należałoby ustalić, do czego będziemy dążyć: chcemy podać algorytm, czyli systematyczny przepis pokazujący, jak uzyskać rozwiązanie (lub stwierdzić, że go nie ma). Przykładem algorytmu dla układu równań liniowych jest: "Powtarzaj: weź pierwsze równanie, jeśli jest niesprzeczne i zawiera zmienną, to wylicz jedną zmienną w oparciu o inne i podstaw do pozostałych równań, usuń równanie". Przykładem algorytmu dla równania kwadratowego jest: "Wylicz jeśli to nie ma rozwiązań, w przeciwnym przypadku rozwiązania to ". Podamy tego typu algorytm, choć dłuższy i bardziej skomplikowany, dla równań napisów.
Nasz algorytm będzie wielokrotnie sprawdzał niezależnie kilka możliwości, np. osobno sprawdzi możliwości, że pierwsza litera podstawienia pod to lub a potem osobno, czy poza tą jedną literą coś jeszcze w podstawieniu jest, czy nie, itd. Jeśli istnieje rozwiązanie, to algorytm znajdzie je dla którejś sekwencji możliwości, dla innych być może nie znajdzie. Nie brzmi to jak dobry pomysł - w takim razie algorytm mógłby po prostu przejrzeć wszystkie możliwe podstawienia, litera po literze… Dlatego też zagwarantujemy coś jeszcze - algorytm będzie przekształcał równanie w taki sposób, że dla którejś z możliwości wiodących do rozwiązania rozważane równanie zawsze będzie miało najwyżej liter i zmiennych, gdzie to długość równania wejściowego. W szczególności dla niektórych możliwości nie znajdziemy rozwiązania (trudno!), a inne doprowadzą nas do równania dłuższego niż - wtedy algorytm przestaje dalej liczyć. Takie podejście można też zrealizować inaczej, bez odwoływania się do sprawdzania wszystkich możliwości: możemy wypisać wszystkie równania długości najwyżej zaznaczyć, które równania możemy przekształcić w które, i sprawdzić, czy potrafimy przekształcić wejściowe równanie w jakieś bardzo proste niesprzeczne równanie, np. albo
Od teraz skupimy się na wykazaniu, że algorytm zawsze ma "dobry wybór", tj. potrafi przekształcić niesprzeczne równanie długości nie większej niż w niesprzeczne równanie długości również nie większej niż Ważne jest też, że niezależnie od wyboru nie przekształcimy równania sprzecznego w niesprzeczne.
Równanie napisów może mieć wiele rozwiązań i algorytm jest w stanie podać reprezentację wszystkich; dla uproszczenia będziemy wymagać jedynie, o ile istnieje, aby podał dowolne. W szczególności: jeśli istnieje rozwiązanie, to istnieje też takie, które używa tylko liter występujących w równaniu, choć sam alfabet może być większy - wszystkie inne litery w rozwiązaniu można zastąpić przez ustaloną literę; nowe podstawienie dalej jest rozwiązaniem. Będziemy też zakładać, że podstawienie pod zmienną jest niepuste, tj. w podstawieniu słowo ma dodatnią długość.
Aby rozwiązać równanie napisów, będziemy skracać jego krótkie fragmenty: popatrzmy jeszcze raz na równanie (które ma rozwiązanie ): jeśli zastąpimy przez "świeżą", tj. nieużywaną w równaniu, literę to otrzymane równanie ma rozwiązanie Łatwo też sprawdzić, że jeśli nowe równanie ma rozwiązanie, to stare też ma - wystarczy zamienić w podstawieniu każde przez Niestety, ten pomysł nie działa, jeśli w oryginalnym równaniu spróbujemy zastąpić przez : po lewej stronie równania nie ma żadnego w podstawieniu również nie ma, jest za to po prawej stronie równania. Problemem jest to, że jest częściowo w podstawieniu i częściowo poza. Parę gdzie nazwiemy złą (dla ustalonego rozwiązania), jeśli jest pierwszą literą podstawienia pod oraz występuje w równaniu lub jest ostatnią literą podstawienia pod oraz występuje w równaniu (lub dla powyższych założeń występuje w równaniu). Parę, która nie jest zła, nazwiemy dobrą. Jeśli para gdzie jest dobra, to skrócenie daje równanie, które ma odpowiadające, krótsze rozwiązanie. Jednocześnie, jeśli nowe równanie ma rozwiązanie, to stare też miało: wystarczy każde zastąpić przez
Co do złych par, to łatwo zauważyć, że jeśli równanie ma wystąpień zmiennych, to jest najwyżej różnych złych par: po jednej na każdą stronę zmiennej. Co więcej, ustaloną złą parę łatwo udobruchać (czyli uczynić dobrą): jeśli jest zła, to dla każdej zmiennej sprawdzamy: jeśli jej podstawienie zaczyna się na czyli to zastępujemy przez (a podstawienie przez ), analogicznie, jeśli podstawienie kończy się na to zastępujemy przez Jeśli w ten sposób podstawienie za stało się puste, to usuwamy z równania. Łatwo sprawdzić, że nowe równanie ma rozwiązanie oraz para jest dobra; jeśli zaś nowe równanie ma rozwiązanie, to miało je też stare równanie: wystarczy dokleić litery, które "wypchnęliśmy" ze zmiennych. W nowym równaniu możemy skrócić
Złe pary to nie jedyny problem: skoro zakładamy, że w parze litery i są różne, to nie potrafimy skrócić długich powtórzeń jednej litery, np. nie wiemy, co zrobić z równaniem z pierwszego przykładu. Zamiast skracać pary, będziemy skracać maksymalne powtórzenia: jest maksymalnym powtórzeniem jeśli na lewo i prawo nie ma litery Podobnie jak w przypadku par, możemy zdefiniować, co to znaczy, że litera jest zła (jest zmienna zaczynająca się na i występuje w równaniu lub…) i dobra. Jeśli jest dobre, to możemy równocześnie zastąpić wszystkie maksymalne wystąpienia powiedzmy dla każdego zastępujemy maksymalne przez ; przy czym to tylko wygodna nazwa dla nas, algorytm nie musi potem pamiętać, że ta litera powstała z Jeśli jest zła, to chcemy ją "udobruchać", ale zastąpienie przez może nie wystarczyć, gdyż podstawienie pod może dalej zaczynać się na Zamiast tego, jeśli gdzie nie zaczyna się ani nie kończy na to zastępujemy przez odpowiednio zmieniając podstawienie pod (teraz ). Wszystkie możliwe chcemy sprawdzić osobno i tu pojawia się problem: i mogą być dowolnie duże. Wiadomo jednak, że jeśli istnieje rozwiązanie równania, to istnieje też rozwiązanie, w którym wszystkie takie mają najwyżej wykładniczą długość. To wciąż dużo, ale zamiast pisać razy możemy zapisać a zapis pozycyjny ma wielomianowo wiele cyfr. I tak zaraz skrócimy wszystkie maksymalne powtórzenia Tak samo jak dla par możemy wykazać, że jest najwyżej złych liter, a jeśli rozpatrzymy jednocześnie złe pary i litery, to podobnie stwierdzamy, że w sumie złych par i liter jest najwyżej
Teraz możemy już podać wybory algorytmu, które prowadzą do rozwiązania, a równanie ma niezmiennie co najwyżej liter (i najwyżej zmiennych): dla danego równania, jeśli istnieje dobra para lub litera, to skracamy ją. Jeśli są tylko złe pary i litery, to wybieramy taką, że po jej udobruchaniu oraz skróceniu otrzymane równanie jest najkrótsze.
Przeanalizujmy algorytm dla tych możliwości: zauważmy najpierw, że jeśli równanie nie ma rozwiązania, to nieważne, co zrobimy, nowe równanie również nie będzie miało rozwiązania. Twierdzimy też, że przy właściwych wyborach równanie nigdy nie będzie miało więcej niż liter, gdzie to długość równania danego na wejściu: Jeśli istnieje dobra para lub litera, to po jej skróceniu nowe równanie jest krótsze niż stare. A co, jeśli są tylko złe pary i litery? Niech równanie ma liter, nie licząc zmiennych. Różnych złych par i liter jest w sumie najwyżej Dla każdej litery rozpatrzmy literę na prawo (lub lewo, dla ostatniej); ta sąsiednia litera może pochodzić z podstawienia pod zmienną. Razem tworzą parę albo są częścią maksymalnego bloku. Czyli dla każdego wystąpienia litery w równaniu istnieje zła para lub litera, której wystąpienie zawiera to ustalone wystąpienie Skrócenie tej pary/litery usunie to ustalone wystąpienie Jako że jest złych par i liter, "średnio" skrócenie usunie przynajmniej liter oraz wprowadzi co najwyżej połowę z tej liczby (skrócenie pary usuwa dwie litery i dodaje jedną, a skrócenie bloku liter usuwa wiele liter i dodaje jedną). Tak więc istnieje takie skrócenie, które w sumie skróci równanie o przynajmniej liter. Musimy też wykonać jedno udobruchanie, które wprowadza do równania najwyżej liter: udobruchanie litery wprowadza długie powtórzenia tej litery, ale zaraz każde takie powtórzenie zostanie zastąpione przez jedną literę. Tak więc nowe równanie ma najwyżej (stare litery) (usunięte przez skrócenie) (udobruchanie) liter. Oszacujmy:
jedyna nierówność wynika z ograniczenia I to jest koniec: dla podanych wyżej wyborów równanie znajdzie rozwiązanie i równania, które rozważa, mają najwyżej liter (i najwyżej zmiennych).
A czego nie wiemy o równaniach napisów? Dokładniejsza analiza algorytmu pokazuje, że jeśli istnieje rozwiązanie, to istnieje też rozwiązanie podwójnie wykładnicze. Nie jest jednak znane równanie, którego najkrótsze rozwiązanie jest ponad wykładnicze; popularna jest hipoteza, że jeśli istnieje rozwiązanie, to istnieje też rozwiązanie wykładnicze. Do równań napisów można też dodać dodatkowe warunki na rozwiązanie, np. żądać, by suma długości podstawień pod i była równa długości podstawienia pod Nie wiadomo, czy równania napisów z liniowymi warunkami na długości podstawień można rozwiązać.