@@ -111,6 +111,59 @@ bool FormulaUtil::isRecursive(const Formula& formula,
111111 return false ;
112112}
113113
114+ // Helper function to check if a function depends on another
115+ static bool dependsOn (const std::multimap<std::string, std::string>& deps,
116+ const std::string& from, const std::string& to) {
117+ auto range = deps.equal_range (from);
118+ for (auto it = range.first ; it != range.second ; ++it) {
119+ if (it->second == to) {
120+ return true ;
121+ }
122+ }
123+ return false ;
124+ }
125+
126+ bool FormulaUtil::hasMutualRecursion (const Formula& formula,
127+ Expression::Type type) {
128+ // Get transitive dependencies between functions
129+ auto deps = getDependencies (formula, type, true , false );
130+
131+ // Build a set of all function names
132+ std::set<std::string> funcNames;
133+ for (const auto & e : formula.entries ) {
134+ if (e.first .type == type && !e.first .name .empty ()) {
135+ funcNames.insert (e.first .name );
136+ }
137+ }
138+
139+ // Check for mutual recursion: A depends on B and B depends on A (where A !=
140+ // B), and neither A nor B is self-recursive.
141+ // If at least one function in the cycle is self-recursive, the LEAN code
142+ // generator will use Nat domain with pattern offsets, which can prove
143+ // termination.
144+ for (auto itA = funcNames.begin (); itA != funcNames.end (); ++itA) {
145+ for (auto itB = std::next (itA); itB != funcNames.end (); ++itB) {
146+ const auto & funcA = *itA;
147+ const auto & funcB = *itB;
148+
149+ // Check for mutual dependency (A->B and B->A)
150+ if (dependsOn (deps, funcA, funcB) && dependsOn (deps, funcB, funcA)) {
151+ // Check if either A or B is self-recursive
152+ // Use non-transitive check for self-recursion
153+ bool aIsSelfRecursive = isRecursive (formula, funcA, type);
154+ bool bIsSelfRecursive = isRecursive (formula, funcB, type);
155+
156+ // If neither is self-recursive, LEAN can't prove termination
157+ // because the domain will be Int instead of Nat
158+ if (!aIsSelfRecursive && !bIsSelfRecursive) {
159+ return true ;
160+ }
161+ }
162+ }
163+ }
164+ return false ;
165+ }
166+
114167Number FormulaUtil::getMinimumBaseCase (const Formula& formula,
115168 const std::string& funcName) {
116169 Number minBaseCase = Number::INF;
0 commit comments