src/Provers/order.ML
author wenzelm
Mon Mar 25 16:45:08 2019 +0100 (3 months ago)
changeset 69980 f2e3adfd916f
parent 67379 c2dfc510a38c
permissions -rw-r--r--
tuned signature;
haftmann@37744
     1
(*  Title:      Provers/order.ML
haftmann@37744
     2
    Author:     Oliver Kutter, TU Muenchen
wenzelm@29276
     3
wenzelm@29276
     4
Transitivity reasoner for partial and linear orders.
ballarin@14398
     5
*)
ballarin@14398
     6
ballarin@14445
     7
(* TODO: reduce number of input thms *)
ballarin@14398
     8
ballarin@14398
     9
(*
ballarin@14398
    10
ballarin@15103
    11
The package provides tactics partial_tac and linear_tac that use all
ballarin@14398
    12
premises of the form
ballarin@14398
    13
ballarin@14398
    14
  t = u, t ~= u, t < u, t <= u, ~(t < u) and ~(t <= u)
ballarin@14398
    15
ballarin@14398
    16
to
ballarin@14398
    17
1. either derive a contradiction,
ballarin@14398
    18
   in which case the conclusion can be any term,
ballarin@14398
    19
2. or prove the conclusion, which must be of the same form as the
ballarin@14398
    20
   premises (excluding ~(t < u) and ~(t <= u) for partial orders)
ballarin@14398
    21
ballarin@24639
    22
The package is not limited to the relation <= and friends.  It can be
ballarin@24639
    23
instantiated to any partial and/or linear order --- for example, the
ballarin@24639
    24
divisibility relation "dvd".  In order to instantiate the package for
ballarin@24639
    25
a partial order only, supply dummy theorems to the rules for linear
ballarin@24639
    26
orders, and don't use linear_tac!
ballarin@14398
    27
ballarin@14398
    28
*)
ballarin@14398
    29
ballarin@24639
    30
signature ORDER_TAC =
ballarin@14398
    31
sig
ballarin@24639
    32
  (* Theorems required by the reasoner *)
ballarin@24639
    33
  type less_arith
ballarin@24639
    34
  val empty : thm -> less_arith
ballarin@24639
    35
  val update : string -> thm -> less_arith -> less_arith
ballarin@14398
    36
ballarin@24639
    37
  (* Tactics *)
ballarin@24639
    38
  val partial_tac:
wenzelm@32215
    39
    (theory -> term -> (term * string * term) option) -> less_arith ->
wenzelm@32215
    40
    Proof.context -> thm list -> int -> tactic
ballarin@24639
    41
  val linear_tac:
wenzelm@32215
    42
    (theory -> term -> (term * string * term) option) -> less_arith ->
wenzelm@32215
    43
    Proof.context -> thm list -> int -> tactic
ballarin@14398
    44
end;
ballarin@14398
    45
ballarin@24639
    46
structure Order_Tac: ORDER_TAC =
ballarin@24639
    47
struct
ballarin@24639
    48
ballarin@24639
    49
(* Record to handle input theorems in a convenient way. *)
ballarin@24639
    50
ballarin@24639
    51
type less_arith =
ballarin@24639
    52
  {
ballarin@24639
    53
    (* Theorems for partial orders *)
ballarin@24639
    54
    less_reflE: thm,  (* x < x ==> P *)
ballarin@24639
    55
    le_refl: thm,  (* x <= x *)
ballarin@24639
    56
    less_imp_le: thm, (* x < y ==> x <= y *)
ballarin@24639
    57
    eqI: thm, (* [| x <= y; y <= x |] ==> x = y *)
ballarin@24639
    58
    eqD1: thm, (* x = y ==> x <= y *)
ballarin@24639
    59
    eqD2: thm, (* x = y ==> y <= x *)
ballarin@24639
    60
    less_trans: thm,  (* [| x < y; y < z |] ==> x < z *)
ballarin@24639
    61
    less_le_trans: thm,  (* [| x < y; y <= z |] ==> x < z *)
ballarin@24639
    62
    le_less_trans: thm,  (* [| x <= y; y < z |] ==> x < z *)
ballarin@24639
    63
    le_trans: thm,  (* [| x <= y; y <= z |] ==> x <= z *)
ballarin@24639
    64
    le_neq_trans : thm, (* [| x <= y ; x ~= y |] ==> x < y *)
ballarin@24639
    65
    neq_le_trans : thm, (* [| x ~= y ; x <= y |] ==> x < y *)
ballarin@24639
    66
    not_sym : thm, (* x ~= y ==> y ~= x *)
ballarin@24639
    67
ballarin@24639
    68
    (* Additional theorems for linear orders *)
ballarin@24639
    69
    not_lessD: thm, (* ~(x < y) ==> y <= x *)
ballarin@24639
    70
    not_leD: thm, (* ~(x <= y) ==> y < x *)
ballarin@24639
    71
    not_lessI: thm, (* y <= x  ==> ~(x < y) *)
ballarin@24639
    72
    not_leI: thm, (* y < x  ==> ~(x <= y) *)
ballarin@24639
    73
ballarin@24639
    74
    (* Additional theorems for subgoals of form x ~= y *)
ballarin@24639
    75
    less_imp_neq : thm, (* x < y ==> x ~= y *)
ballarin@24639
    76
    eq_neq_eq_imp_neq : thm (* [| x = u ; u ~= v ; v = z|] ==> x ~= z *)
ballarin@24639
    77
  }
ballarin@24639
    78
ballarin@24639
    79
fun empty dummy_thm =
ballarin@24639
    80
    {less_reflE= dummy_thm, le_refl= dummy_thm, less_imp_le= dummy_thm, eqI= dummy_thm,
ballarin@24639
    81
      eqD1= dummy_thm, eqD2= dummy_thm,
ballarin@24639
    82
      less_trans= dummy_thm, less_le_trans= dummy_thm, le_less_trans= dummy_thm,
ballarin@24639
    83
      le_trans= dummy_thm, le_neq_trans = dummy_thm, neq_le_trans = dummy_thm,
ballarin@24639
    84
      not_sym = dummy_thm,
ballarin@24639
    85
      not_lessD= dummy_thm, not_leD= dummy_thm, not_lessI= dummy_thm, not_leI= dummy_thm,
ballarin@24639
    86
      less_imp_neq = dummy_thm, eq_neq_eq_imp_neq = dummy_thm}
ballarin@24639
    87
ballarin@24639
    88
fun change thms f =
ballarin@24639
    89
  let
ballarin@24639
    90
    val {less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
    91
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
    92
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
    93
      eq_neq_eq_imp_neq} = thms;
ballarin@24639
    94
    val (less_reflE', le_refl', less_imp_le', eqI', eqD1', eqD2', less_trans',
ballarin@24639
    95
      less_le_trans', le_less_trans', le_trans', le_neq_trans', neq_le_trans',
ballarin@24639
    96
      not_sym', not_lessD', not_leD', not_lessI', not_leI', less_imp_neq',
ballarin@24639
    97
      eq_neq_eq_imp_neq') =
ballarin@24639
    98
     f (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
    99
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   100
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   101
      eq_neq_eq_imp_neq)
ballarin@24639
   102
  in {less_reflE = less_reflE', le_refl= le_refl',
ballarin@24639
   103
      less_imp_le = less_imp_le', eqI = eqI', eqD1 = eqD1', eqD2 = eqD2',
ballarin@24639
   104
      less_trans = less_trans', less_le_trans = less_le_trans',
ballarin@24639
   105
      le_less_trans = le_less_trans', le_trans = le_trans', le_neq_trans = le_neq_trans',
ballarin@24639
   106
      neq_le_trans = neq_le_trans', not_sym = not_sym',
ballarin@24639
   107
      not_lessD = not_lessD', not_leD = not_leD', not_lessI = not_lessI',
ballarin@24639
   108
      not_leI = not_leI',
ballarin@24639
   109
      less_imp_neq = less_imp_neq', eq_neq_eq_imp_neq = eq_neq_eq_imp_neq'}
ballarin@24639
   110
  end;
ballarin@14398
   111
ballarin@24639
   112
fun update "less_reflE" thm thms =
ballarin@24639
   113
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   114
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   115
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   116
      eq_neq_eq_imp_neq) =>
ballarin@24639
   117
    (thm, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   118
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   119
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   120
  | update "le_refl" thm thms =
ballarin@24639
   121
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   122
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   123
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   124
      eq_neq_eq_imp_neq) =>
ballarin@24639
   125
    (less_reflE, thm, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   126
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   127
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   128
  | update "less_imp_le" thm thms =
ballarin@24639
   129
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   130
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   131
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   132
      eq_neq_eq_imp_neq) =>
ballarin@24639
   133
    (less_reflE, le_refl, thm, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   134
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   135
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   136
  | update "eqI" thm thms =
ballarin@24639
   137
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   138
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   139
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   140
      eq_neq_eq_imp_neq) =>
ballarin@24639
   141
    (less_reflE, le_refl, less_imp_le, thm, eqD1, eqD2, less_trans,
ballarin@24639
   142
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   143
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   144
  | update "eqD1" thm thms =
ballarin@24639
   145
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   146
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   147
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   148
      eq_neq_eq_imp_neq) =>
ballarin@24639
   149
    (less_reflE, le_refl, less_imp_le, eqI, thm, eqD2, less_trans,
ballarin@24639
   150
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   151
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   152
  | update "eqD2" thm thms =
ballarin@24639
   153
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   154
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   155
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   156
      eq_neq_eq_imp_neq) =>
ballarin@24639
   157
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, thm, less_trans,
ballarin@24639
   158
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   159
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   160
  | update "less_trans" thm thms =
ballarin@24639
   161
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   162
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   163
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   164
      eq_neq_eq_imp_neq) =>
ballarin@24639
   165
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, thm,
ballarin@24639
   166
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   167
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   168
  | update "less_le_trans" thm thms =
ballarin@24639
   169
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   170
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   171
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   172
      eq_neq_eq_imp_neq) =>
ballarin@24639
   173
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   174
      thm, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   175
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   176
  | update "le_less_trans" thm thms =
ballarin@24639
   177
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   178
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   179
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   180
      eq_neq_eq_imp_neq) =>
ballarin@24639
   181
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   182
      less_le_trans, thm, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   183
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   184
  | update "le_trans" thm thms =
