Skip to main content

tensorlogic_ir/expr/
advanced_analysis.rs

1//! Advanced expression analysis for operator counting and complexity metrics.
2//!
3//! This module provides detailed analysis capabilities for TensorLogic expressions,
4//! including operator type classification, complexity metrics, and pattern detection.
5
6use std::collections::HashMap;
7
8use super::TLExpr;
9
10/// Detailed operator counts categorized by type.
11#[derive(Clone, Debug, Default, PartialEq, Eq)]
12pub struct OperatorCounts {
13    /// Total number of operators
14    pub total: usize,
15    /// Basic logical operators (And, Or, Not, Imply)
16    pub logical: usize,
17    /// Arithmetic operators (Add, Sub, Mul, Div, Pow, Mod, Min, Max)
18    pub arithmetic: usize,
19    /// Comparison operators (Eq, Lt, Gt, Lte, Gte)
20    pub comparison: usize,
21    /// Unary mathematical functions (Abs, Floor, Ceil, Round, Sqrt, Exp, Log, Sin, Cos, Tan)
22    pub mathematical: usize,
23    /// Quantifiers (Exists, ForAll, SoftExists, SoftForAll)
24    pub quantifiers: usize,
25    /// Modal logic operators (Box, Diamond)
26    pub modal: usize,
27    /// Temporal logic operators (Next, Eventually, Always, Until, Release, WeakUntil, StrongRelease)
28    pub temporal: usize,
29    /// Fuzzy logic operators (TNorm, TCoNorm, FuzzyNot, FuzzyImplication)
30    pub fuzzy: usize,
31    /// Probabilistic operators (WeightedRule, ProbabilisticChoice)
32    pub probabilistic: usize,
33    /// Aggregation operators
34    pub aggregation: usize,
35    /// Control flow (IfThenElse, Let)
36    pub control_flow: usize,
37    /// Predicates
38    pub predicates: usize,
39    /// Constants
40    pub constants: usize,
41}
42
43impl OperatorCounts {
44    /// Create a new empty operator count.
45    pub fn new() -> Self {
46        Self::default()
47    }
48
49    /// Compute operator counts from an expression.
50    pub fn from_expr(expr: &TLExpr) -> Self {
51        let mut counts = Self::new();
52        counts.count_recursive(expr);
53        counts
54    }
55
56    /// Recursively count operators in an expression.
57    fn count_recursive(&mut self, expr: &TLExpr) {
58        self.total += 1;
59
60        match expr {
61            // Predicates
62            TLExpr::Pred { .. } => {
63                self.predicates += 1;
64            }
65
66            // Constants
67            TLExpr::Constant(_) => {
68                self.constants += 1;
69            }
70
71            // Basic logical operators
72            TLExpr::And(l, r) | TLExpr::Or(l, r) | TLExpr::Imply(l, r) => {
73                self.logical += 1;
74                self.count_recursive(l);
75                self.count_recursive(r);
76            }
77            TLExpr::Not(e) | TLExpr::Score(e) => {
78                self.logical += 1;
79                self.count_recursive(e);
80            }
81
82            // Arithmetic operators
83            TLExpr::Add(l, r)
84            | TLExpr::Sub(l, r)
85            | TLExpr::Mul(l, r)
86            | TLExpr::Div(l, r)
87            | TLExpr::Pow(l, r)
88            | TLExpr::Mod(l, r)
89            | TLExpr::Min(l, r)
90            | TLExpr::Max(l, r) => {
91                self.arithmetic += 1;
92                self.count_recursive(l);
93                self.count_recursive(r);
94            }
95
96            // Comparison operators
97            TLExpr::Eq(l, r)
98            | TLExpr::Lt(l, r)
99            | TLExpr::Gt(l, r)
100            | TLExpr::Lte(l, r)
101            | TLExpr::Gte(l, r) => {
102                self.comparison += 1;
103                self.count_recursive(l);
104                self.count_recursive(r);
105            }
106
107            // Mathematical functions
108            TLExpr::Abs(e)
109            | TLExpr::Floor(e)
110            | TLExpr::Ceil(e)
111            | TLExpr::Round(e)
112            | TLExpr::Sqrt(e)
113            | TLExpr::Exp(e)
114            | TLExpr::Log(e)
115            | TLExpr::Sin(e)
116            | TLExpr::Cos(e)
117            | TLExpr::Tan(e) => {
118                self.mathematical += 1;
119                self.count_recursive(e);
120            }
121
122            // Quantifiers
123            TLExpr::Exists { body, .. } | TLExpr::ForAll { body, .. } => {
124                self.quantifiers += 1;
125                self.count_recursive(body);
126            }
127            TLExpr::SoftExists { body, .. } | TLExpr::SoftForAll { body, .. } => {
128                self.quantifiers += 1;
129                self.probabilistic += 1; // Also counts as probabilistic
130                self.count_recursive(body);
131            }
132
133            // Modal logic
134            TLExpr::Box(e) | TLExpr::Diamond(e) => {
135                self.modal += 1;
136                self.count_recursive(e);
137            }
138
139            // Temporal logic
140            TLExpr::Next(e) | TLExpr::Eventually(e) | TLExpr::Always(e) => {
141                self.temporal += 1;
142                self.count_recursive(e);
143            }
144            TLExpr::Until { before, after }
145            | TLExpr::Release {
146                released: before,
147                releaser: after,
148            }
149            | TLExpr::WeakUntil { before, after }
150            | TLExpr::StrongRelease {
151                released: before,
152                releaser: after,
153            } => {
154                self.temporal += 1;
155                self.count_recursive(before);
156                self.count_recursive(after);
157            }
158
159            // Fuzzy logic
160            TLExpr::TNorm { left, right, .. } | TLExpr::TCoNorm { left, right, .. } => {
161                self.fuzzy += 1;
162                self.count_recursive(left);
163                self.count_recursive(right);
164            }
165            TLExpr::FuzzyNot { expr, .. } => {
166                self.fuzzy += 1;
167                self.count_recursive(expr);
168            }
169            TLExpr::FuzzyImplication {
170                premise,
171                conclusion,
172                ..
173            } => {
174                self.fuzzy += 1;
175                self.count_recursive(premise);
176                self.count_recursive(conclusion);
177            }
178
179            // Probabilistic operators
180            TLExpr::WeightedRule { rule, .. } => {
181                self.probabilistic += 1;
182                self.count_recursive(rule);
183            }
184            TLExpr::ProbabilisticChoice { alternatives } => {
185                self.probabilistic += 1;
186                for (_, e) in alternatives {
187                    self.count_recursive(e);
188                }
189            }
190
191            // Aggregation
192            TLExpr::Aggregate { body, .. } => {
193                self.aggregation += 1;
194                self.count_recursive(body);
195            }
196
197            // Control flow
198            TLExpr::IfThenElse {
199                condition,
200                then_branch,
201                else_branch,
202            } => {
203                self.control_flow += 1;
204                self.count_recursive(condition);
205                self.count_recursive(then_branch);
206                self.count_recursive(else_branch);
207            }
208            TLExpr::Let { value, body, .. } => {
209                self.control_flow += 1;
210                self.count_recursive(value);
211                self.count_recursive(body);
212            }
213
214            // Beta.1 enhancements
215            TLExpr::Lambda { body, .. } => {
216                self.control_flow += 1;
217                self.count_recursive(body);
218            }
219            TLExpr::Apply { function, argument } => {
220                self.control_flow += 1;
221                self.count_recursive(function);
222                self.count_recursive(argument);
223            }
224            TLExpr::SetMembership { element, set }
225            | TLExpr::SetUnion {
226                left: element,
227                right: set,
228            }
229            | TLExpr::SetIntersection {
230                left: element,
231                right: set,
232            }
233            | TLExpr::SetDifference {
234                left: element,
235                right: set,
236            } => {
237                self.logical += 1;
238                self.count_recursive(element);
239                self.count_recursive(set);
240            }
241            TLExpr::SetCardinality { set } => {
242                self.arithmetic += 1;
243                self.count_recursive(set);
244            }
245            TLExpr::EmptySet => {
246                self.constants += 1;
247            }
248            TLExpr::SetComprehension { condition, .. } => {
249                self.quantifiers += 1;
250                self.count_recursive(condition);
251            }
252            TLExpr::CountingExists { body, .. }
253            | TLExpr::CountingForAll { body, .. }
254            | TLExpr::ExactCount { body, .. }
255            | TLExpr::Majority { body, .. } => {
256                self.quantifiers += 1;
257                self.count_recursive(body);
258            }
259            TLExpr::LeastFixpoint { body, .. } | TLExpr::GreatestFixpoint { body, .. } => {
260                self.control_flow += 1;
261                self.count_recursive(body);
262            }
263            TLExpr::Nominal { .. } => {
264                self.constants += 1;
265            }
266            TLExpr::At { formula, .. } => {
267                self.modal += 1;
268                self.count_recursive(formula);
269            }
270            TLExpr::Somewhere { formula } | TLExpr::Everywhere { formula } => {
271                self.modal += 1;
272                self.count_recursive(formula);
273            }
274            TLExpr::AllDifferent { .. } => {
275                self.logical += 1;
276            }
277            TLExpr::GlobalCardinality { values, .. } => {
278                self.logical += 1;
279                for val in values {
280                    self.count_recursive(val);
281                }
282            }
283            TLExpr::Abducible { .. } => {
284                self.predicates += 1;
285            }
286            TLExpr::Explain { formula } => {
287                self.control_flow += 1;
288                self.count_recursive(formula);
289            }
290            TLExpr::SymbolLiteral(_) => {
291                self.predicates += 1;
292            }
293            TLExpr::Match { scrutinee, arms } => {
294                self.control_flow += 1;
295                self.count_recursive(scrutinee);
296                for (_, body) in arms {
297                    self.count_recursive(body);
298                }
299            }
300        }
301    }
302}
303
304/// Complexity metrics for an expression.
305#[derive(Clone, Debug, PartialEq)]
306pub struct ComplexityMetrics {
307    /// Maximum depth of the expression tree
308    pub max_depth: usize,
309    /// Average depth of leaf nodes
310    pub avg_depth: f64,
311    /// Total number of nodes
312    pub node_count: usize,
313    /// Number of leaf nodes (predicates and constants)
314    pub leaf_count: usize,
315    /// Branching factor (average number of children per non-leaf node)
316    pub branching_factor: f64,
317    /// Cyclomatic complexity (number of decision points + 1)
318    pub cyclomatic_complexity: usize,
319    /// Quantifier depth (maximum nesting level of quantifiers)
320    pub quantifier_depth: usize,
321    /// Modal depth (maximum nesting level of modal operators)
322    pub modal_depth: usize,
323    /// Temporal depth (maximum nesting level of temporal operators)
324    pub temporal_depth: usize,
325}
326
327impl ComplexityMetrics {
328    /// Compute complexity metrics from an expression.
329    pub fn from_expr(expr: &TLExpr) -> Self {
330        let mut metrics = Self {
331            max_depth: 0,
332            avg_depth: 0.0,
333            node_count: 0,
334            leaf_count: 0,
335            branching_factor: 0.0,
336            cyclomatic_complexity: 1, // Start with 1
337            quantifier_depth: 0,
338            modal_depth: 0,
339            temporal_depth: 0,
340        };
341
342        let mut depth_sum = 0;
343        let mut non_leaf_count = 0;
344        let mut child_count = 0;
345
346        metrics.compute_recursive(
347            expr,
348            0,
349            &mut depth_sum,
350            &mut non_leaf_count,
351            &mut child_count,
352            0,
353            0,
354            0,
355        );
356
357        // Compute averages
358        if metrics.leaf_count > 0 {
359            metrics.avg_depth = depth_sum as f64 / metrics.leaf_count as f64;
360        }
361        if non_leaf_count > 0 {
362            metrics.branching_factor = child_count as f64 / non_leaf_count as f64;
363        }
364
365        metrics
366    }
367
368    #[allow(clippy::too_many_arguments)]
369    fn compute_recursive(
370        &mut self,
371        expr: &TLExpr,
372        depth: usize,
373        depth_sum: &mut usize,
374        non_leaf_count: &mut usize,
375        child_count: &mut usize,
376        quantifier_depth: usize,
377        modal_depth: usize,
378        temporal_depth: usize,
379    ) {
380        self.node_count += 1;
381        self.max_depth = self.max_depth.max(depth);
382        self.quantifier_depth = self.quantifier_depth.max(quantifier_depth);
383        self.modal_depth = self.modal_depth.max(modal_depth);
384        self.temporal_depth = self.temporal_depth.max(temporal_depth);
385
386        match expr {
387            // Leaves
388            TLExpr::Pred { .. } | TLExpr::Constant(_) => {
389                self.leaf_count += 1;
390                *depth_sum += depth;
391            }
392
393            // Decision points (add to cyclomatic complexity)
394            TLExpr::IfThenElse {
395                condition,
396                then_branch,
397                else_branch,
398            } => {
399                self.cyclomatic_complexity += 1; // Decision point
400                *non_leaf_count += 1;
401                *child_count += 3;
402                self.compute_recursive(
403                    condition,
404                    depth + 1,
405                    depth_sum,
406                    non_leaf_count,
407                    child_count,
408                    quantifier_depth,
409                    modal_depth,
410                    temporal_depth,
411                );
412                self.compute_recursive(
413                    then_branch,
414                    depth + 1,
415                    depth_sum,
416                    non_leaf_count,
417                    child_count,
418                    quantifier_depth,
419                    modal_depth,
420                    temporal_depth,
421                );
422                self.compute_recursive(
423                    else_branch,
424                    depth + 1,
425                    depth_sum,
426                    non_leaf_count,
427                    child_count,
428                    quantifier_depth,
429                    modal_depth,
430                    temporal_depth,
431                );
432            }
433
434            // Logical operators (decision points)
435            TLExpr::And(l, r) | TLExpr::Or(l, r) => {
436                self.cyclomatic_complexity += 1; // Decision point
437                *non_leaf_count += 1;
438                *child_count += 2;
439                self.compute_recursive(
440                    l,
441                    depth + 1,
442                    depth_sum,
443                    non_leaf_count,
444                    child_count,
445                    quantifier_depth,
446                    modal_depth,
447                    temporal_depth,
448                );
449                self.compute_recursive(
450                    r,
451                    depth + 1,
452                    depth_sum,
453                    non_leaf_count,
454                    child_count,
455                    quantifier_depth,
456                    modal_depth,
457                    temporal_depth,
458                );
459            }
460
461            // Quantifiers (increase quantifier depth)
462            TLExpr::Exists { body, .. }
463            | TLExpr::ForAll { body, .. }
464            | TLExpr::SoftExists { body, .. }
465            | TLExpr::SoftForAll { body, .. } => {
466                *non_leaf_count += 1;
467                *child_count += 1;
468                self.compute_recursive(
469                    body,
470                    depth + 1,
471                    depth_sum,
472                    non_leaf_count,
473                    child_count,
474                    quantifier_depth + 1,
475                    modal_depth,
476                    temporal_depth,
477                );
478            }
479
480            // Modal operators (increase modal depth)
481            TLExpr::Box(e) | TLExpr::Diamond(e) => {
482                *non_leaf_count += 1;
483                *child_count += 1;
484                self.compute_recursive(
485                    e,
486                    depth + 1,
487                    depth_sum,
488                    non_leaf_count,
489                    child_count,
490                    quantifier_depth,
491                    modal_depth + 1,
492                    temporal_depth,
493                );
494            }
495
496            // Temporal operators (increase temporal depth)
497            TLExpr::Next(e) | TLExpr::Eventually(e) | TLExpr::Always(e) => {
498                *non_leaf_count += 1;
499                *child_count += 1;
500                self.compute_recursive(
501                    e,
502                    depth + 1,
503                    depth_sum,
504                    non_leaf_count,
505                    child_count,
506                    quantifier_depth,
507                    modal_depth,
508                    temporal_depth + 1,
509                );
510            }
511
512            // Binary temporal operators
513            TLExpr::Until { before, after }
514            | TLExpr::Release {
515                released: before,
516                releaser: after,
517            }
518            | TLExpr::WeakUntil { before, after }
519            | TLExpr::StrongRelease {
520                released: before,
521                releaser: after,
522            } => {
523                *non_leaf_count += 1;
524                *child_count += 2;
525                self.compute_recursive(
526                    before,
527                    depth + 1,
528                    depth_sum,
529                    non_leaf_count,
530                    child_count,
531                    quantifier_depth,
532                    modal_depth,
533                    temporal_depth + 1,
534                );
535                self.compute_recursive(
536                    after,
537                    depth + 1,
538                    depth_sum,
539                    non_leaf_count,
540                    child_count,
541                    quantifier_depth,
542                    modal_depth,
543                    temporal_depth + 1,
544                );
545            }
546
547            // Unary operators
548            TLExpr::Not(e)
549            | TLExpr::Score(e)
550            | TLExpr::Abs(e)
551            | TLExpr::Floor(e)
552            | TLExpr::Ceil(e)
553            | TLExpr::Round(e)
554            | TLExpr::Sqrt(e)
555            | TLExpr::Exp(e)
556            | TLExpr::Log(e)
557            | TLExpr::Sin(e)
558            | TLExpr::Cos(e)
559            | TLExpr::Tan(e) => {
560                *non_leaf_count += 1;
561                *child_count += 1;
562                self.compute_recursive(
563                    e,
564                    depth + 1,
565                    depth_sum,
566                    non_leaf_count,
567                    child_count,
568                    quantifier_depth,
569                    modal_depth,
570                    temporal_depth,
571                );
572            }
573
574            // Binary operators
575            TLExpr::Imply(l, r)
576            | TLExpr::Add(l, r)
577            | TLExpr::Sub(l, r)
578            | TLExpr::Mul(l, r)
579            | TLExpr::Div(l, r)
580            | TLExpr::Pow(l, r)
581            | TLExpr::Mod(l, r)
582            | TLExpr::Min(l, r)
583            | TLExpr::Max(l, r)
584            | TLExpr::Eq(l, r)
585            | TLExpr::Lt(l, r)
586            | TLExpr::Gt(l, r)
587            | TLExpr::Lte(l, r)
588            | TLExpr::Gte(l, r) => {
589                *non_leaf_count += 1;
590                *child_count += 2;
591                self.compute_recursive(
592                    l,
593                    depth + 1,
594                    depth_sum,
595                    non_leaf_count,
596                    child_count,
597                    quantifier_depth,
598                    modal_depth,
599                    temporal_depth,
600                );
601                self.compute_recursive(
602                    r,
603                    depth + 1,
604                    depth_sum,
605                    non_leaf_count,
606                    child_count,
607                    quantifier_depth,
608                    modal_depth,
609                    temporal_depth,
610                );
611            }
612
613            // Fuzzy operators
614            TLExpr::TNorm { left, right, .. }
615            | TLExpr::TCoNorm { left, right, .. }
616            | TLExpr::FuzzyImplication {
617                premise: left,
618                conclusion: right,
619                ..
620            } => {
621                *non_leaf_count += 1;
622                *child_count += 2;
623                self.compute_recursive(
624                    left,
625                    depth + 1,
626                    depth_sum,
627                    non_leaf_count,
628                    child_count,
629                    quantifier_depth,
630                    modal_depth,
631                    temporal_depth,
632                );
633                self.compute_recursive(
634                    right,
635                    depth + 1,
636                    depth_sum,
637                    non_leaf_count,
638                    child_count,
639                    quantifier_depth,
640                    modal_depth,
641                    temporal_depth,
642                );
643            }
644
645            TLExpr::FuzzyNot { expr, .. } => {
646                *non_leaf_count += 1;
647                *child_count += 1;
648                self.compute_recursive(
649                    expr,
650                    depth + 1,
651                    depth_sum,
652                    non_leaf_count,
653                    child_count,
654                    quantifier_depth,
655                    modal_depth,
656                    temporal_depth,
657                );
658            }
659
660            // Probabilistic operators
661            TLExpr::WeightedRule { rule, .. } => {
662                *non_leaf_count += 1;
663                *child_count += 1;
664                self.compute_recursive(
665                    rule,
666                    depth + 1,
667                    depth_sum,
668                    non_leaf_count,
669                    child_count,
670                    quantifier_depth,
671                    modal_depth,
672                    temporal_depth,
673                );
674            }
675
676            TLExpr::ProbabilisticChoice { alternatives } => {
677                self.cyclomatic_complexity += alternatives.len(); // Multiple decision points
678                *non_leaf_count += 1;
679                *child_count += alternatives.len();
680                for (_, e) in alternatives {
681                    self.compute_recursive(
682                        e,
683                        depth + 1,
684                        depth_sum,
685                        non_leaf_count,
686                        child_count,
687                        quantifier_depth,
688                        modal_depth,
689                        temporal_depth,
690                    );
691                }
692            }
693
694            // Aggregation
695            TLExpr::Aggregate { body, .. } => {
696                *non_leaf_count += 1;
697                *child_count += 1;
698                self.compute_recursive(
699                    body,
700                    depth + 1,
701                    depth_sum,
702                    non_leaf_count,
703                    child_count,
704                    quantifier_depth,
705                    modal_depth,
706                    temporal_depth,
707                );
708            }
709
710            // Let binding
711            TLExpr::Let { value, body, .. } => {
712                *non_leaf_count += 1;
713                *child_count += 2;
714                self.compute_recursive(
715                    value,
716                    depth + 1,
717                    depth_sum,
718                    non_leaf_count,
719                    child_count,
720                    quantifier_depth,
721                    modal_depth,
722                    temporal_depth,
723                );
724                self.compute_recursive(
725                    body,
726                    depth + 1,
727                    depth_sum,
728                    non_leaf_count,
729                    child_count,
730                    quantifier_depth,
731                    modal_depth,
732                    temporal_depth,
733                );
734            }
735
736            // Beta.1 enhancements - comprehensive coverage
737            TLExpr::Lambda { body, .. }
738            | TLExpr::SetCardinality { set: body }
739            | TLExpr::SetComprehension {
740                condition: body, ..
741            }
742            | TLExpr::CountingExists { body, .. }
743            | TLExpr::CountingForAll { body, .. }
744            | TLExpr::ExactCount { body, .. }
745            | TLExpr::Majority { body, .. }
746            | TLExpr::LeastFixpoint { body, .. }
747            | TLExpr::GreatestFixpoint { body, .. }
748            | TLExpr::At { formula: body, .. }
749            | TLExpr::Somewhere { formula: body }
750            | TLExpr::Everywhere { formula: body }
751            | TLExpr::Explain { formula: body } => {
752                *non_leaf_count += 1;
753                *child_count += 1;
754                self.compute_recursive(
755                    body,
756                    depth + 1,
757                    depth_sum,
758                    non_leaf_count,
759                    child_count,
760                    quantifier_depth + 1,
761                    modal_depth,
762                    temporal_depth,
763                );
764            }
765            TLExpr::Apply { function, argument }
766            | TLExpr::SetMembership {
767                element: function,
768                set: argument,
769            }
770            | TLExpr::SetUnion {
771                left: function,
772                right: argument,
773            }
774            | TLExpr::SetIntersection {
775                left: function,
776                right: argument,
777            }
778            | TLExpr::SetDifference {
779                left: function,
780                right: argument,
781            } => {
782                *non_leaf_count += 1;
783                *child_count += 2;
784                self.compute_recursive(
785                    function,
786                    depth + 1,
787                    depth_sum,
788                    non_leaf_count,
789                    child_count,
790                    quantifier_depth,
791                    modal_depth,
792                    temporal_depth,
793                );
794                self.compute_recursive(
795                    argument,
796                    depth + 1,
797                    depth_sum,
798                    non_leaf_count,
799                    child_count,
800                    quantifier_depth,
801                    modal_depth,
802                    temporal_depth,
803                );
804            }
805            TLExpr::GlobalCardinality { values, .. } => {
806                *non_leaf_count += 1;
807                *child_count += values.len();
808                for val in values {
809                    self.compute_recursive(
810                        val,
811                        depth + 1,
812                        depth_sum,
813                        non_leaf_count,
814                        child_count,
815                        quantifier_depth,
816                        modal_depth,
817                        temporal_depth,
818                    );
819                }
820            }
821            TLExpr::EmptySet
822            | TLExpr::Nominal { .. }
823            | TLExpr::AllDifferent { .. }
824            | TLExpr::Abducible { .. }
825            | TLExpr::SymbolLiteral(_) => {
826                self.leaf_count += 1;
827                *depth_sum += depth;
828            }
829            TLExpr::Match { scrutinee, arms } => {
830                *non_leaf_count += 1;
831                *child_count += 1 + arms.len();
832                self.compute_recursive(
833                    scrutinee,
834                    depth + 1,
835                    depth_sum,
836                    non_leaf_count,
837                    child_count,
838                    quantifier_depth,
839                    modal_depth,
840                    temporal_depth,
841                );
842                for (_, body) in arms {
843                    self.compute_recursive(
844                        body,
845                        depth + 1,
846                        depth_sum,
847                        non_leaf_count,
848                        child_count,
849                        quantifier_depth,
850                        modal_depth,
851                        temporal_depth,
852                    );
853                }
854            }
855        }
856    }
857}
858
859/// Pattern detection results.
860#[derive(Clone, Debug, PartialEq, Eq)]
861pub struct PatternAnalysis {
862    /// Detected De Morgan's law patterns: ¬(A ∧ B) or ¬(A ∨ B)
863    pub de_morgan_patterns: usize,
864    /// Double negation patterns: ¬¬A
865    pub double_negation: usize,
866    /// Modal duality patterns: ◇P with ¬□¬P nearby
867    pub modal_duality: usize,
868    /// Temporal duality patterns: FP with ¬G¬P nearby
869    pub temporal_duality: usize,
870    /// Redundant quantifier patterns (nested same quantifiers)
871    pub redundant_quantifiers: usize,
872    /// Tautologies (always true expressions)
873    pub tautologies: usize,
874    /// Contradictions (always false expressions)
875    pub contradictions: usize,
876}
877
878impl PatternAnalysis {
879    /// Detect patterns in an expression.
880    pub fn from_expr(expr: &TLExpr) -> Self {
881        let mut analysis = Self {
882            de_morgan_patterns: 0,
883            double_negation: 0,
884            modal_duality: 0,
885            temporal_duality: 0,
886            redundant_quantifiers: 0,
887            tautologies: 0,
888            contradictions: 0,
889        };
890
891        analysis.detect_recursive(expr, &HashMap::new());
892        analysis
893    }
894
895    fn detect_recursive(&mut self, expr: &TLExpr, _context: &HashMap<String, TLExpr>) {
896        match expr {
897            // Double negation and De Morgan's patterns
898            TLExpr::Not(e) => {
899                // Double negation: ¬¬A
900                if matches!(**e, TLExpr::Not(_)) {
901                    self.double_negation += 1;
902                }
903                // De Morgan's patterns: ¬(A ∧ B) or ¬(A ∨ B)
904                if matches!(**e, TLExpr::And(_, _) | TLExpr::Or(_, _)) {
905                    self.de_morgan_patterns += 1;
906                }
907                self.detect_recursive(e, _context);
908            }
909
910            // Tautologies: A ∨ ¬A, A → A, A ∨ TRUE
911            TLExpr::Or(l, r) => {
912                if let (TLExpr::Not(inner), other) | (other, TLExpr::Not(inner)) = (&**l, &**r) {
913                    if **inner == *other {
914                        self.tautologies += 1;
915                    }
916                }
917                if matches!(**l, TLExpr::Constant(v) if v >= 1.0)
918                    || matches!(**r, TLExpr::Constant(v) if v >= 1.0)
919                {
920                    self.tautologies += 1;
921                }
922                self.detect_recursive(l, _context);
923                self.detect_recursive(r, _context);
924            }
925
926            TLExpr::Imply(l, r) => {
927                if l == r {
928                    self.tautologies += 1;
929                }
930                self.detect_recursive(l, _context);
931                self.detect_recursive(r, _context);
932            }
933
934            // Contradictions: A ∧ ¬A, A ∧ FALSE
935            TLExpr::And(l, r) => {
936                if let (TLExpr::Not(inner), other) | (other, TLExpr::Not(inner)) = (&**l, &**r) {
937                    if **inner == *other {
938                        self.contradictions += 1;
939                    }
940                }
941                if matches!(**l, TLExpr::Constant(v) if v <= 0.0)
942                    || matches!(**r, TLExpr::Constant(v) if v <= 0.0)
943                {
944                    self.contradictions += 1;
945                }
946                self.detect_recursive(l, _context);
947                self.detect_recursive(r, _context);
948            }
949
950            // Redundant quantifiers: ∃x.∃x.P or ∀x.∀x.P
951            TLExpr::Exists { var, body, .. } => {
952                if let TLExpr::Exists { var: inner_var, .. } = &**body {
953                    if var == inner_var {
954                        self.redundant_quantifiers += 1;
955                    }
956                }
957                self.detect_recursive(body, _context);
958            }
959
960            TLExpr::ForAll { var, body, .. } => {
961                if let TLExpr::ForAll { var: inner_var, .. } = &**body {
962                    if var == inner_var {
963                        self.redundant_quantifiers += 1;
964                    }
965                }
966                self.detect_recursive(body, _context);
967            }
968
969            // Modal duality: ◇P when we see ¬□¬P pattern
970            TLExpr::Diamond(e) => {
971                if let TLExpr::Not(inner) = &**e {
972                    if let TLExpr::Box(inner_inner) = &**inner {
973                        if matches!(**inner_inner, TLExpr::Not(_)) {
974                            self.modal_duality += 1;
975                        }
976                    }
977                }
978                self.detect_recursive(e, _context);
979            }
980
981            // Temporal duality: FP when we see ¬G¬P pattern
982            TLExpr::Eventually(e) => {
983                if let TLExpr::Not(inner) = &**e {
984                    if let TLExpr::Always(inner_inner) = &**inner {
985                        if matches!(**inner_inner, TLExpr::Not(_)) {
986                            self.temporal_duality += 1;
987                        }
988                    }
989                }
990                self.detect_recursive(e, _context);
991            }
992
993            // Recursive cases (And and Or are handled above for pattern detection)
994            TLExpr::Add(l, r)
995            | TLExpr::Sub(l, r)
996            | TLExpr::Mul(l, r)
997            | TLExpr::Div(l, r)
998            | TLExpr::Pow(l, r)
999            | TLExpr::Mod(l, r)
1000            | TLExpr::Min(l, r)
1001            | TLExpr::Max(l, r)
1002            | TLExpr::Eq(l, r)
1003            | TLExpr::Lt(l, r)
1004            | TLExpr::Gt(l, r)
1005            | TLExpr::Lte(l, r)
1006            | TLExpr::Gte(l, r) => {
1007                self.detect_recursive(l, _context);
1008                self.detect_recursive(r, _context);
1009            }
1010
1011            TLExpr::Score(e)
1012            | TLExpr::Abs(e)
1013            | TLExpr::Floor(e)
1014            | TLExpr::Ceil(e)
1015            | TLExpr::Round(e)
1016            | TLExpr::Sqrt(e)
1017            | TLExpr::Exp(e)
1018            | TLExpr::Log(e)
1019            | TLExpr::Sin(e)
1020            | TLExpr::Cos(e)
1021            | TLExpr::Tan(e)
1022            | TLExpr::Box(e)
1023            | TLExpr::Next(e)
1024            | TLExpr::Always(e) => {
1025                self.detect_recursive(e, _context);
1026            }
1027
1028            TLExpr::Until { before, after }
1029            | TLExpr::Release {
1030                released: before,
1031                releaser: after,
1032            }
1033            | TLExpr::WeakUntil { before, after }
1034            | TLExpr::StrongRelease {
1035                released: before,
1036                releaser: after,
1037            } => {
1038                self.detect_recursive(before, _context);
1039                self.detect_recursive(after, _context);
1040            }
1041
1042            TLExpr::TNorm { left, right, .. }
1043            | TLExpr::TCoNorm { left, right, .. }
1044            | TLExpr::FuzzyImplication {
1045                premise: left,
1046                conclusion: right,
1047                ..
1048            } => {
1049                self.detect_recursive(left, _context);
1050                self.detect_recursive(right, _context);
1051            }
1052
1053            TLExpr::FuzzyNot { expr, .. } => {
1054                self.detect_recursive(expr, _context);
1055            }
1056
1057            TLExpr::SoftExists { body, .. }
1058            | TLExpr::SoftForAll { body, .. }
1059            | TLExpr::Aggregate { body, .. } => {
1060                self.detect_recursive(body, _context);
1061            }
1062
1063            TLExpr::WeightedRule { rule, .. } => {
1064                self.detect_recursive(rule, _context);
1065            }
1066
1067            TLExpr::ProbabilisticChoice { alternatives } => {
1068                for (_, e) in alternatives {
1069                    self.detect_recursive(e, _context);
1070                }
1071            }
1072
1073            TLExpr::IfThenElse {
1074                condition,
1075                then_branch,
1076                else_branch,
1077            } => {
1078                self.detect_recursive(condition, _context);
1079                self.detect_recursive(then_branch, _context);
1080                self.detect_recursive(else_branch, _context);
1081            }
1082
1083            TLExpr::Let { value, body, .. } => {
1084                self.detect_recursive(value, _context);
1085                self.detect_recursive(body, _context);
1086            }
1087
1088            // Beta.1 enhancements
1089            TLExpr::Lambda { body, .. }
1090            | TLExpr::SetCardinality { set: body }
1091            | TLExpr::SetComprehension {
1092                condition: body, ..
1093            }
1094            | TLExpr::CountingExists { body, .. }
1095            | TLExpr::CountingForAll { body, .. }
1096            | TLExpr::ExactCount { body, .. }
1097            | TLExpr::Majority { body, .. }
1098            | TLExpr::LeastFixpoint { body, .. }
1099            | TLExpr::GreatestFixpoint { body, .. }
1100            | TLExpr::At { formula: body, .. }
1101            | TLExpr::Somewhere { formula: body }
1102            | TLExpr::Everywhere { formula: body }
1103            | TLExpr::Explain { formula: body } => {
1104                self.detect_recursive(body, _context);
1105            }
1106            TLExpr::Apply { function, argument }
1107            | TLExpr::SetMembership {
1108                element: function,
1109                set: argument,
1110            }
1111            | TLExpr::SetUnion {
1112                left: function,
1113                right: argument,
1114            }
1115            | TLExpr::SetIntersection {
1116                left: function,
1117                right: argument,
1118            }
1119            | TLExpr::SetDifference {
1120                left: function,
1121                right: argument,
1122            } => {
1123                self.detect_recursive(function, _context);
1124                self.detect_recursive(argument, _context);
1125            }
1126            TLExpr::GlobalCardinality { values, .. } => {
1127                for val in values {
1128                    self.detect_recursive(val, _context);
1129                }
1130            }
1131            TLExpr::EmptySet
1132            | TLExpr::Nominal { .. }
1133            | TLExpr::AllDifferent { .. }
1134            | TLExpr::Abducible { .. }
1135            | TLExpr::SymbolLiteral(_) => {}
1136
1137            TLExpr::Match { scrutinee, arms } => {
1138                self.detect_recursive(scrutinee, _context);
1139                for (_, body) in arms {
1140                    self.detect_recursive(body, _context);
1141                }
1142            }
1143
1144            // Leaves
1145            TLExpr::Pred { .. } | TLExpr::Constant(_) => {}
1146        }
1147    }
1148}
1149
1150#[cfg(test)]
1151mod tests {
1152    use super::*;
1153    use crate::Term;
1154
1155    #[test]
1156    fn test_operator_counts_basic() {
1157        // Simple: P(x) AND Q(x)
1158        let expr = TLExpr::and(
1159            TLExpr::pred("P", vec![Term::var("x")]),
1160            TLExpr::pred("Q", vec![Term::var("x")]),
1161        );
1162
1163        let counts = OperatorCounts::from_expr(&expr);
1164        assert_eq!(counts.total, 3); // AND + 2 predicates
1165        assert_eq!(counts.logical, 1);
1166        assert_eq!(counts.predicates, 2);
1167    }
1168
1169    #[test]
1170    fn test_operator_counts_modal() {
1171        // □(P(x))
1172        let expr = TLExpr::modal_box(TLExpr::pred("P", vec![Term::var("x")]));
1173
1174        let counts = OperatorCounts::from_expr(&expr);
1175        assert_eq!(counts.modal, 1);
1176        assert_eq!(counts.predicates, 1);
1177    }
1178
1179    #[test]
1180    fn test_operator_counts_temporal() {
1181        // F(P(x))
1182        let expr = TLExpr::eventually(TLExpr::pred("P", vec![Term::var("x")]));
1183
1184        let counts = OperatorCounts::from_expr(&expr);
1185        assert_eq!(counts.temporal, 1);
1186        assert_eq!(counts.predicates, 1);
1187    }
1188
1189    #[test]
1190    fn test_operator_counts_fuzzy() {
1191        // P(x) ⊤_min Q(x)
1192        let expr = TLExpr::fuzzy_and(
1193            TLExpr::pred("P", vec![Term::var("x")]),
1194            TLExpr::pred("Q", vec![Term::var("x")]),
1195        );
1196
1197        let counts = OperatorCounts::from_expr(&expr);
1198        assert_eq!(counts.fuzzy, 1);
1199        assert_eq!(counts.predicates, 2);
1200    }
1201
1202    #[test]
1203    fn test_complexity_metrics_simple() {
1204        // P(x)
1205        let expr = TLExpr::pred("P", vec![Term::var("x")]);
1206
1207        let metrics = ComplexityMetrics::from_expr(&expr);
1208        assert_eq!(metrics.max_depth, 0);
1209        assert_eq!(metrics.node_count, 1);
1210        assert_eq!(metrics.leaf_count, 1);
1211    }
1212
1213    #[test]
1214    fn test_complexity_metrics_nested() {
1215        // ((P AND Q) OR (R AND S))
1216        let expr = TLExpr::or(
1217            TLExpr::and(
1218                TLExpr::pred("P", vec![Term::var("x")]),
1219                TLExpr::pred("Q", vec![Term::var("x")]),
1220            ),
1221            TLExpr::and(
1222                TLExpr::pred("R", vec![Term::var("x")]),
1223                TLExpr::pred("S", vec![Term::var("x")]),
1224            ),
1225        );
1226
1227        let metrics = ComplexityMetrics::from_expr(&expr);
1228        assert_eq!(metrics.max_depth, 2); // OR at 0, AND at 1, predicates at 2
1229        assert_eq!(metrics.node_count, 7); // 1 OR + 2 AND + 4 predicates
1230        assert_eq!(metrics.leaf_count, 4);
1231        assert_eq!(metrics.cyclomatic_complexity, 4); // 1 + 3 decision points (OR, 2 ANDs)
1232    }
1233
1234    #[test]
1235    fn test_complexity_quantifier_depth() {
1236        // ∃x.∀y.P(x,y)
1237        let expr = TLExpr::exists(
1238            "x",
1239            "D",
1240            TLExpr::forall(
1241                "y",
1242                "D",
1243                TLExpr::pred("P", vec![Term::var("x"), Term::var("y")]),
1244            ),
1245        );
1246
1247        let metrics = ComplexityMetrics::from_expr(&expr);
1248        assert_eq!(metrics.quantifier_depth, 2);
1249    }
1250
1251    #[test]
1252    fn test_complexity_modal_depth() {
1253        // □◇P(x)
1254        let expr = TLExpr::modal_box(TLExpr::modal_diamond(TLExpr::pred(
1255            "P",
1256            vec![Term::var("x")],
1257        )));
1258
1259        let metrics = ComplexityMetrics::from_expr(&expr);
1260        assert_eq!(metrics.modal_depth, 2);
1261    }
1262
1263    #[test]
1264    fn test_pattern_double_negation() {
1265        // ¬¬P(x)
1266        let expr = TLExpr::negate(TLExpr::negate(TLExpr::pred("P", vec![Term::var("x")])));
1267
1268        let patterns = PatternAnalysis::from_expr(&expr);
1269        assert_eq!(patterns.double_negation, 1);
1270    }
1271
1272    #[test]
1273    fn test_pattern_de_morgan() {
1274        // ¬(P ∧ Q)
1275        let expr = TLExpr::negate(TLExpr::and(
1276            TLExpr::pred("P", vec![Term::var("x")]),
1277            TLExpr::pred("Q", vec![Term::var("x")]),
1278        ));
1279
1280        let patterns = PatternAnalysis::from_expr(&expr);
1281        assert_eq!(patterns.de_morgan_patterns, 1);
1282    }
1283
1284    #[test]
1285    fn test_pattern_tautology() {
1286        // P(x) ∨ ¬P(x)
1287        let p = TLExpr::pred("P", vec![Term::var("x")]);
1288        let expr = TLExpr::or(p.clone(), TLExpr::negate(p));
1289
1290        let patterns = PatternAnalysis::from_expr(&expr);
1291        assert_eq!(patterns.tautologies, 1);
1292    }
1293
1294    #[test]
1295    fn test_pattern_contradiction() {
1296        // P(x) ∧ ¬P(x)
1297        let p = TLExpr::pred("P", vec![Term::var("x")]);
1298        let expr = TLExpr::and(p.clone(), TLExpr::negate(p));
1299
1300        let patterns = PatternAnalysis::from_expr(&expr);
1301        assert_eq!(patterns.contradictions, 1);
1302    }
1303
1304    #[test]
1305    fn test_pattern_redundant_quantifier() {
1306        // ∃x.∃x.P(x) - redundant nesting of same variable
1307        let expr = TLExpr::exists(
1308            "x",
1309            "D",
1310            TLExpr::exists("x", "D", TLExpr::pred("P", vec![Term::var("x")])),
1311        );
1312
1313        let patterns = PatternAnalysis::from_expr(&expr);
1314        assert_eq!(patterns.redundant_quantifiers, 1);
1315    }
1316}