-
Notifications
You must be signed in to change notification settings - Fork 18
/
SequentConnector.scala
251 lines (227 loc) · 10.1 KB
/
SequentConnector.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
package gapt.proofs
import gapt.proofs.lk.LKProof
import scala.collection.mutable
/**
* This class models the connection of formula occurrences between two sequents in a proof.
*
* The most basic use case is that of connecting the conclusion of an LK inference with one of the premises.
* This is the origin of the names "lowerSizes" and "upperSizes".
*
* @param lowerSizes The dimensions of the first ("lower") of the two connected sequents.
* @param upperSizes The dimensions of the second ("upper") of the two connected sequents.
* @param parentsSequent A sequent of lists of indices such that for each index i of lowerSequent, parentsSequent(i)
* is the list of indices of the parents of i in upperSequent.
*/
case class SequentConnector( lowerSizes: ( Int, Int ), upperSizes: ( Int, Int ),
parentsSequent: Sequent[Seq[SequentIndex]] ) {
require(
parentsSequent.sizes == lowerSizes,
s"Sizes ${parentsSequent.sizes} of parents sequent $parentsSequent don't agree with lower sizes $lowerSizes." )
require( parentsSequent.elements.flatten.forall { _ withinSizes upperSizes } )
val ( antL, sucL ) = lowerSizes
val ( antU, sucU ) = upperSizes
/**
* Analogous to parentsSequent, but in the other direction.
*
* @return A sequent of lists of indices such that for each index i of upperSequent, childrenSequent(i)
* is the list of indices of the children of i in lowerSequent.
*/
def childrenSequent: Sequent[Seq[SequentIndex]] = Sequent( antU, sucU ) map children
/**
* Given a SequentIndex for the lower sequent, this returns the list of parents of that occurrence in
* the upper sequent (if defined).
*
* @param idx An index of lowerSequent.
* @return The list of parents of idx.
*/
def parents( idx: SequentIndex ): Seq[SequentIndex] = parentsSequent( idx )
/**
* Given a SequentIndex for the lower sequent, this returns the parent of that occurrence in the upper sequent
* (if there is exactly one).
*
* @param idx An index of lowerSequent.
* @return The unique parent of idx.
*/
def parent( idx: SequentIndex ): SequentIndex = parents( idx ) match {
case Seq() => throw new NoSuchElementException(
s"When calling parent on SequentConnector $this: Index $idx has no parent in $parentsSequent." )
case Seq( p ) => p
case _ => throw new Exception(
s"When calling parent on SequentConnector $this: Index $idx has more than one parent in $parentsSequent." )
}
/**
* Given a SequentIndex for the lower sequent, this returns the parent of that occurrence in the upper sequent
* (if there is exactly one), and None otherwise.
*
* @param idx An index of lowerSequent.
* @return The unique parent of idx.
*/
def parentOption( idx: SequentIndex ): Option[SequentIndex] = parents( idx ) match {
case Seq() => None
case Seq( p ) => Some( p )
case _ => None
}
/**
* Given a sequent lowerTs of the same size as the lower sequent, return a sequent of the same size as the upper
* sequent that contains the parents of the Ts in lowerTs.
*
* If we call the returned sequent upperTs, then lowerTs(i) in upperTs(j) for all j in parents(i).
*
* The intended use-case is that lowerTs is a sequent of labels for the formulas in the lower sequent.
* parents(lowerTs) will then contain the correct labels for the formulas in the upper sequent.
*/
def parents[T]( lowerTs: Sequent[T] ): Sequent[Seq[T]] = {
require( lowerTs.sizes == lowerSizes )
childrenSequent map { _ map { lowerTs( _ ) } }
}
/**
* Given a sequent lowerTs of the same size as the lower sequent, return a sequent of the same size as the upper
* sequent that contains the unique parent of the Ts in lowerTs, or default otherwise.
*/
def parent[T]( lowerTs: Sequent[T], default: => T = ??? ): Sequent[T] =
parents( lowerTs ) map {
case Seq( t ) => t
case _ => default
}
def child[T]( upperTs: Sequent[T], default: => T = ??? ): Sequent[T] =
inv.parent( upperTs, default )
/**
* Given a SequentIndex for the upper sequent, this returns the list of children of that occurrence in
* the lower sequent (if defined).
*
* @param idx An index of upperSequent.
* @return The list of children of idx.
*/
def children( idx: SequentIndex ): Seq[SequentIndex] =
if ( idx withinSizes upperSizes )
parentsSequent indicesWhere { _ contains idx }
else
throw new IndexOutOfBoundsException
def children[T]( upperTs: Sequent[T] ): Sequent[Seq[T]] =
inv.parents( upperTs )
/**
* Given a SequentIndex for the upper sequent, this returns the child of that occurrence in the lower sequent
* (if there is exactly one).
*
* @param idx An index of upperSequent.
* @return The unique child of idx.
*/
def child( idx: SequentIndex ): SequentIndex = children( idx ) match {
case Seq() => throw new NoSuchElementException(
s"When calling child on SequentConnector $this: Index $idx has no child in $parentsSequent." )
case Seq( c ) => c
case _ => throw new Exception(
s"When calling child on SequentConnector $this: Index $idx has more than one child in $parentsSequent." )
}
/**
* Concatenates two SequentConnectors.
*
* @param that An SequentConnector. upperSizes of this must be the same as lowerSizes of that.
* @return An SequentConnector that connects the lower sequent of this with the upper sequent of that.
*/
def *( that: SequentConnector ) = {
require( this.upperSizes == that.lowerSizes )
SequentConnector( this.lowerSizes, that.upperSizes, this.parentsSequent map { _ flatMap that.parents distinct } )
}
/**
* Inverts an SequentConnector.
*
* @return This SequentConnector with its lower and upper sizes (and parents and children methods) switched around.
*/
def inv: SequentConnector = SequentConnector( upperSizes, lowerSizes, childrenSequent )
/**
* Forms the union of two SequentConnectors.
*
* @param that An SequentConnector. Must have the same upper and lower sizes as this.
* @return A new SequentConnector o such that for any i, o.parents(i) = this.parents(i) ∪ that.parents(i).
*/
def +( that: SequentConnector ) = {
require( this.lowerSizes == that.lowerSizes )
require( this.upperSizes == that.upperSizes )
SequentConnector( lowerSizes, upperSizes, Sequent( antL, sucL ).map( i =>
this.parents( i ) ++ that.parents( i ) distinct ) )
}
/**
* Adds a child/parent pair to an SequentConnector.
*
* @param child An index of lowerSequent.
* @param parent An index of upperSequent.
* @return A new SequentConnector in which parents(child) contains parent.
*/
def +( child: SequentIndex, parent: SequentIndex ) = {
require( child withinSizes lowerSizes )
require( parent withinSizes upperSizes )
SequentConnector( lowerSizes, upperSizes,
parentsSequent.updated( child, parents( child ) :+ parent distinct ) )
}
/**
* Removes a child/parent pair from an SequentConnector.
* @param child An index of lowerSequent.
* @param parent An index of upperSequent. Must be a parent of child.
* @return A new SequentConnector in which parents(child) no longer contains parent.
*/
def -( child: SequentIndex, parent: SequentIndex ) = {
require( child withinSizes lowerSizes )
require( parent withinSizes upperSizes )
SequentConnector( lowerSizes, upperSizes,
parentsSequent.updated( child, parents( child ) diff Seq( parent ) ) )
}
}
object SequentConnector {
/**
* Constructs the trivial SequentConnector of a sequent.
*
* @param sequent A sequent.
* @return An SequentConnector that connects every index of sequent to itself.
*/
def apply( sequent: Sequent[_] ): SequentConnector = SequentConnector( sequent, sequent,
sequent.indicesSequent map { Seq( _ ) } )
/**
* Connects two given sequents via a given parentsSequent.
*/
def apply( lowerSequent: Sequent[_], upperSequent: Sequent[_],
parentsSequent: Sequent[Seq[SequentIndex]] ): SequentConnector =
SequentConnector( lowerSequent.sizes, upperSequent.sizes, parentsSequent )
/**
* Creates an SequentConnector that connects all occurrences of an object in the antecedents of
* two sequents, and analogously
* for the succedents.
*/
def findEquals[A]( firstSequent: Sequent[A], secondSequent: Sequent[A] ): SequentConnector = {
val parentsSequent = firstSequent.map(
x => secondSequent.indicesWhere( _ == x ) filter { _.isAnt },
x => secondSequent.indicesWhere( _ == x ) filter { _.isSuc } )
SequentConnector( firstSequent, secondSequent, parentsSequent )
}
/**
* Guesses a SequentConnector, such that each element in lower gets connected to a different element in upper.
*/
def guessInjection[A]( fromLower: Sequent[A], toUpper: Sequent[A] ): SequentConnector = {
val alreadyUsedOldIndices = mutable.Set[SequentIndex]()
SequentConnector( fromLower, toUpper, fromLower.zipWithIndex.map {
case ( atom, newIdx ) =>
val oldIdx = toUpper.indicesWhere( _ == atom ).
filterNot( alreadyUsedOldIndices.contains ).
find( newIdx.sameSideAs ).
getOrElse( throw new IllegalArgumentException(
s"Cannot find $atom in ${
toUpper.zipWithIndex
.filterNot( alreadyUsedOldIndices contains _._2 ).map( _._1 )
}" ) )
alreadyUsedOldIndices += oldIdx
Seq( oldIdx )
} )
}
}
object guessPermutation {
/**
* Guesses a permutation of formulas in the conclusions of two proofs.
* @param oldProof The original proof.
* @param newProof A transformed proof which proves the same end-sequent as `oldProof`.
* @return A pair consisting of `newProof` and a sequent connector which describes the new
* positions of the formulas in `oldProof.conclusion` with respect to `newProof`.
*/
// FIXME: this is just broken
def apply( oldProof: LKProof, newProof: LKProof ): ( LKProof, SequentConnector ) =
( newProof, SequentConnector.guessInjection( toUpper = newProof.conclusion, fromLower = oldProof.conclusion ).inv )
}