ballarin@24639
   185
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   186
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   187
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   188
      eq_neq_eq_imp_neq) =>
ballarin@24639
   189
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   190
      less_le_trans, le_less_trans, thm, le_neq_trans, neq_le_trans,
ballarin@24639
   191
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   192
  | update "le_neq_trans" thm thms =
ballarin@24639
   193
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   194
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   195
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   196
      eq_neq_eq_imp_neq) =>
ballarin@24639
   197
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   198
      less_le_trans, le_less_trans, le_trans, thm, neq_le_trans,
ballarin@24639
   199
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   200
  | update "neq_le_trans" thm thms =
ballarin@24639
   201
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   202
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   203
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   204
      eq_neq_eq_imp_neq) =>
ballarin@24639
   205
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   206
      less_le_trans, le_less_trans, le_trans, le_neq_trans, thm,
ballarin@24639
   207
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   208
  | update "not_sym" thm thms =
ballarin@24639
   209
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   210
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   211
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   212
      eq_neq_eq_imp_neq) =>
ballarin@24639
   213
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   214
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   215
      thm, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   216
  | update "not_lessD" thm thms =
ballarin@24639
   217
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   218
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   219
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   220
      eq_neq_eq_imp_neq) =>
ballarin@24639
   221
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   222
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   223
      not_sym, thm, not_leD, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   224
  | update "not_leD" thm thms =
ballarin@24639
   225
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   226
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   227
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   228
      eq_neq_eq_imp_neq) =>
ballarin@24639
   229
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   230
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   231
      not_sym, not_lessD, thm, not_lessI, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   232
  | update "not_lessI" thm thms =
ballarin@24639
   233
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   234
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   235
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   236
      eq_neq_eq_imp_neq) =>
ballarin@24639
   237
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   238
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   239
      not_sym, not_lessD, not_leD, thm, not_leI, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   240
  | update "not_leI" thm thms =
ballarin@24639
   241
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   242
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   243
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   244
      eq_neq_eq_imp_neq) =>
ballarin@24639
   245
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   246
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   247
      not_sym, not_lessD, not_leD, not_lessI, thm, less_imp_neq, eq_neq_eq_imp_neq))
ballarin@24639
   248
  | update "less_imp_neq" thm thms =
ballarin@24639
   249
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   250
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   251
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   252
      eq_neq_eq_imp_neq) =>
ballarin@24639
   253
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   254
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   255
      not_sym, not_lessD, not_leD, not_lessI, not_leI, thm, eq_neq_eq_imp_neq))
ballarin@24639
   256
  | update "eq_neq_eq_imp_neq" thm thms =
ballarin@24639
   257
    change thms (fn (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   258
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   259
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq,
ballarin@24639
   260
      eq_neq_eq_imp_neq) =>
ballarin@24639
   261
    (less_reflE, le_refl, less_imp_le, eqI, eqD1, eqD2, less_trans,
ballarin@24639
   262
      less_le_trans, le_less_trans, le_trans, le_neq_trans, neq_le_trans,
ballarin@24639
   263
      not_sym, not_lessD, not_leD, not_lessI, not_leI, less_imp_neq, thm));
ballarin@24639
   264
ballarin@14398
   265
(* Internal datatype for the proof *)
ballarin@14398
   266
datatype proof
wenzelm@32215
   267
  = Asm of int
wenzelm@32215
   268
  | Thm of proof list * thm;
wenzelm@32215
   269
ballarin@14398
   270
exception Cannot;
ballarin@14445
   271
 (* Internal exception, raised if conclusion cannot be derived from
ballarin@14398
   272
     assumptions. *)
ballarin@14398
   273
exception Contr of proof;
ballarin@14398
   274
  (* Internal exception, raised if contradiction ( x < x ) was derived *)
ballarin@14398
   275
wenzelm@32215
   276
fun prove asms =
wenzelm@42364
   277
  let
wenzelm@42364
   278
    fun pr (Asm i) = nth asms i
wenzelm@42364
   279
      | pr (Thm (prfs, thm)) = map pr prfs MRS thm;
ballarin@14398
   280
  in pr end;
ballarin@14398
   281
ballarin@14398
   282
(* Internal datatype for inequalities *)
wenzelm@32215
   283
datatype less
wenzelm@32215
   284
   = Less  of term * term * proof
ballarin@14398
   285
   | Le    of term * term * proof
wenzelm@32215
   286
   | NotEq of term * term * proof;
wenzelm@32215
   287
ballarin@14398
   288
(* Misc functions for datatype less *)
ballarin@14398
   289
fun lower (Less (x, _, _)) = x
ballarin@14398
   290
  | lower (Le (x, _, _)) = x
ballarin@14398
   291
  | lower (NotEq (x,_,_)) = x;
ballarin@14398
   292
ballarin@14398
   293
fun upper (Less (_, y, _)) = y
ballarin@14398
   294
  | upper (Le (_, y, _)) = y
ballarin@14398
   295
  | upper (NotEq (_,y,_)) = y;
ballarin@14398
   296
ballarin@14398
   297
fun getprf   (Less (_, _, p)) = p
ballarin@14398
   298
|   getprf   (Le   (_, _, p)) = p
ballarin@14398
   299
|   getprf   (NotEq (_,_, p)) = p;
ballarin@14398
   300
ballarin@24639
   301
ballarin@14398
   302
(* ************************************************************************ *)
ballarin@14398
   303
(*                                                                          *)
ballarin@24639
   304
(* mkasm_partial                                                            *)
ballarin@14398
   305
(*                                                                          *)
ballarin@14398
   306
(* Tuple (t, n) (t an assumption, n its index in the assumptions) is        *)
ballarin@14398
   307
(* translated to an element of type less.                                   *)
ballarin@14398
   308
(* Partial orders only.                                                     *)
ballarin@14398
   309
(*                                                                          *)
ballarin@14398
   310
(* ************************************************************************ *)
ballarin@14398
   311
haftmann@33206
   312
fun mkasm_partial decomp (less_thms : less_arith) sign (n, t) =
ballarin@24639
   313
  case decomp sign t of
