@@ -9,9 +9,8 @@ import lisa.fol.FOLHelpers.*
9
9
10
10
object ProofsConverter {
11
11
12
- // TODO: remove unnecessary variables "val s_..." in generated proofs -> need to keep track of which steps are used in other steps
12
+ // TODO: remove unnecessary variables "val s_..." in generated proofs -> need to detect which steps are used later in other steps
13
13
// TODO: generate more realistic variable names
14
- // TODO: handle automatic global variable declaration before theorems/proofs
15
14
16
15
private def indent (s : String , indent : Int = 2 ): String = s.split(" \n " ).map(" " * indent + _).mkString(" \n " )
17
16
private def unindent (s : String , indent : Int = 2 ): String = s.split(" \n " ).map(_.drop(indent)).mkString(" \n " )
@@ -22,13 +21,13 @@ object ProofsConverter {
22
21
case term : K .Term => asFront(term)
23
22
).toString.replace(" ⇒" , " ==>" ).replace(" ⇔" , " <=>" )
24
23
25
- def scproof2code (p : K .SCProof ): String = {
26
- def scproof2codeAux (p : K .SCProof , varPrefix : String = " s" , premises : Seq [String ] = Seq .empty): String = {
27
- def scproofstep2code (ps : SCProofStep , stepNum : Int , premises : Seq [String ], varPrefix : String ): String = {
24
+ private def scproof2code (p : K .SCProof ): String = {
25
+ def scproof2codeAux (p : K .SCProof , varPrefix : String = " s" , implicitPremises : Seq [String ] = Seq .empty): String = {
26
+ def scproofstep2code (ps : SCProofStep , stepNum : Int , implicitPremises : Seq [String ], varPrefix : String ): String = {
28
27
29
28
def index2stepvar (i : Int ): String =
30
- if i < - premises .size then throw new Exception (s " step $i is not defined " )
31
- else if i < 0 then premises (- i - 1 )
29
+ if i < - implicitPremises .size then throw new Exception (s " step $i is not defined " )
30
+ else if i < 0 then implicitPremises (- i - 1 )
32
31
else s " ${varPrefix}_ $i"
33
32
34
33
ps match
@@ -43,93 +42,122 @@ object ProofsConverter {
43
42
var tacticName = ps.getClass.getSimpleName
44
43
var opening = " ("
45
44
var closing = " )"
46
- val (bot_, step_ref_seq) = (ps match
47
- case Restate (bot, t1) =>
48
- opening = " .from("
49
- (bot, Seq (t1))
50
- case RestateTrue (bot) =>
51
- tacticName = " Restate"
52
- (bot, null )
53
- case Hypothesis (bot, phi) => (bot, null )
54
- case Cut (bot, t1, t2, phi) => (bot, Seq (t1, t2))
55
- case LeftAnd (bot, t1, phi, psi) => (bot, Seq (t1))
56
- case LeftOr (bot, t, disjuncts) => (bot, t)
57
- case LeftImplies (bot, t1, t2, phi, psi) => (bot, Seq (t1, t2))
58
- case LeftIff (bot, t1, phi, psi) => (bot, Seq (t1))
59
- case LeftNot (bot, t1, phi) => (bot, Seq (t1))
60
- case LeftForall (bot, t1, phi, x, t) => (bot, Seq (t1))
61
- case LeftExists (bot, t1, phi, x) => (bot, Seq (t1))
62
- case LeftExistsOne (bot, t1, phi, x) => (bot, Seq (t1))
63
- case RightAnd (bot, t, conjuncts) => (bot, t)
64
- case RightOr (bot, t1, phi, psi) => (bot, Seq (t1))
65
- case RightImplies (bot, t1, phi, psi) => (bot, Seq (t1))
66
- case RightIff (bot, t1, t2, phi, psi) => (bot, Seq (t1, t2))
67
- case RightNot (bot, t1, phi) => (bot, Seq (t1))
68
- case RightForall (bot, t1, phi, x) => (bot, Seq (t1))
69
- case RightExists (bot, t1, phi, x, t) => (bot, Seq (t1))
70
- case RightExistsOne (bot, t1, phi, x) => (bot, Seq (t1))
71
- case Weakening (bot, t1) => (bot, Seq (t1))
72
- case LeftRefl (bot, t1, phi) => (bot, Seq (t1))
73
- case RightRefl (bot, phi) => (bot, null )
74
- case LeftSubstEq (bot, t1, equals, lambdaPhi) =>
45
+ ps match
46
+ case Restate (_, _) => opening = " .from("
47
+ case RestateTrue (_) => tacticName = " Restate"
48
+ case LeftSubstEq (_, _, equals, lambdaPhi) =>
75
49
tacticName = s " LeftSubstEq.withParametersSimple(List( ${equals
76
50
.map((a, b) => s " (( ${any2code(a.body)}), ( ${any2code(b.body)})) " )
77
51
.mkString(" , " )}), lambda(Seq( ${lambdaPhi._1.map(asFrontLabel).mkString(" , " )}), ${any2code(lambdaPhi._2)})) "
78
- (bot, Seq (t1))
79
- case RightSubstEq (bot, t1, equals, lambdaPhi) =>
52
+ case RightSubstEq (_, _, equals, lambdaPhi) =>
80
53
tacticName = s " RightSubstEq.withParametersSimple(List( ${equals
81
54
.map((a, b) => s " (( ${any2code(a.body)}), ( ${any2code(b.body)})) " )
82
55
.mkString(" , " )}), lambda(Seq( ${lambdaPhi._1.map(asFrontLabel).mkString(" , " )}), ${any2code(lambdaPhi._2)})) "
83
- (bot, Seq (t1))
84
- case LeftSubstIff (bot, t1, equals, lambdaPhi) =>
56
+ case LeftSubstIff (_, _, equals, lambdaPhi) =>
85
57
tacticName = s " LeftSubstIff.withParametersSimple(List( ${equals
86
58
.map((a, b) => s " (( ${any2code(a.body)}), ( ${any2code(b.body)})) " )
87
59
.mkString(" , " )}), lambda(Seq( ${lambdaPhi._1.map(asFrontLabel).mkString(" , " )}), ${any2code(lambdaPhi._2)})) "
88
- (bot, Seq (t1))
89
- case RightSubstIff (bot, t1, equals, lambdaPhi) =>
60
+ case RightSubstIff (_, _, equals, lambdaPhi) =>
90
61
tacticName = s " RightSubstIff.withParametersSimple(List( ${equals
91
62
.map((a, b) => s " (( ${any2code(a.body)}), ( ${any2code(b.body)})) " )
92
63
.mkString(" , " )}), lambda(Seq( ${lambdaPhi._1.map(asFrontLabel).mkString(" , " )}), ${any2code(lambdaPhi._2)})) "
93
- (bot, Seq (t1))
94
- case InstSchema (bot, t1, mCon, mPred, mTerm) =>
64
+ case InstSchema (_, _, mCon, mPred, mTerm) =>
95
65
if mCon.isEmpty && mPred.isEmpty then
96
66
tacticName = s " InstFunSchema(Map( ${mTerm.toList
97
67
.map((k, v) => s " ${asFrontLabel(k)} -> ${any2code(v.body)}" )
98
68
.mkString(" , " )})) "
99
- (bot, Seq (t1))
100
69
else if mCon.isEmpty && mTerm.isEmpty then
101
70
tacticName = s " InstPredSchema(Map( ${mPred.toList
102
71
.map((k, v) => s " ${asFrontLabel(k)} -> ${any2code(v.body)}" )
103
72
.mkString(" , " )})) "
104
- (bot, Seq (t1))
105
73
else throw new Exception (" InstSchema not implemented" )
106
- case _ => throw new Exception (s " Tactic ${ps.getClass.getName} not implemented " )
107
- )
74
+ case _ => ()
108
75
109
76
indent(
110
77
s " val ${varPrefix}_ $stepNum = " + (
111
- if (step_ref_seq != null && step_ref_seq. size == 1 && stepNum > 0 && step_ref_seq. head + 1 == stepNum)
112
- then s " thenHave( ${any2code(bot_ )}) by $tacticName"
78
+ if (ps.premises. size == 1 && ps.premises. head + 1 == stepNum && stepNum > 0 )
79
+ then s " thenHave( ${any2code(ps.bot )}) by $tacticName"
113
80
else
114
- s " have( ${any2code(bot_ )}) by $tacticName" + (
115
- if step_ref_seq == null then " "
116
- else s " $opening${step_ref_seq .map(index2stepvar).mkString(" , " )}$closing"
81
+ s " have( ${any2code(ps.bot )}) by $tacticName" + (
82
+ if ps.premises.size == 0 then " "
83
+ else s " $opening${ps.premises .map(index2stepvar).mkString(" , " )}$closing"
117
84
)
118
85
)
119
86
)
120
87
}
121
88
122
- p.steps.zipWithIndex.map((ps, i) => scproofstep2code(ps, i, premises , varPrefix)).mkString(" \n " )
89
+ p.steps.zipWithIndex.map((ps, i) => scproofstep2code(ps, i, implicitPremises , varPrefix)).mkString(" \n " )
123
90
}
124
91
unindent(scproof2codeAux(p))
125
92
}
126
93
127
- def generateTheoremCode (name : String , statement : K .Sequent , proof : K .SCProof ): String = {
94
+ private def extractFormulasFromProof (proof : K .SCProof ): Set [K .Formula ] =
95
+ proof.steps.foldLeft(Set .empty[K .Formula ])((prev, next) => {
96
+ prev ++ (next match
97
+ case sp @ SCSubproof (subproof, _) => extractFormulasFromProof(subproof)
98
+ case LeftSubstEq (_, _, _, lambdaPhi) => Seq (lambdaPhi._2, K .sequentToFormula(next.bot))
99
+ case RightSubstEq (_, _, _, lambdaPhi) => Seq (lambdaPhi._2, K .sequentToFormula(next.bot))
100
+ case LeftSubstIff (_, _, _, lambdaPhi) => Seq (lambdaPhi._2, K .sequentToFormula(next.bot))
101
+ case RightSubstIff (_, _, _, lambdaPhi) => Seq (lambdaPhi._2, K .sequentToFormula(next.bot))
102
+ case _ => Seq (K .sequentToFormula(next.bot))
103
+ )
104
+ })
105
+
106
+ private def extractVariables (
107
+ formulas : Set [K .Formula ]
108
+ ): (Set [K .VariableLabel ], Set [K .SchematicFunctionLabel ], Set [K .VariableFormulaLabel ], Set [K .SchematicPredicateLabel ], Set [K .SchematicConnectorLabel ]) =
109
+ def extractVariablesAux (
110
+ formula : K .Formula
111
+ ): (Set [K .VariableLabel ], Set [K .SchematicFunctionLabel ], Set [K .VariableFormulaLabel ], Set [K .SchematicPredicateLabel ], Set [K .SchematicConnectorLabel ]) =
112
+ var variableSet = formula.schematicTermLabels.collect { case v : K .VariableLabel => v }
113
+ var functionSet = formula.schematicTermLabels.collect { case f : K .SchematicFunctionLabel => f }
114
+ var formulaVariableSet = formula.schematicAtomicLabels.collect { case v : K .VariableFormulaLabel => v }
115
+ var predicateSet = formula.schematicAtomicLabels.collect { case p : K .SchematicPredicateLabel => p }
116
+ var connectorSet = formula.schematicConnectorLabels.collect { case c : K .SchematicConnectorLabel => c }
117
+ (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet)
118
+
119
+ formulas.foldLeft(
120
+ (Set .empty[K .VariableLabel ], Set .empty[K .SchematicFunctionLabel ], Set .empty[K .VariableFormulaLabel ], Set .empty[K .SchematicPredicateLabel ], Set .empty[K .SchematicConnectorLabel ])
121
+ )((prev, next) => {
122
+ val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = prev
123
+ val (variableSet_, functionSet_, formulaVariableSet_, predicateSet_, connectorSet_) = extractVariablesAux(next)
124
+ (
125
+ variableSet ++ variableSet_,
126
+ functionSet ++ functionSet_,
127
+ formulaVariableSet ++ formulaVariableSet_,
128
+ predicateSet ++ predicateSet_,
129
+ connectorSet ++ connectorSet_
130
+ )
131
+ })
132
+
133
+ private def generateVariablesCode (formulas : Set [K .Formula ], accessibility : String ): String =
134
+ val (variableSet, functionSet, formulaVariableSet, predicateSet, connectorSet) = extractVariables(formulas)
135
+ val access = if accessibility != " " then accessibility.strip() + " " else " "
136
+ (variableSet.map(v => access + s " val ${v.id} = variable " ).toList.sorted ++
137
+ functionSet.map(f => access + s " val ${f.id} = function[ ${f.arity}] " ).toList.sorted ++
138
+ formulaVariableSet.map(v => access + s " val ${v.id} = formulaVariable " ).toList.sorted ++
139
+ predicateSet.map(p => access + s " val ${p.id} = predicate[ ${p.arity}] " ).toList.sorted ++
140
+ connectorSet.map(c => access + s " val ${c.id} = connector[ ${c.arity}] " ).toList.sorted).mkString(" \n " )
141
+
142
+ private def generateVariablesCode (statement : K .Sequent , proof : K .SCProof , accessibility : String = " private" ): String =
143
+ generateVariablesCode(extractFormulasFromProof(proof) + K .sequentToFormula(statement), accessibility)
144
+
145
+ private def generateTheoremCode (name : String , statement : K .Sequent , proof : K .SCProof ): String = {
128
146
s " val $name = Theorem( \n " +
129
147
indent(any2code(statement)) +
130
148
s " \n ) { \n " +
131
149
indent(scproof2code(proof)) +
132
150
s " \n } "
133
151
}
134
152
153
+ def generateStandaloneTheoremFileContent (name : String , statement : K .Sequent , proof : K .SCProof ): String =
154
+ val camelName = " [A-Za-z0-9]+" .r.findAllIn(name).map(_.capitalize).mkString
155
+ s " object $camelName extends lisa.Main { \n\n " +
156
+ indent(
157
+ generateVariablesCode(statement, proof) +
158
+ " \n\n " +
159
+ generateTheoremCode(name, statement, proof)
160
+ ) +
161
+ " \n }"
162
+
135
163
}
0 commit comments