Föreläsning 11 i programmeringsparadigm. Boxmodellen i Sicstus-manualen. The Procedure Box Control Flow Model During debugging, the debugger prints out a sequence of goals in various states of instantiation in order to show the state the program has reached in its execution. However, in order to understand what is occurring it is necessary to understand when and why the debugger prints out goals. As in other programming languages, key points of interest are predicate entry and return, but in Prolog there is the additional complexity of backtracking. One of the major confusions that vice Prolog programmers have to face is the question of what actually happens when a goal fails and the system suddenly starts backtracking. The Procedure Box model of Prolog execution views program control flow in terms of movement about the program text. This model provides a basis for the debugging mechanism in development systems, and enables the user to view the behavior of the program in a consistent way. Let us look at an example Prolog predicate : *--------------------------------------------* Call Exit ---------> + descendant(x,y) :- offspring(x,y). + ---------> descendant(x,z) :- <--------- + offspring(x,y), descendant(y,z). + <--------- Fail Redo *-------------------+-----------------------* The first clause states that Y is a descendant of X if Y is an offspring of X, and the second clause states that Z is a descendant of X if Y is an offspring of X and if Z is a descendant of Y. In the diagram a box has been drawn around the whole predicate and labeled arrows indicate the control flow in and out of this box. There are five (en fattas i min bearbetning av manualen) such arrows, which we shall look at in turn. Call Exit This arrow represents initial invocation of the predicate. When a goal of the form descendant(x,y) is required to be satisfied, control passes through the Call port of the descendant box with the intention of matching a component clause and then satisfying the subgoals in the body of that clause. Note that this is independent of whether such a match is possible; i.e. first the box is called, and then the attempt to match takes place. Textually we can imagine moving to the code for descendant when meeting a call to descendant in some other part of the code. This arrow represents a successful return from the predicate. This occurs when the initial goal has been unified with one of the component clauses and the subgoals have been satisfied. Control w passes out of the Exit port of the descendant box. Textually we stop following the code for descendant and go back to the place we came from.
Redo Fail This arrow indicates that a subsequent goal has failed and that the system is backtracking in an attempt to find alternatives to previous solutions. Control passes through the Redo port of the de scendant box. An attempt will w be made to resatisfy one of the component subgoals in the body of the clause that last succeeded; or, if that fails, to completely rematch the original goal with an alternative clause and then try to satisfy any subgoals in the body of this new clause. Textually we follow the code backwards up the way we came looking for new ways of succeed ing, possibly dropping down on to ather clause and following that if necessary. This arrow represents a failure of the initial goal, which might occur if clause is matched, or if subgoals are never satisfied, or if any solution produced is always rejected by later processing. Control w passes out of the Fail port of the descendant box and the system continues to back track. Textually we move back to the code that called this predicate and keep moving backwards up the code looking for choicepoints. Naiv lösning i Prolog för Sudoku-problem. Hur kontrollerar vi att en suduko-lösning är OK? Jo grupper om nio tal skall innehålla alla tal 1<= tal <= 9. En naiv lösnng: member(x, [X _]). member(x, [_ Ys]):- member(x,ys). ninecheck(xs) :- member(1,xs), member(2,xs),member(3,xs), member(4,xs), member(5,xs),member(6,xs), member(7,xs), member(8,xs),member(9,xs). I övergrupper on nio stycken niogrupper skall alla niogrupper uppfylla detta villkoret ninecheck: nxncheck([]). nxncheck([n Ns]):- ninecheck(n), nxncheck(ns). En sudoku är en 9 x 9-matris och kan skrivas som en lista med 9 rader, varje rad är i sin tur en lista med 9 element. Det finns tre övergrupper; matrisen radvis, kolonnvis och delkvadratvis. En delkvadrat är 3x3 matris och hela sudokun är en 3x3-matris med delkvadrater. En lösning är att skriva en predikat trans(s, St, Sg) där St är S transponerad och Sg är S förvandlad på så sätt att varje rad i Sg är talen i en delkvadrat. allcheck(s) kontrollerar då ett helt sudoku. allcheck(s) :- trans(s,st,sg), nxncheck(s), nxncheck(st), nxncheck(sg). trans([[x11,x12,x13,x14,x15,x16,x17,x18,x19], [X21,X22,X23,X24,X25,X26,X27,X28,X29], [X31,X32,X33,X34,X35,X36,X37,X38,X39], [X41,X42,X43,X44,X45,X46,X47,X48,X49], [X51,X52,X53,X54,X55,X56,X57,X58,X59], [X61,X62,X63,X64,X65,X66,X67,X68,X69], [X71,X72,X73,X74,X75,X76,X77,X78,X79], [X81,X82,X83,X84,X85,X86,X87,X88,X89], [X91,X92,X93,X94,X95,X96,X97,X98,X99]], [[X11,X21,X31,X41,X51,X61,X71,X81,X91], [X12,X22,X32,X42,X52,X62,X72,X82,X92], [X13,X23,X33,X43,X53,X63,X73,X83,X93], [X14,X24,X34,X44,X54,X64,X74,X84,X94], [X15,X25,X35,X45,X55,X65,X75,X85,X95],
[X16,X26,X36,X46,X56,X66,X76,X86,X96], [X17,X27,X37,X47,X57,X67,X77,X87,X97], [X18,X28,X38,X48,X58,X68,X78,X88,X98], [X19,X29,X39,X49,X59,X69,X79,X89,X99]], [[X11,X12,X13, X21,X22,X23, X31,X32,X33], [X14,X15,X16, X24,X25,X26, X34,X35,X36], [X17,X18,X19, X27,X28,X29, X37,X38,X39], [X41,X42,X43, X51,X52,X53, X61,X62,X63], [X44,X45,X46, X54,X55,X56, X64,X65,X66], [X47,X48,X49, X57,X58,X59, X67,X68,X69], [X71,X72,X73, X81,X82,X83, X91,X92,X93], [X74,X75,X76, X84,X85,X86, X94,X95,X96], [X77,X78,X79, X87,X88,X89, X97,X98,X99]]). Om vi definierar ett faktum : s115([[5,6,8,4,9,3,2,1,7], %så kan vi t ex testa?- s115(s),allcheck(s). [1,3,4,5,2,7,6,8,9], S =... [9,7,2,6,1,8,4,5,3], yes [2,5,9,7,4,6,1,3,8], [6,4,1,3,8,9,7,2,5], [7,8,3,2,5,1,9,4,6], [8,2,6,9,3,4,5,7,1], [3,9,5,1,7,2,8,6,4], [4,1,7,8,6,5,3,9,2]]). Men Prologpredikat kan ju köras "baklänges; i princip kan vi alltså använda vårt program för att lösa en sudoku där en del tal fattas : s17(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q, [[5,6,K,4,9,L,2,1,7], [1,3,4,5,J,7,D,8,9], [9,7,2,6,1,8,4,5,3], [2,Q,9,7,A,O,1,3,8], %så kan vi t ex testa [F,4,1,3,8,P,7,G,5], [N,8,B,2,5,C,9,4,6],?- s17(a,b,c,...s), allcheck(s). [8,2,6,H,3,4,5,7,1], A = 4, [3,9,5,1,M,2,8,6,4], B = 3,... [4,1,I,8,6,5,3,E,2]]). Körtiden är några sekunder för detta problem där 17 element saknas. Saknas fler element ökar körtiden snabbt.problemen i tidningarna saknar dock kring 50 st element. Ska vi skriva ett realistiskt program måste vi börja tänka. Det borde gå lite fortare att använda en ninecheck som arbetar med labbens select istället för member men skillnaden är inte stor, jag har provat. Att det börjar ta tid beror ju på att det snabbt blir väldigt mycket "back-tracking". I vår lösning kommer ju ibland körningar av member att ge substitutioner av de logiska variablerna i sodokun, dvs Prolog chansar på at det ska vara en 1 och går vidare, går inte det så kanske en 2 går bättre, osv. Lösningen ovan kan ses som ett exempel på tekniken "Generate -Test", Brna sid 70. Sådana problem kan ofta effektiviseras gem att "skjuta testet in i generatorn". I lättare sudokun går det att finna element som man direkt kan bestämma, vilket gör att kanske ytterligare element kan bestämmas osv. Eventuellt behövs ingen backtracking alls. Sökning på Google med sudoku och prolog ger förstås massor av träffar: Här är t ex en ("full-working"): http://www.allpowerfuldave.com/games/sudoku/sudoku.pl Mitt program på /info/progp05/sudoku.pl.
Diskutabel bild om paradigmer och programmering av problem av "programmeringstävlings-typ". svårighet jobbigt Bilden mest för kombinatoriska problem? Tvungen att komma på effektiv algoritm, ändå hur? imperativ programmering, OO massa fåninga hur-detaljer????? Paradigm-obedroende? bekvämt funktionell programmering logikprogrammering logikläsning duger djupet-först, backtrackning gratis djupet-först, duger ej Algoritmen det svåra, ej att fomulera den? Kunna ADK? snitt, trixs, icke-logisk Prolog nästa föreläsning procedurell läsning krävs terminering problem sökträdsstorlek problem lösning i rätt ordning viktig osv problemstorlek n
Boxmodellen för append. % append(xs, Ys, XsYs) XsYs är resultatet när man konkatenerar listorna Xs och Ys % Haskell: append([], Ys, Ys). % (++) [] ys = ys append([x Xs],Ys,[X Zs]):-append(Xs,Ys,Zs). % (++) (x:xs) ys = x:(xs ++ ys) % Haskell med namn på rekursionantagandet % (++) (x:xs) ys = x:zs where zs=(xs++ys) Jag försöker förklara bilden nedan för en körning av append([1,2], [3, 4], Rs) närmare på föreläsningen. Principen är att vid anrop (Call) unifieras anropets argument med parametrarna i huvudet på den klausul som används, dvs en massa substitutioner sker. Substitutionerna är skrivna med kursiv stil i bilden nedan. Sker därefter ytterligaren ett anrop så sker ytterligare substitutioner osv. Vid en lyckad körning, dvs när vi lämmnar Exit-porten i den yttersta lådan som representerar frågan, så har det bildas en "kanal" kopplad till allt mer detaljerade värden på olika logiska variabler, och de logiska variablerna i frågan kan ges som ett detaljerat förslag. I bilden nedan har till slut Rs alias _276 blivit [1, 2, 3, 4]när vi kommer ut till höger. append([1, 2], [3, 4], Rs). append([], Ys, Ys). append/1 nivå 1 append([], Ys, Ys). append/2 nivå 2 append([x Xs],Ys,[X Zs]) X=1 Xs = [2] Ys = [3, 4] [X Zs] = Rs = _276 _276 = [1 _775] append([x Xs],Ys,[X Zs]) X=2 _775 = [2 _1169] Xs = [] Ys = [3, 4] append/3 nivå 3 append([], Ys, Ys). Ys = [3, 4] _1169 =[3,4] append([x Xs.. append([], Ys, Ys). append([x Xs], Ys, [X Zs]) :- append(xs, Ys, Zs).?- append([1, 2], [3, 4], Rs). 1 1 Call: append([1,2],[3,4],_276)? 2 2 Call: append([2],[3,4],_775)? 3 3 Call: append([],[3,4],_1169)? 3 3 Exit: append([],[3,4],[3,4])? 2 2 Exit: append([2],[3,4],[2,3,4])? 1 1 Exit: append([1,2],[3,4],[1,2,3,4])? Rs = [1,2,3,4]? yes Vid en mer invecklad körning, av annan program databas, där "backtracking" förkommit (Fail och Redo-portar har passerats "åt vänster"), så används inte de substitutioner som görs i de misslyckade sökförsöken, dvs i de grenar av sökträdet som inte "nått fram" till Exit- porten i frågans predikat. Sökträdet
Prologpredikat kan användas på många sätt. Se Brna avsnitt 6.1, The Reversibility of Prolog Programs. Ett lysande exempel på detta är append(?,?,?), som kan användas på massor av sätt.? betyder att argumentet kan vara både "inargument" och "utargument". Körningar på en mängd olika sätt: %append(+, +, 1) dvs append?- append([1, 2, 14], [22, 33], Res).% Vanlig använding, "som vi tänkte " Res = [1,2,14,22,33]? ; % append(+, +, -) + "in" - "out" % Funktion : Se föregående sida?- append([1], R, [1, 2, 3]). %append(+, -, +) suffix R = [2, 3]? ; % med trace: 1 1 Call: append([1],_228,[1,2,3])? 2 2 Call: append([],_228,[2,3])? 2 2 Exit: append([],[2,3],[2,3])? 1 1 Exit: append([1],[2,3],[1,2,3])? R = [2,3]? ;?- append(res, [22,33], [1,2,14,22,33] ). %append(+, -, +) prefix Res = [1,2,14]? ;?- append(r1, R2, [1,2,14]). %append(-, -, +) split R1 = [], R2 = [1,2,14]? ; R1 = [1], R2 = [2,14]? ; R1 = [1,2], R2 = [14]? ; R1 = [1,2,14], R2 = []? ; % med trace:?- append(r1, R2, [1,2,14]). 1 1 Call: append(_208,_230,[1,2,14])? 1 1 Exit: append([],[1,2,14],[1,2,14])? R1 = [], R2 = [1,2,14]? ; 1 1 Redo: append([],[1,2,14],[1,2,14])? 2 2 Call: append(_775,_230,[2,14])? 2 2 Exit: append([],[2,14],[2,14])? 1 1 Exit: append([1],[2,14],[1,2,14])? R1 = [1], R2 = [2,14]? ; 1 1 Redo: append([1],[2,14],[1,2,14])? 2 2 Redo: append([],[2,14],[2,14])? 3 3 Call: append(_1168,_230,[14])? 3 3 Exit: append([],[14],[14])? 2 2 Exit: append([2],[14],[2,14])? 1 1 Exit: append([1,2],[14],[1,2,14])? R1 = [1,2], R2 = [14]? ; 1 1 Redo: append([1,2],[14],[1,2,14])? 2 2 Redo: append([2],[14],[2,14])? 3 3 Redo: append([],[14],[14])? 4 4 Call: append(_1560,_230,[])? 4 4 Exit: append([],[],[])? 3 3 Exit: append([14],[],[14])? 2 2 Exit: append([2,14],[],[2,14])? 1 1 Exit: append([1,2,14],[],[1,2,14])?
R1 = [1,2,14], R2 = []? ; 1 1 Redo: append([1,2,14],[],[1,2,14])? 2 2 Redo: append([2,14],[],[2,14])? 3 3 Redo: append([14],[],[14])? 4 4 Redo: append([],[],[])? 4 4 Fail: append(_1560,_230,[])? 3 3 Fail: append(_1168,_230,[14])? 2 2 Fail: append(_775,_230,[2,14])? 1 1 Fail: append(_208,_230,[1,2,14])? I Haskell kan vi inte använda (++) för att splittra listor, vi måste skriva en invers funktion: splits :: [a] -> [ ([a],[a]) ] splits [] = [ ([],[]) ] splits (x:xs) = ([], x:xs) : map f (splits xs) where f (a, b) = (x:a, b) I Prolog kan vi nu använda append/3 för att enkelt definiera t ex : prefix(xs, Ys) :- append(xs, _, Ys). suffix(xs, Ys) :- append( _, Xs, Ys). member(x, Ys) :- append(_, [X Xs], Ys). member/2 kan alternativt definieras som i Brna 6.3.1 sid 57, vi har ju dessutom gjort det för sudokuproblemt : member(x,[x Xs]). member(x,[y Ys]) :- member(x,ys). % Y kan ersättas med _. Körningar av member/2:?- member(5, [3, 5, 6, 7]). yes?- member(x, [3, 5, 6]). X = 3? ; X = 5? ; X = 6? ;?- member(3, Rs). Rs = [3 _A]? ; Rs = [_A,3 _B]? ; Rs = [_A,_B,3 _C]? yes?- member(r, Rs). Rs = [R _A]? ; Rs = [_A,R _B]? yes Ytterligare ett exempel: adjacent(x, Y, Zs) :- append(_, [X,Y Ys], Zs). last(x, Xs) :- append(_, [X], Xs). Körningar:?- adjacent(14, 28, [23, 14, 28, 45]). yes?- adjacent(14, R, [23, 14, 28, 45]). R = 28? ;
Program med "ackumulering i parameter". 1. Rekursiv definiton av reverse/2: % reverse(list, Tsil) :- Tsil är listan List med elmenten i omvänd ordning reverse1([], []). reverse1([x Xs], Zs):- reverse1(xs, Ys), append(ys, [X], Zs). Körning:?- reverse1([1, 2], Res). Res = [2,1]? ;?- reverse1(res, [1, 2]). Res = [2,1]? ; % Inget händer gör C-c Prolog interruption (h for help)? a {Execution aborted}?- trace.?- reverse1([1, 2], Res). 1 1 Call: reverse1([1,2],_224)? 2 2 Call: reverse1([2],_702)? 3 3 Call: reverse1([],_1100)? 3 3 Exit: reverse1([],[])? 4 3 Call: append([],[2],_702)? 4 3 Exit: append([],[2],[2])? 2 2 Exit: reverse1([2],[2])? 5 2 Call: append([2],[1],_224)? 6 3 Call: append([],[1],_3351)? 6 3 Exit: append([],[1],[1])? 5 2 Exit: append([2],[1],[2,1])? 1 1 Exit: reverse1([1,2],[2,1])? Res = [2,1]? ; Brna kallar detta sätt att resonera för "Building Structure in the Clause Head", se sid 60 långt ner på sidan. (Ovanför står avsiktligt ett helt felaktigt sätt att resonera). I sitt exempel använder Brna is. Till höger om is kan man skriva uttryck som räknas ut och unifieras med det som står till vänster om is, dvs man har tillgång till en funktionellt delspråk i Prolog. Se Brna avsnitt 6.1.1Vi kommer inte att använda detta mycket, kanske inte alls. 2. Definition av reverse/2 med hjälp av "ackumulering i parameter" i hjälpfunktion reverse/2 : reverse(xs, Ys) :- reverse(xs, [], Ys). reverse([x Xs], Acc, Ys) :- reverse(xs, [X Acc], Ys). reverse([], Ys, Ys). Körning:?- reverse([1, 2], Res). Res = [2,1]? ;?- reverse(res, [1, 2]). Prolog interruption (h for help)? a {Execution aborted}?- reverse([1,2], Res). 1 1 Call: reverse([1,2],_224)? 2 2 Call: reverse([1,2],[],_224)?
3 3 Call: reverse([2],[1],_224)? 4 4 Call: reverse([],[2,1],_224)? 4 4 Exit: reverse([],[2,1],[2,1])? 3 3 Exit: reverse([2],[1],[2,1])? 2 2 Exit: reverse([1,2],[],[2,1])? 1 1 Exit: reverse([1,2],[2,1])? Res = [2,1]? ; Märk att vi kan ha samma namn på två olika pedikat, ariteten (ställigheten, i vårt fall /2 respektive /3) räcker för att Prolog ska kunna skilja på predikaten. I Haskell måste varje namn ha en unik definition i sitt "scope". Brna kallar detta sätt att resonera för "Building Structure in the Clause Body", se sid 61. Avsnitt 6.1, 6.2 och 6.3 innehåller en hel del om programmeringsteknik i Prolog och om hur man programmerar listor.. Exempel på sorteringar. Insättningsortering i Prolog och Haskell (Haskellprogrammet modifierat från sid 44 i Fokker) sortlk([x Xs],Ys) :- sortlk(xs,zs), insert(x,zs,ys). sortlk([],[]). insert(x,[],x). insert(x,[y Ys],[Y Zs]) :- X > Y, insert(x,ys,zs). insert(x,[y Ys],[X,Y Ys]) :- X =< Y. sort :: Ord a => [a] -> [a] sort (x:xs) = insert x (sort xs) sort [] = [] insert:: Ord a => a-> [a] -> [a] insert x [] = [x] insert x (y:ys) x > y = y: insert x ys otherwise = x:y:ys I Prolog är > en operator. Operatorer är också predikat men med vissa speciella egenskaper, bl a används många med infix-placering. För att förstå sorteringsprogrammet ovan räcker det att förstå att t ex 3 < 5 lyckas, 5>=17 misslyckas. Operatorn = betyder att en unifiering sker. Även quicksort blir ganska lika: /*sort(xs,ys) :- The list Ys is an ordered permutation of the Xs. /* quicksort([x Xs],Ys) :- partition(xs,x,littles,bigs), quicksort(littles,ls), quicksort(bigs,bs), append(ls,[x Bs],Ys). quicksort([],[]). partition([x Xs],Y,[X Ls],Bs) :- X =< Y, partition(xs,y,ls,bs). partition([x Xs],Y,Ls,[X Bs]) :- X > Y, partition(xs,y,ls,bs). partition([],y,[],[]). -- Haskell : quicksort :: Ord a => [a] - [a] quicksort (x:xs) = ls ++ [x] ++ bs where (littles,bigs) = partion(xs, x) ls = quicksort littles, bs = quicksort bigs quicksort [] =[] partition Ord a => [a] -> a ->([a],[a]) partition (x:xs) y x <= y = (x :ls, bs) otherwise = (ls, x:bs) where (ls, bs) = partition xs y partition [] = ([],[]).
Predikatet permutation från labben kan användas i en (ineffektiv) sortering : sort(xs,ys) :- permutation(xs,ys), ordered(ys). ordered([]). ordered([x]). ordered([x,y Ys]) :- X =< Y, ordered([y Ys]). Generate och test. Inför labben "Tidernas knepigaste problem". Det står lite grann om detta i Brna avsnitt 7.3, sid 70 till 72 ungefär. Ett exempel som liknar labben "Tidernas knepigaste problem" finns i labhäftet. Programmering i ren Prolog. Ren Prolog (pure Prolog) definieras som att allt i programmet har en logisk läsning. Man rekommenderar att man börjar programmera på detta sätt och tänker på programmet med den logiska läsningen, och det har vi gjort än så länge. I den logiska läsningen spelar klausul-ordningen ingen roll, och delmålen i en regelkropp spelar ingen roll. I regel måste man även i rena Prologprogram läsa programmet med en procedurell syn, för att programmet skall fungera (t ex inte gå in i en evig loop), bli snabbt mm. Det gäller bl a att klausul-ordningen bestämmer i vilken ordning man får lösningarna Finns "oändliga lösningar" är detta viktigt, i annat fall om man vill se alla lösningar mindre viktigt. ordningen mellan delmålen i en regels vänsterled bestämmer hur sökningen går till. I apan-och-bananen-problemet på nästa sida får vi "oändliga lösningar först", dvs datorn svarar inte, om klausul-ordningen är olämplig.
Apan och bananen (inte BanArne). Efter Bratko 2.5. Apan vid dörren är hungrig, men kan inte nå bananen som hänger för högt upp i mitten på rummet. Vid fönstret står en låda. Om lådan skulle stå mitt under bananen skulle apan nå bananen om den steg upp på lådan. Kan apan stilla sin hunger? Hur? atdoor middle atwindow Lösning: (på /info/progp02/prolog/monkey.pl ) % state(horizontal position of monkey (atdoor/atwindow/middle), % vertical position of monkey( onbox/onfloor), % position of box (atdoor/atwindow/middle), % possesion of banana (has/hast)). % move(prestate, Action, PostState) Action changes state from PreState to % PostState. move(state(middle, onbox, middle, hast), grasp, state(middle, onbox, middle, has)). move(state(p, onfloor, P, H), climb, state(p, onbox, P, H)). move(state(p1, onfloor, P1, H), push(p1, P2), state(p2, onfloor, P2, H)). move(state(p1, onfloor, B, H), walk(p1, P2), state(p2, onfloor, B, H)). % canget(state, Actions) -- monkey can get the banana from state State by % performing the actions Actions. canget(state(_, _, _, has), []). canget(state1, [Action As]) :- move(state1, Action, State2), canget(state2, As). /* Körning :?- canget(state(atdoor, onfloor, atwindow, hast), Rs). Rs = [walk(atdoor,atwindow),push(atwindow,middle),climb,grasp]? ; Rs = [walk(atdoor,atwindow),push(atwindow,_a),push(_a,middle),climb,grasp]? ; Rs = [walk(atdoor,atwindow),push(atwindow,_a),push(_a,_b),push(_b,middle),climb,grasp]? yes */
Från Ny teknik om sudoku: Det nya sifferpusslet sudoku har blivit en dundersuccé i Sverige. De flesta stora dagstidningarna publicerar i dag pusslet, som går ut på att fylla ett rutnät med siffror efter lättbegripliga regler. Vissa sudoku är mycket enkla att lösa. Men matematikerna har fått sig en del huvudbry när de dykt ner i matematiken kring det nya sifferpusslet. En grundläggande matematisk fråga är hur många olika sudoku som är möjliga att skapa. Alltså på hur många sätt de 81 siffrorna på spelplanen kan kombineras med varandra enligt reglerna för spelet. Trots att pusslet varit känt sedan 1970-talet och varit en jättefluga i Japan under tiotals år fick frågan sitt svar först i maj 2005. - Att det tog så lång tid beror g på att matematiker tidigare inte varit seriöst intresserade av sudoku, säger Paul Vaderlind, som är matematiker vid Stockholms universitet. - För dem som är insatta i kombinatorik är det relativt enkelt att räkna ut hur många det finns. Olika svårighetsgrad Svårigheten att lösa pusslet hänger nära samman med hur många av de 81 rutorna som är ifyllda från början. Med 35 givna siffror är pusslet ofta ganska lätt, medan 25 kända siffror kan erbjuda många timmars funderande, sifferplitande och suddande. FAKTA SUDOKU Antalet kombinationer bevisat Den tyska matematikern Bertram Felgenhauer blev först med att publicera svaret på hur många olika sudoku som kan konstrueras. Han bevisade att det finns 6 670 903 752 021 072 936 960 olika sätt att kombinera de 81 siffrorna enligt reglerna för pusslet. Hur många siffror som minst måste vara givna för att pusslet bara ska ha en lösning, och alltså vara en äkta sudoku, finns inget bevis för. Det lägsta antalet som är känt idag är 17. Men för bara några månader sedan var det 19. En annan fråga som väntar på sitt svar är hur många av de nio små kvadraterna med 3 x 3 siffror som helt kan sakna givna siffror i en lösningsbar sudoku. Det bästa exemplet som Paul Vaderlind sett har tre helt tomma kvadrater och ytterligare två kvadrater med endast en given siffra i varje. Alltså fem kvadrater som tillsammans bara innehåller två givna siffror. Regler: Varje lodrät och vågrät rad liksom de nio mindre kvadraterna ska innehålla siffrorna ett till nio. Varje siffra får bara förekomma en gång i varje rad och kvadrat.