1#!/usr/bin/python3 2# -*- mode: python; coding: utf-8 -*- 3# Copyright (C) 2017-2019, 2021 Laboratoire de Recherche et Développement de 4# l'EPITA. 5# 6# This file is part of Spot, a model checking library. 7# 8# Spot is free software; you can redistribute it and/or modify it 9# under the terms of the GNU General Public License as published by 10# the Free Software Foundation; either version 3 of the License, or 11# (at your option) any later version. 12# 13# Spot is distributed in the hope that it will be useful, but WITHOUT 14# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16# License for more details. 17# 18# You should have received a copy of the GNU General Public License 19# along with this program. If not, see <http://www.gnu.org/licenses/>. 20 21import spot 22import buddy 23 24match_strings = [('is_buchi', 'is_co_buchi'), 25 ('is_generalized_buchi', 'is_generalized_co_buchi'), 26 ('is_all', 'is_none'), 27 ('is_all', 'is_all'), 28 ('is_buchi', 'is_all')] 29 30# existential and universal are dual 31# deterministic is self-dual 32 33 34def dualtype(aut, dual): 35 if dual.acc().is_none(): 36 return True 37 return (not spot.is_deterministic(aut) or spot.is_deterministic(dual))\ 38 and (spot.is_universal(dual) or not aut.is_existential())\ 39 and (dual.is_existential() or not spot.is_universal(aut)) 40 41 42def produce_phi(rg, n): 43 phi = [] 44 while len(phi) < n: 45 phi.append(rg.next()) 46 return phi 47 48 49def produce_automaton(phi): 50 aut = [] 51 for f in phi: 52 aut.append(spot.translate(f)) 53 return aut 54 55 56def test_aut(aut, d=None): 57 if d is None: 58 d = spot.dualize(aut) 59 aa = aut.acc() 60 da = d.acc() 61 62 complete = spot.is_complete(aut) 63 univ = aut.is_univ_dest(aut.get_init_state_number()) 64 an = aut.num_states() 65 dn = d.num_states() 66 67 if not dualtype(aut, d): 68 return (False, 'Incorrect transition mode resulting of dual') 69 for p in match_strings: 70 if ((getattr(aa, p[0])() and getattr(da, p[1])()) 71 or (getattr(aa, p[1])() and getattr(da, p[0])())): 72 return (True, '') 73 return (False, 'Incorrect acceptance type dual') 74 75# Tests that a (deterministic) automaton and its complement have complementary 76# languages. 77# FIXME This test could be extended to non-deterministic automata with a 78# dealternization procedure. 79 80 81def test_complement(aut): 82 assert aut.is_deterministic() 83 d = spot.dualize(aut) 84 s = spot.product_or(aut, d) 85 assert spot.dualize(s).is_empty() 86 87 88def test_assert(a, d=None): 89 t = test_aut(a, d) 90 if not t[0]: 91 print (t[1]) 92 print (a.to_str('hoa')) 93 print (spot.dualize(a).to_str('hoa')) 94 assert False 95 96 97aut = spot.translate('a') 98 99test_assert(aut) 100 101dual = spot.dualize(aut) 102h = dual.to_str('hoa') 103 104assert h == """HOA: v1 105States: 3 106Start: 1 107AP: 1 "a" 108acc-name: co-Buchi 109Acceptance: 1 Fin(0) 110properties: trans-labels explicit-labels state-acc complete 111properties: deterministic stutter-invariant very-weak 112--BODY-- 113State: 0 {0} 114[t] 0 115State: 1 116[0] 0 117[!0] 2 118State: 2 119[t] 2 120--END--""" 121 122aut = spot.automaton(""" 123HOA: v1 124States: 3 125Start: 0 126AP: 2 "a" "b" 127acc-name: Buchi 128Acceptance: 1 Inf(0) 129properties: trans-labels explicit-labels state-acc 130--BODY-- 131State: 0 132[0] 1 133[0] 2 134State: 1 {0} 135[0] 1 136State: 2 {0} 137[1] 2 138--END--""") 139 140test_assert(aut) 141dual = spot.dualize(aut) 142h = dual.to_str('hoa') 143 144assert h == """HOA: v1 145States: 4 146Start: 0 147AP: 2 "a" "b" 148acc-name: co-Buchi 149Acceptance: 1 Fin(0) 150properties: trans-labels explicit-labels state-acc complete 151properties: deterministic univ-branch 152--BODY-- 153State: 0 154[!0] 3 155[0] 1&2 156State: 1 {0} 157[0] 1 158[!0] 3 159State: 2 {0} 160[1] 2 161[!1] 3 162State: 3 163[t] 3 164--END--""" 165 166aut = spot.automaton(""" 167HOA: v1 168States: 4 169Start: 0&2 170AP: 2 "a" "b" 171acc-name: Buchi 172Acceptance: 1 Inf(0) 173properties: trans-labels explicit-labels state-acc univ-branch 174--BODY-- 175State: 0 176[0] 1 177State: 1 {0} 178[t] 1 179State: 2 180[1] 3 181State: 3 {0} 182[t] 3 183--END--""") 184 185test_assert(aut) 186dual = spot.dualize(aut) 187h = dual.to_str('hoa') 188 189assert h == """HOA: v1 190States: 2 191Start: 1 192AP: 2 "a" "b" 193acc-name: all 194Acceptance: 0 t 195properties: trans-labels explicit-labels state-acc deterministic 196--BODY-- 197State: 0 198[t] 0 199State: 1 200[!0 | !1] 0 201--END--""" 202 203aut = spot.automaton(""" 204HOA: v1 205States: 4 206Start: 0&2 207AP: 2 "a" "b" 208Acceptance: 2 Inf(0) | Inf(1) 209properties: trans-labels explicit-labels state-acc univ-branch 210--BODY-- 211State: 0 212[0] 1 213State: 1 {0} 214[t] 1 215State: 2 216[1] 3 217State: 3 {1} 218[t] 3 219--END--""") 220 221dual = spot.dualize(aut) 222assert dualtype(aut, dual) 223h = dual.to_str('hoa') 224 225assert h == """HOA: v1 226States: 2 227Start: 1 228AP: 2 "a" "b" 229acc-name: all 230Acceptance: 0 t 231properties: trans-labels explicit-labels state-acc deterministic 232--BODY-- 233State: 0 234[t] 0 235State: 1 236[!0 | !1] 0 237--END--""" 238 239aut = spot.automaton(""" 240HOA: v1 241States: 4 242Start: 0 243AP: 2 "a" "b" 244Acceptance: 1 Inf(0) | Fin(0) 245properties: trans-labels explicit-labels state-acc 246--BODY-- 247State: 0 248[0] 1 249State: 1 {0} 250[0] 3 251State: 2 252[0] 3 253State: 3 {0} 254[t] 3 255--END--""") 256 257dual = spot.dualize(aut) 258assert dualtype(aut, dual) 259h = dual.to_str('hoa') 260 261assert h == """HOA: v1 262States: 5 263Start: 0 264AP: 2 "a" "b" 265acc-name: co-Buchi 266Acceptance: 1 Fin(0) 267properties: trans-labels explicit-labels state-acc complete 268properties: deterministic 269--BODY-- 270State: 0 {0} 271[0] 1 272[!0] 4 273State: 1 {0} 274[0] 3 275[!0] 4 276State: 2 {0} 277[0] 3 278[!0] 4 279State: 3 {0} 280[t] 3 281State: 4 282[t] 4 283--END--""" 284 285aut = spot.automaton(""" 286HOA: v1 287States: 3 288Start: 0 289AP: 2 "a" "b" 290Acceptance: 2 Inf(0) & Fin(1) 291properties: trans-labels explicit-labels state-acc 292--BODY-- 293State: 0 {0} 294[0&!1] 1 295[0&1] 2 296State: 1 {1} 297[1] 1 298[0&!1] 2 299State: 2 300[!0&!1] 0 301[t] 2 302--END--""") 303 304dual = spot.dualize(aut) 305assert dualtype(aut, dual) 306h = dual.to_str('hoa') 307 308assert h == """HOA: v1 309States: 4 310Start: 0 311AP: 2 "a" "b" 312acc-name: Streett 1 313Acceptance: 2 Fin(0) | Inf(1) 314properties: trans-labels explicit-labels state-acc complete 315properties: deterministic univ-branch 316--BODY-- 317State: 0 {0} 318[0&!1] 1 319[0&1] 2 320[!0] 3 321State: 1 {1} 322[1] 1 323[0&!1] 2 324[!0&!1] 3 325State: 2 326[0 | 1] 2 327[!0&!1] 0&2 328State: 3 329[t] 3 330--END--""" 331 332aut = spot.automaton(""" 333HOA: v1 334States: 3 335Start: 0 336AP: 1 "a" 337Acceptance: 1 Inf(0) | Fin(0) 338properties: trans-labels explicit-labels state-acc complete 339--BODY-- 340State: 0 341[0] 1 342[!0] 2 343State: 1 {0} 344[t] 1 345State: 2 346[t] 2 347[0] 0 348--END--""") 349 350dual = spot.dualize(aut) 351assert dualtype(aut, dual) 352h = dual.to_str('hoa') 353 354assert h == """HOA: v1 355States: 1 356Start: 0 357AP: 1 "a" 358acc-name: none 359Acceptance: 0 f 360properties: trans-labels explicit-labels state-acc complete 361properties: deterministic terminal 362--BODY-- 363State: 0 364[t] 0 365--END--""" 366 367aut = spot.automaton(""" 368HOA: v1 369States: 3 370Start: 0 371AP: 1 "a" 372Acceptance: 1 Inf(0) | Fin(0) 373properties: trans-labels explicit-labels state-acc complete 374--BODY-- 375State: 0 376[0] 1 377[!0] 2 378State: 1 {0} 379[t] 1 380State: 2 381[t] 2 382--END--""") 383 384dual = spot.dualize(aut) 385assert dualtype(aut, dual) 386h = dual.to_str('hoa') 387 388assert h == """HOA: v1 389States: 1 390Start: 0 391AP: 1 "a" 392acc-name: none 393Acceptance: 0 f 394properties: trans-labels explicit-labels state-acc complete 395properties: deterministic terminal 396--BODY-- 397State: 0 398[t] 0 399--END--""" 400 401aut = spot.automaton(""" 402HOA: v1 403States: 3 404Start: 0 405AP: 2 "a" "b" 406Acceptance: 1 Inf(0) 407properties: trans-labels explicit-labels trans-acc 408--BODY-- 409State: 0 410[0&1] 1 411[0&!1] 2 412State: 1 413[t] 1 {0} 414[0] 0 415State: 2 416[0] 2 417--END--""") 418 419dual = spot.dualize(aut) 420h = dual.to_str('hoa') 421 422assert h == """HOA: v1 423States: 3 424Start: 0 425AP: 2 "a" "b" 426acc-name: co-Buchi 427Acceptance: 1 Fin(0) 428properties: trans-labels explicit-labels state-acc complete 429properties: deterministic 430--BODY-- 431State: 0 432[0&1] 1 433[!0 | !1] 2 434State: 1 {0} 435[t] 1 436State: 2 437[t] 2 438--END--""" 439 440aut = spot.automaton(""" 441HOA: v1 442States: 3 443Start: 0 444AP: 1 "a" 445Acceptance: 1 Fin(0) 446properties: trans-labels explicit-labels state-acc 447--BODY-- 448State: 0 449[0] 1 450[0] 2 451State: 1 {0} 452[0] 1 453State: 2 454[t] 2 455--END--""") 456 457 458dual = spot.dualize(aut) 459assert dualtype(aut, dual) 460h = dual.to_str('hoa') 461 462assert h == """HOA: v1 463States: 2 464Start: 0 465AP: 1 "a" 466acc-name: Buchi 467Acceptance: 1 Inf(0) 468properties: trans-labels explicit-labels state-acc deterministic 469--BODY-- 470State: 0 471[!0] 1 472State: 1 {0} 473[t] 1 474--END--""" 475 476aut = spot.automaton(""" 477HOA: v1 478States: 4 479Start: 0 480AP: 1 "a" 481Acceptance: 1 Fin(0) 482properties: trans-labels explicit-labels state-acc 483--BODY-- 484State: 0 485[0] 1 486[!0] 2 487[0] 0 488State: 1 {0} 489[t] 1 490State: 2 491[0] 3 492[!0] 0 493State: 3 {0} 494[t] 3 495--END--""") 496 497dual = spot.dualize(aut) 498assert dualtype(aut, dual) 499h = dual.to_str('hoa') 500 501assert h == """HOA: v1 502States: 3 503Start: 0 504AP: 1 "a" 505acc-name: Buchi 506Acceptance: 1 Inf(0) 507properties: trans-labels explicit-labels state-acc complete 508properties: deterministic 509--BODY-- 510State: 0 511[0] 0 512[!0] 1 513State: 1 514[!0] 0 515[0] 2 516State: 2 {0} 517[t] 2 518--END--""" 519 520aut = spot.automaton(""" 521HOA: v1 522States: 3 523Start: 0 524AP: 1 "a" 525Acceptance: 2 Fin(0) & Inf(1) 526properties: trans-labels explicit-labels 527--BODY-- 528State: 0 529[!0] 0 530[0] 1 {0} 531[0] 2 {1} 532State: 1 533[t] 0 534State: 2 535[t] 0 536--END--""") 537 538dual = spot.dualize(aut) 539assert dualtype(aut, dual) 540h = dual.to_str('hoa') 541 542assert h == """HOA: v1 543States: 3 544Start: 0 545AP: 1 "a" 546acc-name: parity min even 2 547Acceptance: 2 Inf(0) | Fin(1) 548properties: trans-labels explicit-labels state-acc complete 549properties: deterministic univ-branch 550--BODY-- 551State: 0 552[!0] 0 553[0] 1&2 554State: 1 {0} 555[t] 0 556State: 2 {1} 557[t] 0 558--END--""" 559 560aut = spot.translate('G!a R XFb') 561test_assert(aut) 562dual = spot.dualize(aut) 563h = dual.to_str('hoa') 564 565assert h == """HOA: v1 566States: 5 567Start: 0 568AP: 2 "a" "b" 569acc-name: co-Buchi 570Acceptance: 1 Fin(0) 571properties: trans-labels explicit-labels state-acc complete 572properties: deterministic univ-branch 573--BODY-- 574State: 0 {0} 575[0&1] 0 576[0&!1] 2 577[!0&1] 0&1 578[!0&!1] 1&2 579State: 1 580[!0&1] 3 581[0 | !1] 4 582State: 2 583[0&1] 0 584[0&!1] 2 585[!0&1] 0&1 586[!0&!1] 1&2 587State: 3 {0} 588[!0] 3 589[0] 4 590State: 4 591[t] 4 592--END--""" 593 594opts = spot.option_map() 595opts.set('output', spot.randltlgenerator.LTL) 596opts.set('tree_size_min', 15) 597opts.set('tree_size_max', 15) 598opts.set('seed', 0) 599opts.set('simplification_level', 0) 600spot.srand(0) 601rg = spot.randltlgenerator(2, opts) 602 603for a in produce_automaton(produce_phi(rg, 1000)): 604 test_assert(a) 605 test_assert(spot.dualize(a), spot.dualize(spot.dualize(a))) 606 607aut = spot.automaton(""" 608HOA: v1 609States: 1 610Start: 0 611AP: 1 "a" 612Acceptance: 3 Fin(2) & (Inf(1) | Fin(0)) 613--BODY-- 614State: 0 615--END--""") 616test_complement(aut) 617 618for a in spot.automata('randaut -A \"random 0..6\" -H -D -n50 4|'): 619 test_complement(a) 620