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        }
291    }
292}
293
294/// Complexity metrics for an expression.
295#[derive(Clone, Debug, PartialEq)]
296pub struct ComplexityMetrics {
297    /// Maximum depth of the expression tree
298    pub max_depth: usize,
299    /// Average depth of leaf nodes
300    pub avg_depth: f64,
301    /// Total number of nodes
302    pub node_count: usize,
303    /// Number of leaf nodes (predicates and constants)
304    pub leaf_count: usize,
305    /// Branching factor (average number of children per non-leaf node)
306    pub branching_factor: f64,
307    /// Cyclomatic complexity (number of decision points + 1)
308    pub cyclomatic_complexity: usize,
309    /// Quantifier depth (maximum nesting level of quantifiers)
310    pub quantifier_depth: usize,
311    /// Modal depth (maximum nesting level of modal operators)
312    pub modal_depth: usize,
313    /// Temporal depth (maximum nesting level of temporal operators)
314    pub temporal_depth: usize,
315}
316
317impl ComplexityMetrics {
318    /// Compute complexity metrics from an expression.
319    pub fn from_expr(expr: &TLExpr) -> Self {
320        let mut metrics = Self {
321            max_depth: 0,
322            avg_depth: 0.0,
323            node_count: 0,
324            leaf_count: 0,
325            branching_factor: 0.0,
326            cyclomatic_complexity: 1, // Start with 1
327            quantifier_depth: 0,
328            modal_depth: 0,
329            temporal_depth: 0,
330        };
331
332        let mut depth_sum = 0;
333        let mut non_leaf_count = 0;
334        let mut child_count = 0;
335
336        metrics.compute_recursive(
337            expr,
338            0,
339            &mut depth_sum,
340            &mut non_leaf_count,
341            &mut child_count,
342            0,
343            0,
344            0,
345        );
346
347        // Compute averages
348        if metrics.leaf_count > 0 {
349            metrics.avg_depth = depth_sum as f64 / metrics.leaf_count as f64;
350        }
351        if non_leaf_count > 0 {
352            metrics.branching_factor = child_count as f64 / non_leaf_count as f64;
353        }
354
355        metrics
356    }
357
358    #[allow(clippy::too_many_arguments)]
359    fn compute_recursive(
360        &mut self,
361        expr: &TLExpr,
362        depth: usize,
363        depth_sum: &mut usize,
364        non_leaf_count: &mut usize,
365        child_count: &mut usize,
366        quantifier_depth: usize,
367        modal_depth: usize,
368        temporal_depth: usize,
369    ) {
370        self.node_count += 1;
371        self.max_depth = self.max_depth.max(depth);
372        self.quantifier_depth = self.quantifier_depth.max(quantifier_depth);
373        self.modal_depth = self.modal_depth.max(modal_depth);
374        self.temporal_depth = self.temporal_depth.max(temporal_depth);
375
376        match expr {
377            // Leaves
378            TLExpr::Pred { .. } | TLExpr::Constant(_) => {
379                self.leaf_count += 1;
380                *depth_sum += depth;
381            }
382
383            // Decision points (add to cyclomatic complexity)
384            TLExpr::IfThenElse {
385                condition,
386                then_branch,
387                else_branch,
388            } => {
389                self.cyclomatic_complexity += 1; // Decision point
390                *non_leaf_count += 1;
391                *child_count += 3;
392                self.compute_recursive(
393                    condition,
394                    depth + 1,
395                    depth_sum,
396                    non_leaf_count,
397                    child_count,
398                    quantifier_depth,
399                    modal_depth,
400                    temporal_depth,
401                );
402                self.compute_recursive(
403                    then_branch,
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                    else_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            }
423
424            // Logical operators (decision points)
425            TLExpr::And(l, r) | TLExpr::Or(l, r) => {
426                self.cyclomatic_complexity += 1; // Decision point
427                *non_leaf_count += 1;
428                *child_count += 2;
429                self.compute_recursive(
430                    l,
431                    depth + 1,
432                    depth_sum,
433                    non_leaf_count,
434                    child_count,
435                    quantifier_depth,
436                    modal_depth,
437                    temporal_depth,
438                );
439                self.compute_recursive(
440                    r,
441                    depth + 1,
442                    depth_sum,
443                    non_leaf_count,
444                    child_count,
445                    quantifier_depth,
446                    modal_depth,
447                    temporal_depth,
448                );
449            }
450
451            // Quantifiers (increase quantifier depth)
452            TLExpr::Exists { body, .. }
453            | TLExpr::ForAll { body, .. }
454            | TLExpr::SoftExists { body, .. }
455            | TLExpr::SoftForAll { body, .. } => {
456                *non_leaf_count += 1;
457                *child_count += 1;
458                self.compute_recursive(
459                    body,
460                    depth + 1,
461                    depth_sum,
462                    non_leaf_count,
463                    child_count,
464                    quantifier_depth + 1,
465                    modal_depth,
466                    temporal_depth,
467                );
468            }
469
470            // Modal operators (increase modal depth)
471            TLExpr::Box(e) | TLExpr::Diamond(e) => {
472                *non_leaf_count += 1;
473                *child_count += 1;
474                self.compute_recursive(
475                    e,
476                    depth + 1,
477                    depth_sum,
478                    non_leaf_count,
479                    child_count,
480                    quantifier_depth,
481                    modal_depth + 1,
482                    temporal_depth,
483                );
484            }
485
486            // Temporal operators (increase temporal depth)
487            TLExpr::Next(e) | TLExpr::Eventually(e) | TLExpr::Always(e) => {
488                *non_leaf_count += 1;
489                *child_count += 1;
490                self.compute_recursive(
491                    e,
492                    depth + 1,
493                    depth_sum,
494                    non_leaf_count,
495                    child_count,
496                    quantifier_depth,
497                    modal_depth,
498                    temporal_depth + 1,
499                );
500            }
501
502            // Binary temporal operators
503            TLExpr::Until { before, after }
504            | TLExpr::Release {
505                released: before,
506                releaser: after,
507            }
508            | TLExpr::WeakUntil { before, after }
509            | TLExpr::StrongRelease {
510                released: before,
511                releaser: after,
512            } => {
513                *non_leaf_count += 1;
514                *child_count += 2;
515                self.compute_recursive(
516                    before,
517                    depth + 1,
518                    depth_sum,
519                    non_leaf_count,
520                    child_count,
521                    quantifier_depth,
522                    modal_depth,
523                    temporal_depth + 1,
524                );
525                self.compute_recursive(
526                    after,
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            }
536
537            // Unary operators
538            TLExpr::Not(e)
539            | TLExpr::Score(e)
540            | TLExpr::Abs(e)
541            | TLExpr::Floor(e)
542            | TLExpr::Ceil(e)
543            | TLExpr::Round(e)
544            | TLExpr::Sqrt(e)
545            | TLExpr::Exp(e)
546            | TLExpr::Log(e)
547            | TLExpr::Sin(e)
548            | TLExpr::Cos(e)
549            | TLExpr::Tan(e) => {
550                *non_leaf_count += 1;
551                *child_count += 1;
552                self.compute_recursive(
553                    e,
554                    depth + 1,
555                    depth_sum,
556                    non_leaf_count,
557                    child_count,
558                    quantifier_depth,
559                    modal_depth,
560                    temporal_depth,
561                );
562            }
563
564            // Binary operators
565            TLExpr::Imply(l, r)
566            | TLExpr::Add(l, r)
567            | TLExpr::Sub(l, r)
568            | TLExpr::Mul(l, r)
569            | TLExpr::Div(l, r)
570            | TLExpr::Pow(l, r)
571            | TLExpr::Mod(l, r)
572            | TLExpr::Min(l, r)
573            | TLExpr::Max(l, r)
574            | TLExpr::Eq(l, r)
575            | TLExpr::Lt(l, r)
576            | TLExpr::Gt(l, r)
577            | TLExpr::Lte(l, r)
578            | TLExpr::Gte(l, r) => {
579                *non_leaf_count += 1;
580                *child_count += 2;
581                self.compute_recursive(
582                    l,
583                    depth + 1,
584                    depth_sum,
585                    non_leaf_count,
586                    child_count,
587                    quantifier_depth,
588                    modal_depth,
589                    temporal_depth,
590                );
591                self.compute_recursive(
592                    r,
593                    depth + 1,
594                    depth_sum,
595                    non_leaf_count,
596                    child_count,
597                    quantifier_depth,
598                    modal_depth,
599                    temporal_depth,
600                );
601            }
602
603            // Fuzzy operators
604            TLExpr::TNorm { left, right, .. }
605            | TLExpr::TCoNorm { left, right, .. }
606            | TLExpr::FuzzyImplication {
607                premise: left,
608                conclusion: right,
609                ..
610            } => {
611                *non_leaf_count += 1;
612                *child_count += 2;
613                self.compute_recursive(
614                    left,
615                    depth + 1,
616                    depth_sum,
617                    non_leaf_count,
618                    child_count,
619                    quantifier_depth,
620                    modal_depth,
621                    temporal_depth,
622                );
623                self.compute_recursive(
624                    right,
625                    depth + 1,
626                    depth_sum,
627                    non_leaf_count,
628                    child_count,
629                    quantifier_depth,
630                    modal_depth,
631                    temporal_depth,
632                );
633            }
634
635            TLExpr::FuzzyNot { expr, .. } => {
636                *non_leaf_count += 1;
637                *child_count += 1;
638                self.compute_recursive(
639                    expr,
640                    depth + 1,
641                    depth_sum,
642                    non_leaf_count,
643                    child_count,
644                    quantifier_depth,
645                    modal_depth,
646                    temporal_depth,
647                );
648            }
649
650            // Probabilistic operators
651            TLExpr::WeightedRule { rule, .. } => {
652                *non_leaf_count += 1;
653                *child_count += 1;
654                self.compute_recursive(
655                    rule,
656                    depth + 1,
657                    depth_sum,
658                    non_leaf_count,
659                    child_count,
660                    quantifier_depth,
661                    modal_depth,
662                    temporal_depth,
663                );
664            }
665
666            TLExpr::ProbabilisticChoice { alternatives } => {
667                self.cyclomatic_complexity += alternatives.len(); // Multiple decision points
668                *non_leaf_count += 1;
669                *child_count += alternatives.len();
670                for (_, e) in alternatives {
671                    self.compute_recursive(
672                        e,
673                        depth + 1,
674                        depth_sum,
675                        non_leaf_count,
676                        child_count,
677                        quantifier_depth,
678                        modal_depth,
679                        temporal_depth,
680                    );
681                }
682            }
683
684            // Aggregation
685            TLExpr::Aggregate { body, .. } => {
686                *non_leaf_count += 1;
687                *child_count += 1;
688                self.compute_recursive(
689                    body,
690                    depth + 1,
691                    depth_sum,
692                    non_leaf_count,
693                    child_count,
694                    quantifier_depth,
695                    modal_depth,
696                    temporal_depth,
697                );
698            }
699
700            // Let binding
701            TLExpr::Let { value, body, .. } => {
702                *non_leaf_count += 1;
703                *child_count += 2;
704                self.compute_recursive(
705                    value,
706                    depth + 1,
707                    depth_sum,
708                    non_leaf_count,
709                    child_count,
710                    quantifier_depth,
711                    modal_depth,
712                    temporal_depth,
713                );
714                self.compute_recursive(
715                    body,
716                    depth + 1,
717                    depth_sum,
718                    non_leaf_count,
719                    child_count,
720                    quantifier_depth,
721                    modal_depth,
722                    temporal_depth,
723                );
724            }
725
726            // Beta.1 enhancements - comprehensive coverage
727            TLExpr::Lambda { body, .. }
728            | TLExpr::SetCardinality { set: body }
729            | TLExpr::SetComprehension {
730                condition: body, ..
731            }
732            | TLExpr::CountingExists { body, .. }
733            | TLExpr::CountingForAll { body, .. }
734            | TLExpr::ExactCount { body, .. }
735            | TLExpr::Majority { body, .. }
736            | TLExpr::LeastFixpoint { body, .. }
737            | TLExpr::GreatestFixpoint { body, .. }
738            | TLExpr::At { formula: body, .. }
739            | TLExpr::Somewhere { formula: body }
740            | TLExpr::Everywhere { formula: body }
741            | TLExpr::Explain { formula: body } => {
742                *non_leaf_count += 1;
743                *child_count += 1;
744                self.compute_recursive(
745                    body,
746                    depth + 1,
747                    depth_sum,
748                    non_leaf_count,
749                    child_count,
750                    quantifier_depth + 1,
751                    modal_depth,
752                    temporal_depth,
753                );
754            }
755            TLExpr::Apply { function, argument }
756            | TLExpr::SetMembership {
757                element: function,
758                set: argument,
759            }
760            | TLExpr::SetUnion {
761                left: function,
762                right: argument,
763            }
764            | TLExpr::SetIntersection {
765                left: function,
766                right: argument,
767            }
768            | TLExpr::SetDifference {
769                left: function,
770                right: argument,
771            } => {
772                *non_leaf_count += 1;
773                *child_count += 2;
774                self.compute_recursive(
775                    function,
776                    depth + 1,
777                    depth_sum,
778                    non_leaf_count,
779                    child_count,
780                    quantifier_depth,
781                    modal_depth,
782                    temporal_depth,
783                );
784                self.compute_recursive(
785                    argument,
786                    depth + 1,
787                    depth_sum,
788                    non_leaf_count,
789                    child_count,
790                    quantifier_depth,
791                    modal_depth,
792                    temporal_depth,
793                );
794            }
795            TLExpr::GlobalCardinality { values, .. } => {
796                *non_leaf_count += 1;
797                *child_count += values.len();
798                for val in values {
799                    self.compute_recursive(
800                        val,
801                        depth + 1,
802                        depth_sum,
803                        non_leaf_count,
804                        child_count,
805                        quantifier_depth,
806                        modal_depth,
807                        temporal_depth,
808                    );
809                }
810            }
811            TLExpr::EmptySet
812            | TLExpr::Nominal { .. }
813            | TLExpr::AllDifferent { .. }
814            | TLExpr::Abducible { .. } => {
815                self.leaf_count += 1;
816                *depth_sum += depth;
817            }
818        }
819    }
820}
821
822/// Pattern detection results.
823#[derive(Clone, Debug, PartialEq, Eq)]
824pub struct PatternAnalysis {
825    /// Detected De Morgan's law patterns: ¬(A ∧ B) or ¬(A ∨ B)
826    pub de_morgan_patterns: usize,
827    /// Double negation patterns: ¬¬A
828    pub double_negation: usize,
829    /// Modal duality patterns: ◇P with ¬□¬P nearby
830    pub modal_duality: usize,
831    /// Temporal duality patterns: FP with ¬G¬P nearby
832    pub temporal_duality: usize,
833    /// Redundant quantifier patterns (nested same quantifiers)
834    pub redundant_quantifiers: usize,
835    /// Tautologies (always true expressions)
836    pub tautologies: usize,
837    /// Contradictions (always false expressions)
838    pub contradictions: usize,
839}
840
841impl PatternAnalysis {
842    /// Detect patterns in an expression.
843    pub fn from_expr(expr: &TLExpr) -> Self {
844        let mut analysis = Self {
845            de_morgan_patterns: 0,
846            double_negation: 0,
847            modal_duality: 0,
848            temporal_duality: 0,
849            redundant_quantifiers: 0,
850            tautologies: 0,
851            contradictions: 0,
852        };
853
854        analysis.detect_recursive(expr, &HashMap::new());
855        analysis
856    }
857
858    fn detect_recursive(&mut self, expr: &TLExpr, _context: &HashMap<String, TLExpr>) {
859        match expr {
860            // Double negation and De Morgan's patterns
861            TLExpr::Not(e) => {
862                // Double negation: ¬¬A
863                if matches!(**e, TLExpr::Not(_)) {
864                    self.double_negation += 1;
865                }
866                // De Morgan's patterns: ¬(A ∧ B) or ¬(A ∨ B)
867                if matches!(**e, TLExpr::And(_, _) | TLExpr::Or(_, _)) {
868                    self.de_morgan_patterns += 1;
869                }
870                self.detect_recursive(e, _context);
871            }
872
873            // Tautologies: A ∨ ¬A, A → A, A ∨ TRUE
874            TLExpr::Or(l, r) => {
875                if let (TLExpr::Not(inner), other) | (other, TLExpr::Not(inner)) = (&**l, &**r) {
876                    if **inner == *other {
877                        self.tautologies += 1;
878                    }
879                }
880                if matches!(**l, TLExpr::Constant(v) if v >= 1.0)
881                    || matches!(**r, TLExpr::Constant(v) if v >= 1.0)
882                {
883                    self.tautologies += 1;
884                }
885                self.detect_recursive(l, _context);
886                self.detect_recursive(r, _context);
887            }
888
889            TLExpr::Imply(l, r) => {
890                if l == r {
891                    self.tautologies += 1;
892                }
893                self.detect_recursive(l, _context);
894                self.detect_recursive(r, _context);
895            }
896
897            // Contradictions: A ∧ ¬A, A ∧ FALSE
898            TLExpr::And(l, r) => {
899                if let (TLExpr::Not(inner), other) | (other, TLExpr::Not(inner)) = (&**l, &**r) {
900                    if **inner == *other {
901                        self.contradictions += 1;
902                    }
903                }
904                if matches!(**l, TLExpr::Constant(v) if v <= 0.0)
905                    || matches!(**r, TLExpr::Constant(v) if v <= 0.0)
906                {
907                    self.contradictions += 1;
908                }
909                self.detect_recursive(l, _context);
910                self.detect_recursive(r, _context);
911            }
912
913            // Redundant quantifiers: ∃x.∃x.P or ∀x.∀x.P
914            TLExpr::Exists { var, body, .. } => {
915                if let TLExpr::Exists { var: inner_var, .. } = &**body {
916                    if var == inner_var {
917                        self.redundant_quantifiers += 1;
918                    }
919                }
920                self.detect_recursive(body, _context);
921            }
922
923            TLExpr::ForAll { var, body, .. } => {
924                if let TLExpr::ForAll { var: inner_var, .. } = &**body {
925                    if var == inner_var {
926                        self.redundant_quantifiers += 1;
927                    }
928                }
929                self.detect_recursive(body, _context);
930            }
931
932            // Modal duality: ◇P when we see ¬□¬P pattern
933            TLExpr::Diamond(e) => {
934                if let TLExpr::Not(inner) = &**e {
935                    if let TLExpr::Box(inner_inner) = &**inner {
936                        if matches!(**inner_inner, TLExpr::Not(_)) {
937                            self.modal_duality += 1;
938                        }
939                    }
940                }
941                self.detect_recursive(e, _context);
942            }
943
944            // Temporal duality: FP when we see ¬G¬P pattern
945            TLExpr::Eventually(e) => {
946                if let TLExpr::Not(inner) = &**e {
947                    if let TLExpr::Always(inner_inner) = &**inner {
948                        if matches!(**inner_inner, TLExpr::Not(_)) {
949                            self.temporal_duality += 1;
950                        }
951                    }
952                }
953                self.detect_recursive(e, _context);
954            }
955
956            // Recursive cases (And and Or are handled above for pattern detection)
957            TLExpr::Add(l, r)
958            | TLExpr::Sub(l, r)
959            | TLExpr::Mul(l, r)
960            | TLExpr::Div(l, r)
961            | TLExpr::Pow(l, r)
962            | TLExpr::Mod(l, r)
963            | TLExpr::Min(l, r)
964            | TLExpr::Max(l, r)
965            | TLExpr::Eq(l, r)
966            | TLExpr::Lt(l, r)
967            | TLExpr::Gt(l, r)
968            | TLExpr::Lte(l, r)
969            | TLExpr::Gte(l, r) => {
970                self.detect_recursive(l, _context);
971                self.detect_recursive(r, _context);
972            }
973
974            TLExpr::Score(e)
975            | TLExpr::Abs(e)
976            | TLExpr::Floor(e)
977            | TLExpr::Ceil(e)
978            | TLExpr::Round(e)
979            | TLExpr::Sqrt(e)
980            | TLExpr::Exp(e)
981            | TLExpr::Log(e)
982            | TLExpr::Sin(e)
983            | TLExpr::Cos(e)
984            | TLExpr::Tan(e)
985            | TLExpr::Box(e)
986            | TLExpr::Next(e)
987            | TLExpr::Always(e) => {
988                self.detect_recursive(e, _context);
989            }
990
991            TLExpr::Until { before, after }
992            | TLExpr::Release {
993                released: before,
994                releaser: after,
995            }
996            | TLExpr::WeakUntil { before, after }
997            | TLExpr::StrongRelease {
998                released: before,
999                releaser: after,
1000            } => {
1001                self.detect_recursive(before, _context);
1002                self.detect_recursive(after, _context);
1003            }
1004
1005            TLExpr::TNorm { left, right, .. }
1006            | TLExpr::TCoNorm { left, right, .. }
1007            | TLExpr::FuzzyImplication {
1008                premise: left,
1009                conclusion: right,
1010                ..
1011            } => {
1012                self.detect_recursive(left, _context);
1013                self.detect_recursive(right, _context);
1014            }
1015
1016            TLExpr::FuzzyNot { expr, .. } => {
1017                self.detect_recursive(expr, _context);
1018            }
1019
1020            TLExpr::SoftExists { body, .. }
1021            | TLExpr::SoftForAll { body, .. }
1022            | TLExpr::Aggregate { body, .. } => {
1023                self.detect_recursive(body, _context);
1024            }
1025
1026            TLExpr::WeightedRule { rule, .. } => {
1027                self.detect_recursive(rule, _context);
1028            }
1029
1030            TLExpr::ProbabilisticChoice { alternatives } => {
1031                for (_, e) in alternatives {
1032                    self.detect_recursive(e, _context);
1033                }
1034            }
1035
1036            TLExpr::IfThenElse {
1037                condition,
1038                then_branch,
1039                else_branch,
1040            } => {
1041                self.detect_recursive(condition, _context);
1042                self.detect_recursive(then_branch, _context);
1043                self.detect_recursive(else_branch, _context);
1044            }
1045
1046            TLExpr::Let { value, body, .. } => {
1047                self.detect_recursive(value, _context);
1048                self.detect_recursive(body, _context);
1049            }
1050
1051            // Beta.1 enhancements
1052            TLExpr::Lambda { body, .. }
1053            | TLExpr::SetCardinality { set: body }
1054            | TLExpr::SetComprehension {
1055                condition: body, ..
1056            }
1057            | TLExpr::CountingExists { body, .. }
1058            | TLExpr::CountingForAll { body, .. }
1059            | TLExpr::ExactCount { body, .. }
1060            | TLExpr::Majority { body, .. }
1061            | TLExpr::LeastFixpoint { body, .. }
1062            | TLExpr::GreatestFixpoint { body, .. }
1063            | TLExpr::At { formula: body, .. }
1064            | TLExpr::Somewhere { formula: body }
1065            | TLExpr::Everywhere { formula: body }
1066            | TLExpr::Explain { formula: body } => {
1067                self.detect_recursive(body, _context);
1068            }
1069            TLExpr::Apply { function, argument }
1070            | TLExpr::SetMembership {
1071                element: function,
1072                set: argument,
1073            }
1074            | TLExpr::SetUnion {
1075                left: function,
1076                right: argument,
1077            }
1078            | TLExpr::SetIntersection {
1079                left: function,
1080                right: argument,
1081            }
1082            | TLExpr::SetDifference {
1083                left: function,
1084                right: argument,
1085            } => {
1086                self.detect_recursive(function, _context);
1087                self.detect_recursive(argument, _context);
1088            }
1089            TLExpr::GlobalCardinality { values, .. } => {
1090                for val in values {
1091                    self.detect_recursive(val, _context);
1092                }
1093            }
1094            TLExpr::EmptySet
1095            | TLExpr::Nominal { .. }
1096            | TLExpr::AllDifferent { .. }
1097            | TLExpr::Abducible { .. } => {}
1098
1099            // Leaves
1100            TLExpr::Pred { .. } | TLExpr::Constant(_) => {}
1101        }
1102    }
1103}
1104
1105#[cfg(test)]
1106mod tests {
1107    use super::*;
1108    use crate::Term;
1109
1110    #[test]
1111    fn test_operator_counts_basic() {
1112        // Simple: P(x) AND Q(x)
1113        let expr = TLExpr::and(
1114            TLExpr::pred("P", vec![Term::var("x")]),
1115            TLExpr::pred("Q", vec![Term::var("x")]),
1116        );
1117
1118        let counts = OperatorCounts::from_expr(&expr);
1119        assert_eq!(counts.total, 3); // AND + 2 predicates
1120        assert_eq!(counts.logical, 1);
1121        assert_eq!(counts.predicates, 2);
1122    }
1123
1124    #[test]
1125    fn test_operator_counts_modal() {
1126        // □(P(x))
1127        let expr = TLExpr::modal_box(TLExpr::pred("P", vec![Term::var("x")]));
1128
1129        let counts = OperatorCounts::from_expr(&expr);
1130        assert_eq!(counts.modal, 1);
1131        assert_eq!(counts.predicates, 1);
1132    }
1133
1134    #[test]
1135    fn test_operator_counts_temporal() {
1136        // F(P(x))
1137        let expr = TLExpr::eventually(TLExpr::pred("P", vec![Term::var("x")]));
1138
1139        let counts = OperatorCounts::from_expr(&expr);
1140        assert_eq!(counts.temporal, 1);
1141        assert_eq!(counts.predicates, 1);
1142    }
1143
1144    #[test]
1145    fn test_operator_counts_fuzzy() {
1146        // P(x) ⊤_min Q(x)
1147        let expr = TLExpr::fuzzy_and(
1148            TLExpr::pred("P", vec![Term::var("x")]),
1149            TLExpr::pred("Q", vec![Term::var("x")]),
1150        );
1151
1152        let counts = OperatorCounts::from_expr(&expr);
1153        assert_eq!(counts.fuzzy, 1);
1154        assert_eq!(counts.predicates, 2);
1155    }
1156
1157    #[test]
1158    fn test_complexity_metrics_simple() {
1159        // P(x)
1160        let expr = TLExpr::pred("P", vec![Term::var("x")]);
1161
1162        let metrics = ComplexityMetrics::from_expr(&expr);
1163        assert_eq!(metrics.max_depth, 0);
1164        assert_eq!(metrics.node_count, 1);
1165        assert_eq!(metrics.leaf_count, 1);
1166    }
1167
1168    #[test]
1169    fn test_complexity_metrics_nested() {
1170        // ((P AND Q) OR (R AND S))
1171        let expr = TLExpr::or(
1172            TLExpr::and(
1173                TLExpr::pred("P", vec![Term::var("x")]),
1174                TLExpr::pred("Q", vec![Term::var("x")]),
1175            ),
1176            TLExpr::and(
1177                TLExpr::pred("R", vec![Term::var("x")]),
1178                TLExpr::pred("S", vec![Term::var("x")]),
1179            ),
1180        );
1181
1182        let metrics = ComplexityMetrics::from_expr(&expr);
1183        assert_eq!(metrics.max_depth, 2); // OR at 0, AND at 1, predicates at 2
1184        assert_eq!(metrics.node_count, 7); // 1 OR + 2 AND + 4 predicates
1185        assert_eq!(metrics.leaf_count, 4);
1186        assert_eq!(metrics.cyclomatic_complexity, 4); // 1 + 3 decision points (OR, 2 ANDs)
1187    }
1188
1189    #[test]
1190    fn test_complexity_quantifier_depth() {
1191        // ∃x.∀y.P(x,y)
1192        let expr = TLExpr::exists(
1193            "x",
1194            "D",
1195            TLExpr::forall(
1196                "y",
1197                "D",
1198                TLExpr::pred("P", vec![Term::var("x"), Term::var("y")]),
1199            ),
1200        );
1201
1202        let metrics = ComplexityMetrics::from_expr(&expr);
1203        assert_eq!(metrics.quantifier_depth, 2);
1204    }
1205
1206    #[test]
1207    fn test_complexity_modal_depth() {
1208        // □◇P(x)
1209        let expr = TLExpr::modal_box(TLExpr::modal_diamond(TLExpr::pred(
1210            "P",
1211            vec![Term::var("x")],
1212        )));
1213
1214        let metrics = ComplexityMetrics::from_expr(&expr);
1215        assert_eq!(metrics.modal_depth, 2);
1216    }
1217
1218    #[test]
1219    fn test_pattern_double_negation() {
1220        // ¬¬P(x)
1221        let expr = TLExpr::negate(TLExpr::negate(TLExpr::pred("P", vec![Term::var("x")])));
1222
1223        let patterns = PatternAnalysis::from_expr(&expr);
1224        assert_eq!(patterns.double_negation, 1);
1225    }
1226
1227    #[test]
1228    fn test_pattern_de_morgan() {
1229        // ¬(P ∧ Q)
1230        let expr = TLExpr::negate(TLExpr::and(
1231            TLExpr::pred("P", vec![Term::var("x")]),
1232            TLExpr::pred("Q", vec![Term::var("x")]),
1233        ));
1234
1235        let patterns = PatternAnalysis::from_expr(&expr);
1236        assert_eq!(patterns.de_morgan_patterns, 1);
1237    }
1238
1239    #[test]
1240    fn test_pattern_tautology() {
1241        // P(x) ∨ ¬P(x)
1242        let p = TLExpr::pred("P", vec![Term::var("x")]);
1243        let expr = TLExpr::or(p.clone(), TLExpr::negate(p));
1244
1245        let patterns = PatternAnalysis::from_expr(&expr);
1246        assert_eq!(patterns.tautologies, 1);
1247    }
1248
1249    #[test]
1250    fn test_pattern_contradiction() {
1251        // P(x) ∧ ¬P(x)
1252        let p = TLExpr::pred("P", vec![Term::var("x")]);
1253        let expr = TLExpr::and(p.clone(), TLExpr::negate(p));
1254
1255        let patterns = PatternAnalysis::from_expr(&expr);
1256        assert_eq!(patterns.contradictions, 1);
1257    }
1258
1259    #[test]
1260    fn test_pattern_redundant_quantifier() {
1261        // ∃x.∃x.P(x) - redundant nesting of same variable
1262        let expr = TLExpr::exists(
1263            "x",
1264            "D",
1265            TLExpr::exists("x", "D", TLExpr::pred("P", vec![Term::var("x")])),
1266        );
1267
1268        let patterns = PatternAnalysis::from_expr(&expr);
1269        assert_eq!(patterns.redundant_quantifiers, 1);
1270    }
1271}