skalberg@15531
   314
    SOME (x, rel, y) => (case rel of
wenzelm@32215
   315
      "<"   => if (x aconv y) then raise Contr (Thm ([Asm n], #less_reflE less_thms))
ballarin@14398
   316
               else [Less (x, y, Asm n)]
ballarin@14398
   317
    | "~<"  => []
ballarin@14398
   318
    | "<="  => [Le (x, y, Asm n)]
wenzelm@32215
   319
    | "~<=" => []
ballarin@24639
   320
    | "="   => [Le (x, y, Thm ([Asm n], #eqD1 less_thms)),
ballarin@24639
   321
                Le (y, x, Thm ([Asm n], #eqD2 less_thms))]
wenzelm@32215
   322
    | "~="  => if (x aconv y) then
ballarin@24639
   323
                  raise Contr (Thm ([(Thm ([(Thm ([], #le_refl less_thms)) ,(Asm n)], #le_neq_trans less_thms))], #less_reflE less_thms))
ballarin@14398
   324
               else [ NotEq (x, y, Asm n),
wenzelm@32215
   325
                      NotEq (y, x,Thm ( [Asm n], #not_sym less_thms))]
ballarin@14398
   326
    | _     => error ("partial_tac: unknown relation symbol ``" ^ rel ^
ballarin@24639
   327
                 "''returned by decomp."))
skalberg@15531
   328
  | NONE => [];
ballarin@14398
   329
ballarin@14398
   330
(* ************************************************************************ *)
ballarin@14398
   331
(*                                                                          *)
ballarin@24639
   332
(* mkasm_linear                                                             *)
ballarin@14398
   333
(*                                                                          *)
ballarin@14398
   334
(* Tuple (t, n) (t an assumption, n its index in the assumptions) is        *)
ballarin@14398
   335
(* translated to an element of type less.                                   *)
ballarin@14398
   336
(* Linear orders only.                                                      *)
ballarin@14398
   337
(*                                                                          *)
ballarin@14398
   338
(* ************************************************************************ *)
wenzelm@32215
   339
haftmann@33206
   340
fun mkasm_linear decomp (less_thms : less_arith) sign (n, t) =
ballarin@24639
   341
  case decomp sign t of
skalberg@15531
   342
    SOME (x, rel, y) => (case rel of
wenzelm@32215
   343
      "<"   => if (x aconv y) then raise Contr (Thm ([Asm n], #less_reflE less_thms))
ballarin@14398
   344
               else [Less (x, y, Asm n)]
ballarin@24639
   345
    | "~<"  => [Le (y, x, Thm ([Asm n], #not_lessD less_thms))]
ballarin@14398
   346
    | "<="  => [Le (x, y, Asm n)]
wenzelm@32215
   347
    | "~<=" => if (x aconv y) then
wenzelm@32215
   348
                  raise (Contr (Thm ([Thm ([Asm n], #not_leD less_thms)], #less_reflE less_thms)))
wenzelm@32215
   349
               else [Less (y, x, Thm ([Asm n], #not_leD less_thms))]
ballarin@24639
   350
    | "="   => [Le (x, y, Thm ([Asm n], #eqD1 less_thms)),
ballarin@24639
   351
                Le (y, x, Thm ([Asm n], #eqD2 less_thms))]
wenzelm@32215
   352
    | "~="  => if (x aconv y) then
ballarin@24639
   353
                  raise Contr (Thm ([(Thm ([(Thm ([], #le_refl less_thms)) ,(Asm n)], #le_neq_trans less_thms))], #less_reflE less_thms))
ballarin@14398
   354
               else [ NotEq (x, y, Asm n),
wenzelm@32215
   355
                      NotEq (y, x,Thm ( [Asm n], #not_sym less_thms))]
ballarin@14398
   356
    | _     => error ("linear_tac: unknown relation symbol ``" ^ rel ^
ballarin@24639
   357
                 "''returned by decomp."))
skalberg@15531
   358
  | NONE => [];
ballarin@14398
   359
ballarin@14398
   360
(* ************************************************************************ *)
ballarin@14398
   361
(*                                                                          *)
ballarin@24639
   362
(* mkconcl_partial                                                          *)
ballarin@14398
   363
(*                                                                          *)
ballarin@14398
   364
(* Translates conclusion t to an element of type less.                      *)
ballarin@14398
   365
(* Partial orders only.                                                     *)
ballarin@14398
   366
(*                                                                          *)
ballarin@14398
   367
(* ************************************************************************ *)
ballarin@14398
   368
ballarin@24639
   369
fun mkconcl_partial decomp (less_thms : less_arith) sign t =
ballarin@24639
   370
  case decomp sign t of
skalberg@15531
   371
    SOME (x, rel, y) => (case rel of
ballarin@14398
   372
      "<"   => ([Less (x, y, Asm ~1)], Asm 0)
ballarin@14398
   373
    | "<="  => ([Le (x, y, Asm ~1)], Asm 0)
ballarin@14398
   374
    | "="   => ([Le (x, y, Asm ~1), Le (y, x, Asm ~1)],
ballarin@24639
   375
                 Thm ([Asm 0, Asm 1], #eqI less_thms))
ballarin@14398
   376
    | "~="  => ([NotEq (x,y, Asm ~1)], Asm 0)
ballarin@14398
   377
    | _  => raise Cannot)
skalberg@15531
   378
  | NONE => raise Cannot;
ballarin@14398
   379
ballarin@14398
   380
(* ************************************************************************ *)
ballarin@14398
   381
(*                                                                          *)
ballarin@24639
   382
(* mkconcl_linear                                                           *)
ballarin@14398
   383
(*                                                                          *)
ballarin@14398
   384
(* Translates conclusion t to an element of type less.                      *)
ballarin@14398
   385
(* Linear orders only.                                                      *)
ballarin@14398
   386
(*                                                                          *)
ballarin@14398
   387
(* ************************************************************************ *)
ballarin@14398
   388
ballarin@24639
   389
fun mkconcl_linear decomp (less_thms : less_arith) sign t =
ballarin@24639
   390
  case decomp sign t of
skalberg@15531
   391
    SOME (x, rel, y) => (case rel of
ballarin@14398
   392
      "<"   => ([Less (x, y, Asm ~1)], Asm 0)
ballarin@24639
   393
    | "~<"  => ([Le (y, x, Asm ~1)], Thm ([Asm 0], #not_lessI less_thms))
ballarin@14398
   394
    | "<="  => ([Le (x, y, Asm ~1)], Asm 0)
ballarin@24639
   395
    | "~<=" => ([Less (y, x, Asm ~1)], Thm ([Asm 0], #not_leI less_thms))
ballarin@14398
   396
    | "="   => ([Le (x, y, Asm ~1), Le (y, x, Asm ~1)],
ballarin@24639
   397
                 Thm ([Asm 0, Asm 1], #eqI less_thms))
ballarin@14398
   398
    | "~="  => ([NotEq (x,y, Asm ~1)], Asm 0)
ballarin@14398
   399
    | _  => raise Cannot)
skalberg@15531
   400
  | NONE => raise Cannot;
ballarin@24639
   401
ballarin@24639
   402
ballarin@24639
   403
(*** The common part for partial and linear orders ***)
ballarin@24639
   404
ballarin@24639
   405
(* Analysis of premises and conclusion: *)
ballarin@24639
   406
(* decomp (`x Rel y') should yield (x, Rel, y)
ballarin@24639
   407
     where Rel is one of "<", "<=", "~<", "~<=", "=" and "~=",
ballarin@24639
   408
     other relation symbols cause an error message *)
ballarin@24639
   409
wenzelm@32215
   410
fun gen_order_tac mkasm mkconcl decomp' (less_thms : less_arith) ctxt prems =
ballarin@24639
   411
ballarin@24639
   412
let
ballarin@24639
   413
berghofe@26834
   414
fun decomp sign t = Option.map (fn (x, rel, y) =>
berghofe@26834
   415
  (Envir.beta_eta_contract x, rel, Envir.beta_eta_contract y)) (decomp' sign t);
berghofe@26834
   416
ballarin@14398
   417
(* ******************************************************************* *)
ballarin@14398
   418
(*                                                                     *)
ballarin@24639
   419
(* mergeLess                                                           *)
ballarin@14398
   420
(*                                                                     *)
ballarin@24639
   421
(* Merge two elements of type less according to the following rules    *)
ballarin@14398
   422
(*                                                                     *)
ballarin@14398
   423
(* x <  y && y <  z ==> x < z                                          *)
ballarin@14398
   424
(* x <  y && y <= z ==> x < z                                          *)
ballarin@14398
   425
(* x <= y && y <  z ==> x < z                                          *)
ballarin@14398
   426
(* x <= y && y <= z ==> x <= z                                         *)
ballarin@14398
   427
(* x <= y && x ~= y ==> x < y                                          *)
ballarin@14398
   428
(* x ~= y && x <= y ==> x < y                                          *)
ballarin@14398
   429
(* x <  y && x ~= y ==> x < y                                          *)
ballarin@14398
   430
(* x ~= y && x <  y ==> x < y                                          *)
ballarin@14398
   431
(*                                                                     *)
ballarin@14398
   432
(* ******************************************************************* *)
ballarin@14398
   433
ballarin@14398
   434
fun mergeLess (Less (x, _, p) , Less (_ , z, q)) =
ballarin@24639
   435
      Less (x, z, Thm ([p,q] , #less_trans less_thms))
ballarin@14398
   436
|   mergeLess (Less (x, _, p) , Le (_ , z, q)) =
ballarin@24639
   437
      Less (x, z, Thm ([p,q] , #less_le_trans less_thms))
ballarin@14398
   438
|   mergeLess (Le (x, _, p) , Less (_ , z, q)) =
ballarin@24639
   439
      Less (x, z, Thm ([p,q] , #le_less_trans less_thms))
ballarin@14398
   440
|   mergeLess (Le (x, z, p) , NotEq (x', z', q)) =
wenzelm@32215
   441
      if (x aconv x' andalso z aconv z' )
ballarin@24639
   442
      then Less (x, z, Thm ([p,q] , #le_neq_trans less_thms))
ballarin@14398
   443
      else error "linear/partial_tac: internal error le_neq_trans"
ballarin@14398
   444
|   mergeLess (NotEq (x, z, p) , Le (x' , z', q)) =
wenzelm@32215
   445
      if (x aconv x' andalso z aconv z')
ballarin@24639
   446
      then Less (x, z, Thm ([p,q] , #neq_le_trans less_thms))
ballarin@14398
   447
      else error "linear/partial_tac: internal error neq_le_trans"
ballarin@14398
   448
|   mergeLess (NotEq (x, z, p) , Less (x' , z', q)) =
wenzelm@32215
   449
      if (x aconv x' andalso z aconv z')
ballarin@14398
   450
      then Less ((x' , z', q))
ballarin@14398
   451
      else error "linear/partial_tac: internal error neq_less_trans"
ballarin@14398
   452
|   mergeLess (Less (x, z, p) , NotEq (x', z', q)) =
wenzelm@32215
   453
      if (x aconv x' andalso z aconv z')
ballarin@14398
   454
      then Less (x, z, p)
ballarin@14398
   455
      else error "linear/partial_tac: internal error less_neq_trans"
ballarin@14398
   456
|   mergeLess (Le (x, _, p) , Le (_ , z, q)) =
ballarin@24639
   457
      Le (x, z, Thm ([p,q] , #le_trans less_thms))
ballarin@14398
   458
|   mergeLess (_, _) =
ballarin@14398
   459
      error "linear/partial_tac: internal error: undefined case";
ballarin@14398
   460
ballarin@14398
   461
ballarin@14398
   462
(* ******************************************************************** *)
ballarin@14398
   463
(* tr checks for valid transitivity step                                *)
ballarin@14398
   464
(* ******************************************************************** *)
ballarin@14398
   465
ballarin@14398
   466
infix tr;
ballarin@14398
   467
fun (Less (_, y, _)) tr (Le (x', _, _))   = ( y aconv x' )
ballarin@14398
   468
  | (Le   (_, y, _)) tr (Less (x', _, _)) = ( y aconv x' )
ballarin@14398
   469
  | (Less (_, y, _)) tr (Less (x', _, _)) = ( y aconv x' )
ballarin@14398
   470
  | (Le (_, y, _))   tr (Le (x', _, _))   = ( y aconv x' )
ballarin@14398
   471
  | _ tr _ = false;
wenzelm@32215
   472
wenzelm@32215
   473
ballarin@14398
   474
(* ******************************************************************* *)
ballarin@14398
   475
(*                                                                     *)
ballarin@14398
   476
(* transPath (Lesslist, Less): (less list * less) -> less              *)
ballarin@14398
   477
(*                                                                     *)
ballarin@14398
   478
(* If a path represented by a list of elements of type less is found,  *)
ballarin@14398
   479
(* this needs to be contracted to a single element of type less.       *)
ballarin@14398
   480
(* Prior to each transitivity step it is checked whether the step is   *)
ballarin@14398
   481
(* valid.                                                              *)
ballarin@14398
   482
(*                                                                     *)
ballarin@14398
   483
(* ******************************************************************* *)
ballarin@14398
   484
ballarin@14398
   485
fun transPath ([],lesss) = lesss
ballarin@14398
   486
|   transPath (x::xs,lesss) =
ballarin@14398
   487
      if lesss tr x then transPath (xs, mergeLess(lesss,x))
ballarin@14398
   488
      else error "linear/partial_tac: internal error transpath";
wenzelm@32215
   489
ballarin@14398
   490
(* ******************************************************************* *)
ballarin@14398
   491
(*                                                                     *)
ballarin@14398
   492
(* less1 subsumes less2 : less -> less -> bool                         *)
ballarin@14398
   493
(*                                                                     *)
ballarin@14398
   494
(* subsumes checks whether less1 implies less2                         *)
ballarin@14398
   495
(*                                                                     *)
ballarin@14398
   496
(* ******************************************************************* *)
wenzelm@32215
   497
ballarin@14398
   498
infix subsumes;
ballarin@14398
   499
fun (Less (x, y, _)) subsumes (Le (x', y', _)) =
ballarin@14398
   500
      (x aconv x' andalso y aconv y')
ballarin@14398
   501
  | (Less (x, y, _)) subsumes (Less (x', y', _)) =
ballarin@14398
   502
      (x aconv x' andalso y aconv y')
ballarin@14398
   503
  | (Le (x, y, _)) subsumes (Le (x', y', _)) =
ballarin@14398
   504
      (x aconv x' andalso y aconv y')
ballarin@14398
   505
  | (Less (x, y, _)) subsumes (NotEq (x', y', _)) =
ballarin@14398
   506
      (x aconv x' andalso y aconv y') orelse (y aconv x' andalso x aconv y')
ballarin@14398
   507
  | (NotEq (x, y, _)) subsumes (NotEq (x', y', _)) =
ballarin@14398
   508
      (x aconv x' andalso y aconv y') orelse (y aconv x' andalso x aconv y')
ballarin@14398
   509
  | (Le _) subsumes (Less _) =
ballarin@14398
   510
      error "linear/partial_tac: internal error: Le cannot subsume Less"
ballarin@14398
   511
  | _ subsumes _ = false;
ballarin@14398
   512
ballarin@14398
   513
(* ******************************************************************* *)
ballarin@14398
   514
(*                                                                     *)
skalberg@15531
   515
(* triv_solv less1 : less ->  proof option                     *)
ballarin@14398
   516
(*                                                                     *)
ballarin@14398
   517
(* Solves trivial goal x <= x.                                         *)
ballarin@14398
   518
(*                                                                     *)
ballarin@14398
   519
(* ******************************************************************* *)
ballarin@14398
   520
ballarin@14398
   521
fun triv_solv (Le (x, x', _)) =
ballarin@24639
   522
    if x aconv x' then  SOME (Thm ([], #le_refl less_thms))
skalberg@15531
   523
    else NONE
skalberg@15531
   524
|   triv_solv _ = NONE;
ballarin@14398
   525
ballarin@14398
   526
(* ********************************************************************* *)
ballarin@14398
   527
(* Graph functions                                                       *)
ballarin@14398
   528
(* ********************************************************************* *)
ballarin@14398
   529
ballarin@14398
   530
ballarin@14398
   531
ballarin@14398
   532
(* ******************************************************************* *)
ballarin@14398
   533
(*                                                                     *)
ballarin@14398
   534
(* General:                                                            *)
ballarin@14398
   535
(*                                                                     *)
ballarin@14398
   536
(* Inequalities are represented by various types of graphs.            *)
ballarin@14398
   537
(*                                                                     *)
ballarin@14445
   538
(* 1. (Term.term * (Term.term * less) list) list                       *)
ballarin@14398
   539
(*    - Graph of this type is generated from the assumptions,          *)
ballarin@14398
   540
(*      it does contain information on which edge stems from which     *)
ballarin@14398
   541
(*      assumption.                                                    *)
ballarin@14445
   542
(*    - Used to compute strongly connected components                  *)
ballarin@14445
   543
(*    - Used to compute component subgraphs                            *)
ballarin@14445
   544
(*    - Used for component subgraphs to reconstruct paths in components*)
ballarin@14398
   545
(*                                                                     *)
ballarin@14445
   546
(* 2. (int * (int * less) list ) list                                  *)
ballarin@14398
   547
(*    - Graph of this type is generated from the strong components of  *)
ballarin@14445
   548
(*      graph of type 1.  It consists of the strong components of      *)
ballarin@14445
   549
(*      graph 1, where nodes are indices of the components.            *)
ballarin@14398
   550
(*      Only edges between components are part of this graph.          *)
ballarin@14398
   551
(*    - Used to reconstruct paths between several components.          *)
ballarin@14398
   552
(*                                                                     *)
ballarin@14398
   553
(* ******************************************************************* *)
ballarin@14398
   554
wenzelm@32215
   555
ballarin@14398
   556
(* *********************************************************** *)
ballarin@14398
   557
(* Functions for constructing graphs                           *)
ballarin@14398
   558
(* *********************************************************** *)
ballarin@14398
   559
ballarin@14445
   560
fun addEdge (v,d,[]) = [(v,d)]
ballarin@14445
   561
|   addEdge (v,d,((u,dl)::el)) = if v aconv u then ((v,d@dl)::el)
ballarin@14445
   562
    else (u,dl):: (addEdge(v,d,el));
wenzelm@32215
   563
ballarin@14398
   564
(* ********************************************************************* *)
ballarin@14398
   565
(*                                                                       *)
wenzelm@32215
   566
(* mkGraphs constructs from a list of objects of type less a graph g,    *)
ballarin@14445
   567
(* by taking all edges that are candidate for a <=, and a list neqE, by  *)
ballarin@14445
   568
(* taking all edges that are candiate for a ~=                           *)
ballarin@14398
   569
(*                                                                       *)
ballarin@14398
   570
(* ********************************************************************* *)
ballarin@14398
   571
ballarin@14445
   572
fun mkGraphs [] = ([],[],[])
wenzelm@32215
   573
|   mkGraphs lessList =
ballarin@14445
   574
 let
ballarin@14398
   575
ballarin@14445
   576
fun buildGraphs ([],leqG,neqG,neqE) = (leqG, neqG, neqE)
wenzelm@32215
   577
|   buildGraphs (l::ls, leqG,neqG, neqE) = case l of
wenzelm@32215
   578
  (Less (x,y,p)) =>
wenzelm@32215
   579
       buildGraphs (ls, addEdge (x,[(y,(Less (x, y, p)))],leqG) ,
wenzelm@32215
   580
                        addEdge (x,[(y,(Less (x, y, p)))],neqG), l::neqE)
ballarin@14398
   581
| (Le (x,y,p)) =>
wenzelm@32215
   582
      buildGraphs (ls, addEdge (x,[(y,(Le (x, y,p)))],leqG) , neqG, neqE)
wenzelm@32215
   583
| (NotEq  (x,y,p)) =>
ballarin@14445
   584
      buildGraphs (ls, leqG , addEdge (x,[(y,(NotEq (x, y, p)))],neqG), l::neqE) ;
ballarin@14445
   585
ballarin@14445
   586
  in buildGraphs (lessList, [], [], []) end;
ballarin@14398
   587
ballarin@14398
   588
ballarin@14398
   589
(* *********************************************************************** *)
ballarin@14398
   590
(*                                                                         *)
ballarin@14445
   591
(* adjacent g u : (''a * 'b list ) list -> ''a -> 'b list                  *)
ballarin@14398
   592
(*                                                                         *)
ballarin@14398
   593
(* List of successors of u in graph g                                      *)
ballarin@14398
   594
(*                                                                         *)
ballarin@14398
   595
(* *********************************************************************** *)
wenzelm@32215
   596
wenzelm@32215
   597
fun adjacent eq_comp ((v,adj)::el) u =
ballarin@14445
   598
    if eq_comp (u, v) then adj else adjacent eq_comp el u
wenzelm@32215
   599
|   adjacent _  []  _ = []
wenzelm@32215
   600
wenzelm@32215
   601
ballarin@14398
   602
(* *********************************************************************** *)
ballarin@14398
   603
(*                                                                         *)
ballarin@14398
   604
(* transpose g:                                                            *)
ballarin@14398
   605
(* (''a * ''a list) list -> (''a * ''a list) list                          *)
ballarin@14398
   606
(*                                                                         *)
ballarin@14398
   607
(* Computes transposed graph g' from g                                     *)
ballarin@14398
   608
(* by reversing all edges u -> v to v -> u                                 *)
ballarin@14398
   609
(*                                                                         *)
ballarin@14398
   610
(* *********************************************************************** *)
ballarin@14398
   611
ballarin@14445
   612
fun transpose eq_comp g =
ballarin@14398
   613
  let
ballarin@14398
   614
   (* Compute list of reversed edges for each adjacency list *)
ballarin@14445
   615
   fun flip (u,(v,l)::el) = (v,(u,l)) :: flip (u,el)
wenzelm@32768
   616
     | flip (_,[]) = []
wenzelm@32215
   617
ballarin@14398
   618
   (* Compute adjacency list for node u from the list of edges
ballarin@14398
   619
      and return a likewise reduced list of edges.  The list of edges
ballarin@14398
   620
      is searches for edges starting from u, and these edges are removed. *)
ballarin@14398
   621
   fun gather (u,(v,w)::el) =
ballarin@14398
   622
    let
ballarin@14398
   623
     val (adj,edges) = gather (u,el)
ballarin@14398
   624
    in
ballarin@14445
   625
     if eq_comp (u, v) then (w::adj,edges)
ballarin@14398
   626
     else (adj,(v,w)::edges)
ballarin@14398
   627
    end
wenzelm@32768
   628
   | gather (_,[]) = ([],[])
ballarin@14398
   629
ballarin@14398
   630
   (* For every node in the input graph, call gather to find all reachable
ballarin@14398
   631
      nodes in the list of edges *)
ballarin@14398
   632
   fun assemble ((u,_)::el) edges =
ballarin@14398
   633
       let val (adj,edges) = gather (u,edges)
ballarin@14398
   634
       in (u,adj) :: assemble el edges
ballarin@14398
   635
       end
wenzelm@32768
   636
     | assemble [] _ = []
ballarin@14398
   637
ballarin@14398
   638
   (* Compute, for each adjacency list, the list with reversed edges,
ballarin@14398
   639
      and concatenate these lists. *)
wenzelm@32768
   640
   val flipped = maps flip g
wenzelm@32215
   641
wenzelm@32215
   642
 in assemble g flipped end
wenzelm@32215
   643
ballarin@14445
   644
(* *********************************************************************** *)
wenzelm@32215
   645
(*                                                                         *)
ballarin@14445
   646
(* scc_term : (term * term list) list -> term list list                    *)
ballarin@14445
   647
(*                                                                         *)
ballarin@14445
   648
(* The following is based on the algorithm for finding strongly connected  *)
ballarin@14445
   649
(* components described in Introduction to Algorithms, by Cormon, Leiserson*)
ballarin@14445
   650
(* and Rivest, section 23.5. The input G is an adjacency list description  *)
ballarin@14445
   651
(* of a directed graph. The output is a list of the strongly connected     *)
wenzelm@32215
   652
(* components (each a list of vertices).                                   *)
wenzelm@32215
   653
(*                                                                         *)
ballarin@14445
   654
(*                                                                         *)
ballarin@14445
   655
(* *********************************************************************** *)
ballarin@14398
   656
ballarin@14398
   657
fun scc_term G =
ballarin@14398
   658
     let
ballarin@14398
   659
  (* Ordered list of the vertices that DFS has finished with;
ballarin@14398
   660
     most recently finished goes at the head. *)
wenzelm@32740
   661
  val finish : term list Unsynchronized.ref = Unsynchronized.ref []
ballarin@14398
   662
ballarin@14398
   663
  (* List of vertices which have been visited. *)
wenzelm@32740
   664
  val visited : term list Unsynchronized.ref = Unsynchronized.ref []
wenzelm@32215
   665
ballarin@14398
   666
  fun been_visited v = exists (fn w => w aconv v) (!visited)
wenzelm@32215
   667
ballarin@14398
   668
  (* Given the adjacency list rep of a graph (a list of pairs),
wenzelm@32215
   669
     return just the first element of each pair, yielding the
ballarin@14398
   670
     vertex list. *)
ballarin@14398
   671
  val members = map (fn (v,_) => v)
ballarin@14398
   672
ballarin@14398
   673
  (* Returns the nodes in the DFS tree rooted at u in g *)
ballarin@14398
   674
  fun dfs_visit g u : term list =
ballarin@14398
   675
      let
ballarin@14398
   676
   val _ = visited := u :: !visited
ballarin@14398
   677
   val descendents =
wenzelm@30190
   678
       List.foldr (fn ((v,l),ds) => if been_visited v then ds
ballarin@14398
   679
            else v :: dfs_visit g v @ ds)
wenzelm@32768
   680
        [] (adjacent (op aconv) g u)
ballarin@14398
   681
      in
ballarin@14398
   682
   finish := u :: !finish;
ballarin@14398
   683
   descendents
ballarin@14398
   684
      end
ballarin@14398
   685
     in
ballarin@14398
   686
ballarin@14398
   687
  (* DFS on the graph; apply dfs_visit to each vertex in
ballarin@14398
   688
     the graph, checking first to make sure the vertex is
ballarin@14398
   689
     as yet unvisited. *)
wenzelm@67379
   690
  List.app (fn u => if been_visited u then ()
ballarin@14398
   691
        else (dfs_visit G u; ()))  (members G);
wenzelm@32768
   692
  visited := [];
ballarin@14398
   693
ballarin@14398
   694
  (* We don't reset finish because its value is used by
ballarin@14445
   695
     foldl below, and it will never be used again (even
ballarin@14398
   696
     though dfs_visit will continue to modify it). *)
ballarin@14398
   697
ballarin@14398
   698
  (* DFS on the transpose. The vertices returned by
ballarin@14398
   699
     dfs_visit along with u form a connected component. We
ballarin@14398
   700
     collect all the connected components together in a
ballarin@14398
   701
     list, which is what is returned. *)
wenzelm@33245
   702
  fold (fn u => fn comps =>
ballarin@14398
   703
      if been_visited u then comps
wenzelm@33245
   704
      else (u :: dfs_visit (transpose (op aconv) G) u) :: comps) (!finish) []
ballarin@14398
   705
end;
ballarin@14398
   706
ballarin@14398
   707
ballarin@14398
   708
(* *********************************************************************** *)
ballarin@14398
   709
(*                                                                         *)
ballarin@14398
   710
(* dfs_int_reachable g u:                                                  *)
wenzelm@32215
   711
(* (int * int list) list -> int -> int list                                *)
ballarin@14398
   712
(*                                                                         *)
ballarin@14398
   713
(* Computes list of all nodes reachable from u in g.                       *)
ballarin@14398
   714
(*                                                                         *)
ballarin@14398
   715
(* *********************************************************************** *)
ballarin@14398
   716
wenzelm@32215
   717
fun dfs_int_reachable g u =
ballarin@14398
   718
 let
ballarin@14398
   719
  (* List of vertices which have been visited. *)
wenzelm@32740
   720
  val visited : int list Unsynchronized.ref = Unsynchronized.ref []
wenzelm@32215
   721
ballarin@14398
   722
  fun been_visited v = exists (fn w => w = v) (!visited)
ballarin@14398
   723
ballarin@14398
   724
  fun dfs_visit g u : int list =
ballarin@14398
   725
      let
ballarin@14398
   726
   val _ = visited := u :: !visited
ballarin@14398
   727
   val descendents =
wenzelm@30190
   728
       List.foldr (fn ((v,l),ds) => if been_visited v then ds
ballarin@14398
   729
            else v :: dfs_visit g v @ ds)
wenzelm@32768
   730
        [] (adjacent (op =) g u)
ballarin@14398
   731
   in  descendents end
wenzelm@32215
   732
ballarin@14398
   733
 in u :: dfs_visit g u end;
ballarin@14398
   734
wenzelm@32215
   735
wenzelm@32215
   736
fun indexNodes IndexComp =
wenzelm@32952
   737
    maps (fn (index, comp) => (map (fn v => (v,index)) comp)) IndexComp;
wenzelm@32215
   738
ballarin@14398
   739
fun getIndex v [] = ~1
wenzelm@32215
   740
|   getIndex v ((v',k)::vs) = if v aconv v' then k else getIndex v vs;
wenzelm@32215
   741
ballarin@14398
   742
ballarin@14398
   743
ballarin@14398
   744
(* *********************************************************************** *)
ballarin@14398
   745
(*                                                                         *)
ballarin@14445
   746
(* dfs eq_comp g u v:                                                       *)
ballarin@14445
   747
(* ('a * 'a -> bool) -> ('a  *( 'a * less) list) list ->                   *)
wenzelm@32215
   748
(* 'a -> 'a -> (bool * ('a * less) list)                                   *)
ballarin@14398
   749
(*                                                                         *)
ballarin@14398
   750
(* Depth first search of v from u.                                         *)
ballarin@14398
   751
(* Returns (true, path(u, v)) if successful, otherwise (false, []).        *)
ballarin@14398
   752
(*                                                                         *)
ballarin@14398
   753
(* *********************************************************************** *)
ballarin@14398
   754
wenzelm@32215
   755
fun dfs eq_comp g u v =
wenzelm@32215
   756
 let
wenzelm@32740
   757
    val pred = Unsynchronized.ref [];
wenzelm@32740
   758
    val visited = Unsynchronized.ref [];
wenzelm@32215
   759
ballarin@14445
   760
    fun been_visited v = exists (fn w => eq_comp (w, v)) (!visited)
wenzelm@32215
   761
wenzelm@32215
   762
    fun dfs_visit u' =
ballarin@14398
   763
    let val _ = visited := u' :: (!visited)
wenzelm@32215
   764
ballarin@14445
   765
    fun update (x,l) = let val _ = pred := (x,l) ::(!pred) in () end;
wenzelm@32215
   766
wenzelm@32215
   767
    in if been_visited v then ()
wenzelm@67379
   768
    else (List.app (fn (v',l) => if been_visited v' then () else (
wenzelm@32215
   769
       update (v',l);
ballarin@14445
   770
       dfs_visit v'; ()) )) (adjacent eq_comp g u')
ballarin@14445
   771
     end
wenzelm@32215
   772
  in
wenzelm@32215
   773
    dfs_visit u;
wenzelm@32215
   774
    if (been_visited v) then (true, (!pred)) else (false , [])
ballarin@14398
   775
  end;
ballarin@14398
   776
wenzelm@32215
   777
ballarin@14398
   778
(* *********************************************************************** *)
ballarin@14398
   779
(*                                                                         *)
ballarin@14398
   780
(* completeTermPath u v g:                                                 *)
wenzelm@32215
   781
(* Term.term -> Term.term -> (Term.term * (Term.term * less) list) list    *)
ballarin@14398
   782
(* -> less list                                                            *)
ballarin@14398
   783
(*                                                                         *)
ballarin@14398
   784
(* Complete the path from u to v in graph g.  Path search is performed     *)
ballarin@14398
   785
(* with dfs_term g u v.  This yields for each node v' its predecessor u'   *)
ballarin@14398
   786
(* and the edge u' -> v'.  Allows traversing graph backwards from v and    *)
ballarin@14398
   787
(* finding the path u -> v.                                                *)
ballarin@14398
   788
(*                                                                         *)
ballarin@14398
   789
(* *********************************************************************** *)
ballarin@14398
   790
wenzelm@32215
   791
wenzelm@32215
   792
fun completeTermPath u v g  =
wenzelm@32215
   793
  let
ballarin@14445
   794
   val (found, tmp) =  dfs (op aconv) g u v ;
ballarin@14445
   795
   val pred = map snd tmp;
wenzelm@32215
   796
ballarin@14398
   797
   fun path x y  =
ballarin@14398
   798
      let
wenzelm@32215
   799
ballarin@14398
   800
      (* find predecessor u of node v and the edge u -> v *)
ballarin@14398
   801
ballarin@14398
   802
      fun lookup v [] = raise Cannot
ballarin@14398
   803
      |   lookup v (e::es) = if (upper e) aconv v then e else lookup v es;
ballarin@14398
   804
wenzelm@32215
   805
      (* traverse path backwards and return list of visited edges *)
wenzelm@32215
   806
      fun rev_path v =
ballarin@14398
   807
       let val l = lookup v pred
ballarin@14398
   808
           val u = lower l;
ballarin@14398
   809
       in
ballarin@14398
   810
        if u aconv x then [l]
wenzelm@32215
   811
        else (rev_path u) @ [l]
ballarin@14398
   812
       end
ballarin@14398
   813
     in rev_path y end;
wenzelm@32215
   814
wenzelm@32215
   815
  in
ballarin@24639
   816
  if found then (if u aconv v then [(Le (u, v, (Thm ([], #le_refl less_thms))))]
ballarin@14398
   817
  else path u v ) else raise Cannot
wenzelm@32215
   818
end;
ballarin@14398
   819
wenzelm@32215
   820
ballarin@14398
   821
(* *********************************************************************** *)
ballarin@14398
   822
(*                                                                         *)
ballarin@14445
   823
(* findProof (sccGraph, neqE, ntc, sccSubgraphs) subgoal:                  *)
ballarin@14398
   824
(*                                                                         *)
ballarin@14445
   825
(* (int * (int * less) list) list * less list *  (Term.term * int) list    *)
ballarin@14445
   826
(* * ((term * (term * less) list) list) list -> Less -> proof              *)
ballarin@14398
   827
(*                                                                         *)
ballarin@14445
   828
(* findProof constructs from graphs (sccGraph, sccSubgraphs) and neqE a    *)
ballarin@14445
   829
(* proof for subgoal.  Raises exception Cannot if this is not possible.    *)
ballarin@14398
   830
(*                                                                         *)
ballarin@14398
   831
(* *********************************************************************** *)
wenzelm@32215
   832
ballarin@14445
   833
fun findProof (sccGraph, neqE, ntc, sccSubgraphs) subgoal =
ballarin@14398
   834
let
wenzelm@32215
   835
ballarin@14398
   836
 (* complete path x y from component graph *)
wenzelm@32215
   837
 fun completeComponentPath x y predlist =
wenzelm@32215
   838
   let
wenzelm@32215
   839
          val xi = getIndex x ntc
wenzelm@32215
   840
          val yi = getIndex y ntc
wenzelm@32215
   841
wenzelm@32215
   842
          fun lookup k [] =  raise Cannot
wenzelm@32215
   843
          |   lookup k ((h: int,l)::us) = if k = h then l else lookup k us;
wenzelm@32215
   844
wenzelm@32215
   845
          fun rev_completeComponentPath y' =
wenzelm@32215
   846
           let val edge = lookup (getIndex y' ntc) predlist
wenzelm@32215
   847
               val u = lower edge
wenzelm@32215
   848
               val v = upper edge
wenzelm@32215
   849
           in
wenzelm@32215
   850
             if (getIndex u ntc) = xi then
wenzelm@42364
   851
               completeTermPath x u (nth sccSubgraphs xi) @ [edge] @
wenzelm@42364
   852
               completeTermPath v y' (nth sccSubgraphs (getIndex y' ntc))
wenzelm@42364
   853
             else
wenzelm@42364
   854
              rev_completeComponentPath u @ [edge] @
wenzelm@42364
   855
                completeTermPath v y' (nth sccSubgraphs (getIndex y' ntc))
ballarin@14398
   856
           end
wenzelm@32215
   857
   in
wenzelm@42364
   858
     if x aconv y then
wenzelm@42364
   859
       [(Le (x, y, (Thm ([], #le_refl less_thms))))]
wenzelm@42364
   860
     else if xi = yi then completeTermPath x y (nth sccSubgraphs xi)
wenzelm@42364
   861
     else rev_completeComponentPath y
ballarin@14398
   862
   end;
ballarin@14398
   863
wenzelm@32215
   864
(* ******************************************************************* *)
ballarin@14398
   865
(* findLess e x y xi yi xreachable yreachable                          *)
ballarin@14398
   866
(*                                                                     *)
ballarin@14398
   867
(* Find a path from x through e to y, of weight <                      *)
wenzelm@32215
   868
(* ******************************************************************* *)
wenzelm@32215
   869
wenzelm@32215
   870
 fun findLess e x y xi yi xreachable yreachable =
wenzelm@32215
   871
  let val u = lower e
ballarin@14398
   872
      val v = upper e
ballarin@14398
   873
      val ui = getIndex u ntc
ballarin@14398
   874
      val vi = getIndex v ntc
wenzelm@32215
   875
wenzelm@32215
   876
  in
haftmann@36692
   877
      if member (op =) xreachable ui andalso member (op =) xreachable vi andalso
haftmann@36692
   878
         member (op =) yreachable ui andalso member (op =) yreachable vi then (
wenzelm@32215
   879
wenzelm@32215
   880
  (case e of (Less (_, _, _)) =>
ballarin@14398
   881
       let
ballarin@14445
   882
        val (xufound, xupred) =  dfs (op =) sccGraph xi (getIndex u ntc)
wenzelm@32215
   883
            in
wenzelm@32215
   884
             if xufound then (
wenzelm@32215
   885
              let
wenzelm@32215
   886
               val (vyfound, vypred) =  dfs (op =) sccGraph (getIndex v ntc) yi
wenzelm@32215
   887
              in
wenzelm@32215
   888
               if vyfound then (
wenzelm@32215
   889
                let
wenzelm@32215
   890
                 val xypath = (completeComponentPath x u xupred)@[e]@(completeComponentPath v y vypred)
wenzelm@32215
   891
                 val xyLesss = transPath (tl xypath, hd xypath)
wenzelm@32215
   892
                in
wenzelm@32215
   893
                 if xyLesss subsumes subgoal then SOME (getprf xyLesss)
skalberg@15531
   894
                 else NONE
wenzelm@32215
   895
               end)
wenzelm@32215
   896
               else NONE
wenzelm@32215
   897
              end)
wenzelm@32215
   898
             else NONE
wenzelm@32215
   899
            end
wenzelm@32215
   900
       |  _   =>
wenzelm@32215
   901
         let val (uvfound, uvpred) =  dfs (op =) sccGraph (getIndex u ntc) (getIndex v ntc)
wenzelm@32215
   902
             in
wenzelm@32215
   903
              if uvfound then (
wenzelm@32215
   904
               let
wenzelm@32215
   905
                val (xufound, xupred) = dfs (op =) sccGraph xi (getIndex u ntc)
wenzelm@32215
   906
               in
wenzelm@32215
   907
                if xufound then (
wenzelm@32215
   908
                 let
wenzelm@32215
   909
                  val (vyfound, vypred) =  dfs (op =) sccGraph (getIndex v ntc) yi
wenzelm@32215
   910
                 in
wenzelm@32215
   911
                  if vyfound then (
wenzelm@32215
   912
                   let
wenzelm@32215
   913
                    val uvpath = completeComponentPath u v uvpred
wenzelm@32215
   914
                    val uvLesss = mergeLess ( transPath (tl uvpath, hd uvpath), e)
wenzelm@32215
   915
                    val xypath = (completeComponentPath  x u xupred)@[uvLesss]@(completeComponentPath v y vypred)
wenzelm@32215
   916
                    val xyLesss = transPath (tl xypath, hd xypath)
wenzelm@32215
   917
                   in
wenzelm@32215
   918
                    if xyLesss subsumes subgoal then SOME (getprf xyLesss)
skalberg@15531
   919
                    else NONE
wenzelm@32215
   920
                   end )
wenzelm@32215
   921
                  else NONE
wenzelm@32215
   922
                 end)
wenzelm@32215
   923
                else NONE
wenzelm@32215
   924
               end )
wenzelm@32215
   925
              else NONE
wenzelm@32215
   926
             end )
skalberg@15531
   927
    ) else NONE
wenzelm@32215
   928
end;
wenzelm@32215
   929
wenzelm@32215
   930
ballarin@14398
   931
in
ballarin@14398
   932
  (* looking for x <= y: any path from x to y is sufficient *)
ballarin@14398
   933
  case subgoal of (Le (x, y, _)) => (
wenzelm@32215
   934
  if null sccGraph then raise Cannot else (
wenzelm@32215
   935
   let
ballarin@14398
   936
    val xi = getIndex x ntc
ballarin@14398
   937
    val yi = getIndex y ntc
ballarin@14445
   938
    (* searches in sccGraph a path from xi to yi *)
ballarin@14445
   939
    val (found, pred) = dfs (op =) sccGraph xi yi
wenzelm@32215
   940
   in
ballarin@14398
   941
    if found then (
wenzelm@32215
   942
       let val xypath = completeComponentPath x y pred
wenzelm@32215
   943
           val xyLesss = transPath (tl xypath, hd xypath)
wenzelm@32215
   944
       in
wenzelm@32215
   945
          (case xyLesss of
wenzelm@32215
   946
            (Less (_, _, q)) => if xyLesss subsumes subgoal then (Thm ([q], #less_imp_le less_thms))
wenzelm@32215
   947
                                else raise Cannot
wenzelm@32215
   948
             | _   => if xyLesss subsumes subgoal then (getprf xyLesss)
wenzelm@32215
   949
                      else raise Cannot)
ballarin@14398
   950
       end )
wenzelm@32215
   951
     else raise Cannot
wenzelm@32215
   952
   end
ballarin@14445
   953
    )
ballarin@14398
   954
   )
ballarin@14398
   955
 (* looking for x < y: particular path required, which is not necessarily
ballarin@14398
   956
    found by normal dfs *)
ballarin@14398
   957
 |   (Less (x, y, _)) => (
wenzelm@19617
   958
  if null sccGraph then raise Cannot else (
wenzelm@32215
   959
   let
ballarin@14398
   960
    val xi = getIndex x ntc
ballarin@14398
   961
    val yi = getIndex y ntc
ballarin@14445
   962
    val sccGraph_transpose = transpose (op =) sccGraph
ballarin@14445
   963
    (* all components that can be reached from component xi  *)
ballarin@14445
   964
    val xreachable = dfs_int_reachable sccGraph xi
ballarin@14445
   965
    (* all comonents reachable from y in the transposed graph sccGraph' *)
ballarin@14445
   966
    val yreachable = dfs_int_reachable sccGraph_transpose yi
ballarin@14398
   967
    (* for all edges u ~= v or u < v check if they are part of path x < y *)
wenzelm@32215
   968
    fun processNeqEdges [] = raise Cannot
wenzelm@32215
   969
    |   processNeqEdges (e::es) =
wenzelm@32215
   970
      case  (findLess e x y xi yi xreachable yreachable) of (SOME prf) => prf
ballarin@14398
   971
      | _ => processNeqEdges es
wenzelm@32215
   972
wenzelm@32215
   973
    in
wenzelm@32215
   974
       processNeqEdges neqE
ballarin@14398
   975
    end
ballarin@14445
   976
  )
ballarin@14398
   977
 )
ballarin@14398
   978
| (NotEq (x, y, _)) => (
ballarin@14445
   979
  (* if there aren't any edges that are candidate for a ~= raise Cannot *)
wenzelm@19617
   980
  if null neqE then raise Cannot
ballarin@14445
   981
  (* if there aren't any edges that are candidate for <= then just search a edge in neqE that implies the subgoal *)
wenzelm@19617
   982
  else if null sccSubgraphs then (
wenzelm@59584
   983
     (case (find_first (fn fact => fact subsumes subgoal) neqE, subgoal) of
skalberg@15531
   984
       ( SOME (NotEq (x, y, p)), NotEq (x', y', _)) =>
wenzelm@32215
   985
          if  (x aconv x' andalso y aconv y') then p
wenzelm@32215
   986
          else Thm ([p], #not_sym less_thms)
wenzelm@32215
   987
     | ( SOME (Less (x, y, p)), NotEq (x', y', _)) =>
ballarin@24639
   988
          if x aconv x' andalso y aconv y' then (Thm ([p], #less_imp_neq less_thms))
ballarin@24639
   989
          else (Thm ([(Thm ([p], #less_imp_neq less_thms))], #not_sym less_thms))
wenzelm@32215
   990
     | _ => raise Cannot)
ballarin@14445
   991
   ) else (
wenzelm@32215
   992
wenzelm@32215
   993
   let  val xi = getIndex x ntc
ballarin@14398
   994
        val yi = getIndex y ntc
wenzelm@32215
   995
        val sccGraph_transpose = transpose (op =) sccGraph
ballarin@14445
   996
        val xreachable = dfs_int_reachable sccGraph xi
wenzelm@32215
   997
        val yreachable = dfs_int_reachable sccGraph_transpose yi
wenzelm@32215
   998
wenzelm@32215
   999
        fun processNeqEdges [] = raise Cannot
wenzelm@32215
  1000
        |   processNeqEdges (e::es) = (
wenzelm@32215
  1001
            let val u = lower e
wenzelm@32215
  1002
                val v = upper e
wenzelm@32215
  1003
                val ui = getIndex u ntc
wenzelm@32215
  1004
                val vi = getIndex v ntc
wenzelm@32215
  1005
wenzelm@32215
  1006
            in
wenzelm@32215
  1007
                (* if x ~= y follows from edge e *)
wenzelm@32215
  1008
                if e subsumes subgoal then (
wenzelm@32215
  1009
                     case e of (Less (u, v, q)) => (
wenzelm@32215
  1010
                       if u aconv x andalso v aconv y then (Thm ([q], #less_imp_neq less_thms))
wenzelm@32215
  1011
                       else (Thm ([(Thm ([q], #less_imp_neq less_thms))], #not_sym less_thms))
wenzelm@32215
  1012
                     )
wenzelm@32215
  1013
                     |    (NotEq (u,v, q)) => (
wenzelm@32215
  1014
                       if u aconv x andalso v aconv y then q
wenzelm@32215
  1015
                       else (Thm ([q],  #not_sym less_thms))
wenzelm@32215
  1016
                     )
wenzelm@32215
  1017
                 )
ballarin@14398
  1018
                (* if SCC_x is linked to SCC_y via edge e *)
wenzelm@32215
  1019
                 else if ui = xi andalso vi = yi then (
ballarin@14398
  1020
                   case e of (Less (_, _,_)) => (
wenzelm@42364
  1021
                        let
wenzelm@42364
  1022
                          val xypath =
wenzelm@42364
  1023
                            completeTermPath x u (nth sccSubgraphs ui) @ [e] @
wenzelm@42364
  1024
                            completeTermPath v y (nth sccSubgraphs vi)
wenzelm@42364
  1025
                          val xyLesss = transPath (tl xypath, hd xypath)
wenzelm@32215
  1026
                        in  (Thm ([getprf xyLesss], #less_imp_neq less_thms)) end)
wenzelm@32215
  1027
                   | _ => (
wenzelm@32215
  1028
                        let
wenzelm@42364
  1029
                            val xupath = completeTermPath x u (nth sccSubgraphs ui)
wenzelm@42364
  1030
                            val uxpath = completeTermPath u x (nth sccSubgraphs ui)
wenzelm@42364
  1031
                            val vypath = completeTermPath v y (nth sccSubgraphs vi)
wenzelm@42364
  1032
                            val yvpath = completeTermPath y v (nth sccSubgraphs vi)
wenzelm@32215
  1033
                            val xuLesss = transPath (tl xupath, hd xupath)
wenzelm@32215
  1034
                            val uxLesss = transPath (tl uxpath, hd uxpath)
wenzelm@32215
  1035
                            val vyLesss = transPath (tl vypath, hd vypath)
wenzelm@32215
  1036
                            val yvLesss = transPath (tl yvpath, hd yvpath)
wenzelm@32215
  1037
                            val x_eq_u =  (Thm ([(getprf xuLesss),(getprf uxLesss)], #eqI less_thms))
wenzelm@32215
  1038
                            val v_eq_y =  (Thm ([(getprf vyLesss),(getprf yvLesss)], #eqI less_thms))
wenzelm@32215
  1039
                        in
wenzelm@32215
  1040
                           (Thm ([x_eq_u , (getprf e), v_eq_y ], #eq_neq_eq_imp_neq less_thms))
wenzelm@32215
  1041
                        end
wenzelm@32215
  1042
                        )
wenzelm@32215
  1043
                  ) else if ui = yi andalso vi = xi then (
wenzelm@32215
  1044
                     case e of (Less (_, _,_)) => (
wenzelm@42364
  1045
                        let
wenzelm@42364
  1046
                          val xypath =
wenzelm@42364
  1047
                            completeTermPath y u (nth sccSubgraphs ui) @ [e] @
wenzelm@42364
  1048
                            completeTermPath v x (nth sccSubgraphs vi)
wenzelm@42364
  1049
                          val xyLesss = transPath (tl xypath, hd xypath)
wenzelm@32215
  1050
                        in (Thm ([(Thm ([getprf xyLesss], #less_imp_neq less_thms))] , #not_sym less_thms)) end )
wenzelm@32215
  1051
                     | _ => (
wenzelm@32215
  1052
wenzelm@42364
  1053
                        let val yupath = completeTermPath y u (nth sccSubgraphs ui)
wenzelm@42364
  1054
                            val uypath = completeTermPath u y (nth sccSubgraphs ui)
wenzelm@42364
  1055
                            val vxpath = completeTermPath v x (nth sccSubgraphs vi)
wenzelm@42364
  1056
                            val xvpath = completeTermPath x v (nth sccSubgraphs vi)
wenzelm@32215
  1057
                            val yuLesss = transPath (tl yupath, hd yupath)
wenzelm@32215
  1058
                            val uyLesss = transPath (tl uypath, hd uypath)
wenzelm@32215
  1059
                            val vxLesss = transPath (tl vxpath, hd vxpath)
wenzelm@32215
  1060
                            val xvLesss = transPath (tl xvpath, hd xvpath)
wenzelm@32215
  1061
                            val y_eq_u =  (Thm ([(getprf yuLesss),(getprf uyLesss)], #eqI less_thms))
wenzelm@32215
  1062
                            val v_eq_x =  (Thm ([(getprf vxLesss),(getprf xvLesss)], #eqI less_thms))
wenzelm@32215
  1063
                        in
wenzelm@32215
  1064
                            (Thm ([(Thm ([y_eq_u , (getprf e), v_eq_x ], #eq_neq_eq_imp_neq less_thms))], #not_sym less_thms))
wenzelm@32215
  1065
                        end
wenzelm@32215
  1066
                       )
wenzelm@32215
  1067
                  ) else (
ballarin@14398
  1068
                       (* there exists a path x < y or y < x such that
ballarin@14398
  1069
                          x ~= y may be concluded *)
wenzelm@32215
  1070
                        case  (findLess e x y xi yi xreachable yreachable) of
wenzelm@32215
  1071
                              (SOME prf) =>  (Thm ([prf], #less_imp_neq less_thms))
skalberg@15531
  1072
                             | NONE =>  (
wenzelm@32215
  1073
                               let
wenzelm@32215
  1074
                                val yr = dfs_int_reachable sccGraph yi
wenzelm@32215
  1075
                                val xr = dfs_int_reachable sccGraph_transpose xi
wenzelm@32215
  1076
                               in
wenzelm@32215
  1077
                                case  (findLess e y x yi xi yr xr) of
wenzelm@32215
  1078
                                      (SOME prf) => (Thm ([(Thm ([prf], #less_imp_neq less_thms))], #not_sym less_thms))
ballarin@14398
  1079
                                      | _ => processNeqEdges es
wenzelm@32215
  1080
                               end)
wenzelm@32215
  1081
                 ) end)
ballarin@14445
  1082
     in processNeqEdges neqE end)
wenzelm@32215
  1083
  )
ballarin@14398
  1084
end;
ballarin@14398
  1085
ballarin@14398
  1086
ballarin@14445
  1087
(* ******************************************************************* *)
ballarin@14445
  1088
(*                                                                     *)
ballarin@14445
  1089
(* mk_sccGraphs components leqG neqG ntc :                             *)
ballarin@14445
  1090
(* Term.term list list ->                                              *)
ballarin@14445
  1091
(* (Term.term * (Term.term * less) list) list ->                       *)
ballarin@14445
  1092
(* (Term.term * (Term.term * less) list) list ->                       *)
ballarin@14445
  1093
(* (Term.term * int)  list ->                                          *)
ballarin@14445
  1094
(* (int * (int * less) list) list   *                                  *)
ballarin@14445
  1095
(* ((Term.term * (Term.term * less) list) list) list                   *)
ballarin@14445
  1096
(*                                                                     *)
ballarin@14445
  1097
(*                                                                     *)
ballarin@14445
  1098
(* Computes, from graph leqG, list of all its components and the list  *)
ballarin@14445
  1099
(* ntc (nodes, index of component) a graph whose nodes are the         *)
ballarin@14445
  1100
(* indices of the components of g.  Egdes of the new graph are         *)
ballarin@14445
  1101
(* only the edges of g linking two components. Also computes for each  *)
ballarin@14445
  1102
(* component the subgraph of leqG that forms this component.           *)
ballarin@14445
  1103
(*                                                                     *)
ballarin@14445
  1104
(* For each component SCC_i is checked if there exists a edge in neqG  *)
ballarin@14445
  1105
(* that leads to a contradiction.                                      *)
ballarin@14445
  1106
(*                                                                     *)
ballarin@14445
  1107
(* We have a contradiction for edge u ~= v and u < v if:               *)
ballarin@14445
  1108
(* - u and v are in the same component,                                *)
ballarin@14445
  1109
(* that is, a path u <= v and a path v <= u exist, hence u = v.        *)
ballarin@14445
  1110
(* From irreflexivity of < follows u < u or v < v. Ex false quodlibet. *)
ballarin@14445
  1111
(*                                                                     *)
ballarin@14445
  1112
(* ******************************************************************* *)
ballarin@14398
  1113
ballarin@14445
  1114
fun mk_sccGraphs _ [] _ _ = ([],[])
wenzelm@32215
  1115
|   mk_sccGraphs components leqG neqG ntc =
ballarin@14445
  1116
    let
ballarin@14445
  1117
    (* Liste (Index der Komponente, Komponente *)
haftmann@33063
  1118
    val IndexComp = map_index I components;
ballarin@14398
  1119
wenzelm@32215
  1120
wenzelm@32215
  1121
    fun handleContr edge g =
wenzelm@32215
  1122
       (case edge of
ballarin@14398
  1123
          (Less  (x, y, _)) => (
wenzelm@32215
  1124
            let
wenzelm@32215
  1125
             val xxpath = edge :: (completeTermPath y x g )
wenzelm@32215
  1126
             val xxLesss = transPath (tl xxpath, hd xxpath)
wenzelm@32215
  1127
             val q = getprf xxLesss
wenzelm@32215
  1128
            in
wenzelm@32215
  1129
             raise (Contr (Thm ([q], #less_reflE less_thms )))
wenzelm@32215
  1130
            end
wenzelm@32215
  1131
          )
ballarin@14398
  1132
        | (NotEq (x, y, _)) => (
wenzelm@32215
  1133
            let
wenzelm@32215
  1134
             val xypath = (completeTermPath x y g )
wenzelm@32215
  1135
             val yxpath = (completeTermPath y x g )
wenzelm@32215
  1136
             val xyLesss = transPath (tl xypath, hd xypath)
wenzelm@32215
  1137
             val yxLesss = transPath (tl yxpath, hd yxpath)
wenzelm@32215
  1138
             val q = getprf (mergeLess ((mergeLess (edge, xyLesss)),yxLesss ))
wenzelm@32215
  1139
            in
wenzelm@32215
  1140
             raise (Contr (Thm ([q], #less_reflE less_thms )))
wenzelm@32215
  1141
            end
wenzelm@32215
  1142
         )
wenzelm@32215
  1143
        | _ =>  error "trans_tac/handleContr: invalid Contradiction");
wenzelm@32215
  1144
wenzelm@32215
  1145
wenzelm@32215
  1146
    (* k is index of the actual component *)
wenzelm@32215
  1147
wenzelm@32215
  1148
    fun processComponent (k, comp) =
wenzelm@32215
  1149
     let
wenzelm@32215
  1150
        (* all edges with weight <= of the actual component *)
wenzelm@32952
  1151
        val leqEdges = maps (adjacent (op aconv) leqG) comp;
wenzelm@32215
  1152
        (* all edges with weight ~= of the actual component *)
wenzelm@32952
  1153
        val neqEdges = map snd (maps (adjacent (op aconv) neqG) comp);
ballarin@14398
  1154
wenzelm@32215
  1155
       (* find an edge leading to a contradiction *)
skalberg@15531
  1156
       fun findContr [] = NONE
wenzelm@32215
  1157
       |   findContr (e::es) =
wenzelm@32215
  1158
                    let val ui = (getIndex (lower e) ntc)
wenzelm@32215
  1159
                        val vi = (getIndex (upper e) ntc)
wenzelm@32215
  1160
                    in
wenzelm@32215
  1161
                        if ui = vi then  SOME e
wenzelm@32215
  1162
                        else findContr es
wenzelm@32215
  1163
                    end;
wenzelm@32215
  1164
wenzelm@32215
  1165
                (* sort edges into component internal edges and
wenzelm@32215
  1166
                   edges pointing away from the component *)
wenzelm@32215
  1167
                fun sortEdges  [] (intern,extern)  = (intern,extern)
wenzelm@32215
  1168
                |   sortEdges  ((v,l)::es) (intern, extern) =
wenzelm@32215
  1169
                    let val k' = getIndex v ntc in
wenzelm@32215
  1170
                        if k' = k then
wenzelm@32215
  1171
                            sortEdges es (l::intern, extern)
wenzelm@32215
  1172
                        else sortEdges  es (intern, (k',l)::extern) end;
wenzelm@32215
  1173
wenzelm@32215
  1174
                (* Insert edge into sorted list of edges, where edge is
ballarin@14445
  1175
                    only added if
ballarin@14445
  1176
                    - it is found for the first time
ballarin@14445
  1177
                    - it is a <= edge and no parallel < edge was found earlier
ballarin@14445
  1178
                    - it is a < edge
ballarin@14445
  1179
                 *)
wenzelm@32215
  1180
                 fun insert (h: int,l) [] = [(h,l)]
wenzelm@32215
  1181
                 |   insert (h,l) ((k',l')::es) = if h = k' then (
wenzelm@32215
  1182
                     case l of (Less (_, _, _)) => (h,l)::es
wenzelm@32215
  1183
                     | _  => (case l' of (Less (_, _, _)) => (h,l')::es
wenzelm@32215
  1184
                              | _ => (k',l)::es) )
wenzelm@32215
  1185
                     else (k',l'):: insert (h,l) es;
wenzelm@32215
  1186
wenzelm@32215
  1187
                (* Reorganise list of edges such that
ballarin@14445
  1188
                    - duplicate edges are removed
ballarin@14445
  1189
                    - if a < edge and a <= edge exist at the same time,
ballarin@14445
  1190
                      remove <= edge *)
wenzelm@32215
  1191
                 fun reOrganizeEdges [] sorted = sorted: (int * less) list
wenzelm@32215
  1192
                 |   reOrganizeEdges (e::es) sorted = reOrganizeEdges es (insert e sorted);
wenzelm@32215
  1193
ballarin@14445
  1194
                 (* construct the subgraph forming the strongly connected component
wenzelm@32215
  1195
                    from the edge list *)
wenzelm@32215
  1196
                 fun sccSubGraph [] g  = g
wenzelm@32215
  1197
                 |   sccSubGraph (l::ls) g =
wenzelm@32215
  1198
                          sccSubGraph ls (addEdge ((lower l),[((upper l),l)],g))
wenzelm@32215
  1199
wenzelm@32215
  1200
                 val (intern, extern) = sortEdges leqEdges ([], []);
ballarin@14445
  1201
                 val subGraph = sccSubGraph intern [];
wenzelm@32215
  1202
wenzelm@32215
  1203
     in
skalberg@15531
  1204
         case findContr neqEdges of SOME e => handleContr e subGraph
wenzelm@32215
  1205
         | _ => ((k, (reOrganizeEdges (extern) [])), subGraph)
wenzelm@32215
  1206
     end;
wenzelm@32215
  1207
wenzelm@32215
  1208
    val tmp =  map processComponent IndexComp
wenzelm@32215
  1209
in
wenzelm@32215
  1210
     ( (map fst tmp), (map snd tmp))
wenzelm@32215
  1211
end;
ballarin@14398
  1212
ballarin@14398
  1213
ballarin@24639
  1214
(** Find proof if possible. **)
ballarin@14398
  1215
ballarin@24639
  1216
fun gen_solve mkconcl sign (asms, concl) =
wenzelm@32215
  1217
 let
ballarin@14445
  1218
  val (leqG, neqG, neqE) = mkGraphs asms
wenzelm@32215
  1219
  val components = scc_term leqG
haftmann@33063
  1220
  val ntc = indexNodes (map_index I components)
ballarin@14445
  1221
  val (sccGraph, sccSubgraphs) = mk_sccGraphs components leqG neqG ntc
ballarin@14398
  1222
 in
wenzelm@32215
  1223
   let
ballarin@24639
  1224
   val (subgoals, prf) = mkconcl decomp less_thms sign concl
ballarin@14398
  1225
   fun solve facts less =
skalberg@15531
  1226
      (case triv_solv less of NONE => findProof (sccGraph, neqE, ntc, sccSubgraphs) less
skalberg@15531
  1227
      | SOME prf => prf )
ballarin@14398
  1228
  in
ballarin@14398
  1229
   map (solve asms) subgoals
ballarin@14398
  1230
  end
ballarin@14398
  1231
 end;
ballarin@24639
  1232
ballarin@24639
  1233
in
wenzelm@32215
  1234
 SUBGOAL (fn (A, n) => fn st =>
wenzelm@32215
  1235
  let
wenzelm@42361
  1236
   val thy = Proof_Context.theory_of ctxt;
wenzelm@32215
  1237
   val rfrees = map Free (Term.rename_wrt_term A (Logic.strip_params A));
wenzelm@59582
  1238
   val Hs =
wenzelm@59582
  1239
    map Thm.prop_of prems @
wenzelm@59582
  1240
    map (fn H => subst_bounds (rfrees, H)) (Logic.strip_assums_hyp A)
wenzelm@32215
  1241
   val C = subst_bounds (rfrees, Logic.strip_assums_concl A)
haftmann@33206
  1242
   val lesss = flat (map_index (mkasm decomp less_thms thy) Hs)
wenzelm@32215
  1243
   val prfs = gen_solve mkconcl thy (lesss, C);
wenzelm@32215
  1244
   val (subgoals, prf) = mkconcl decomp less_thms thy C;
wenzelm@32215
  1245
  in
wenzelm@59498
  1246
   Subgoal.FOCUS (fn {context = ctxt', prems = asms, ...} =>
wenzelm@32215
  1247
     let val thms = map (prove (prems @ asms)) prfs
wenzelm@59498
  1248
     in resolve_tac ctxt' [prove thms prf] 1 end) ctxt n st
wenzelm@32215
  1249
  end
wenzelm@32215
  1250
  handle Contr p =>
wenzelm@59498
  1251
      (Subgoal.FOCUS (fn {context = ctxt', prems = asms, ...} =>
wenzelm@59498
  1252
          resolve_tac ctxt' [prove asms p] 1) ctxt n st
wenzelm@43278
  1253
        handle General.Subscript => Seq.empty)
wenzelm@32215
  1254
   | Cannot => Seq.empty
wenzelm@43278
  1255
   | General.Subscript => Seq.empty)
ballarin@24639
  1256
end;
ballarin@24639
  1257
ballarin@14445
  1258
(* partial_tac - solves partial orders *)
ballarin@24639
  1259
val partial_tac = gen_order_tac mkasm_partial mkconcl_partial;
ballarin@24639
  1260
ballarin@14398
  1261
(* linear_tac - solves linear/total orders *)
ballarin@24639
  1262
val linear_tac = gen_order_tac mkasm_linear mkconcl_linear;
ballarin@24639
  1263
ballarin@14398
  1264
end;