""" Description : Quality Evaluation Layer (Layer 3) - Diversity Evaluator (4-dimension) - Semantic Coverage Calculator - Test Case Quality Scorer Author : CGA Enhancement Project Time : 2026/03/16 """ import re import logging import hashlib import json from typing import List, Dict, Optional, Any, Tuple, Set from dataclasses import dataclass, field from enum import Enum from collections import defaultdict logger = logging.getLogger(__name__) # ============================================================================ # 配置常量 # ============================================================================ class QualityConfig: """质量评估配置""" # 多样性评估权重 SEQUENCE_DIVERSITY_WEIGHT = 0.30 # 输入序列多样性权重 SEMANTIC_VECTOR_WEIGHT = 0.25 # 语义向量多样性权重 EXECUTION_PATH_WEIGHT = 0.25 # 执行路径多样性权重 FUNCTION_COVERAGE_WEIGHT = 0.20 # 功能覆盖多样性权重 # 多样性阈值 MIN_DIVERSITY_THRESHOLD = 0.1 # 最低多样性阈值 HIGH_DIVERSITY_THRESHOLD = 0.7 # 高多样性阈值 # 语义覆盖率阈值 SEMANTIC_COVERAGE_TARGET = 0.85 # 目标语义覆盖率 # 编辑距离配置 MIN_EDIT_DISTANCE = 3 # 最小编辑距离要求 # 相似度阈值 SIMILARITY_THRESHOLD = 0.8 # 相似度阈值(超过此值认为相似) # ============================================================================ # 数据结构定义 # ============================================================================ class DiversityDimension(Enum): """多样性维度枚举""" SEQUENCE = "sequence" # 输入序列多样性 SEMANTIC_VECTOR = "semantic" # 语义向量多样性 EXECUTION_PATH = "path" # 执行路径多样性 FUNCTION_COVERAGE = "function" # 功能覆盖多样性 @dataclass class DiversityScore: """ 多样性评分 Attributes: sequence_diversity: 输入序列多样性得分 semantic_diversity: 语义向量多样性得分 path_diversity: 执行路径多样性得分 function_diversity: 功能覆盖多样性得分 overall_score: 综合多样性得分 details: 详细信息 """ sequence_diversity: float = 0.0 semantic_diversity: float = 0.0 path_diversity: float = 0.0 function_diversity: float = 0.0 overall_score: float = 0.0 details: Dict[str, Any] = field(default_factory=dict) def calculate_overall(self) -> float: """计算综合多样性得分""" self.overall_score = ( QualityConfig.SEQUENCE_DIVERSITY_WEIGHT * self.sequence_diversity + QualityConfig.SEMANTIC_VECTOR_WEIGHT * self.semantic_diversity + QualityConfig.EXECUTION_PATH_WEIGHT * self.path_diversity + QualityConfig.FUNCTION_COVERAGE_WEIGHT * self.function_diversity ) return self.overall_score def to_dict(self) -> Dict[str, Any]: """转换为字典""" return { 'sequence_diversity': round(self.sequence_diversity, 4), 'semantic_diversity': round(self.semantic_diversity, 4), 'path_diversity': round(self.path_diversity, 4), 'function_diversity': round(self.function_diversity, 4), 'overall_score': round(self.overall_score, 4), 'details': self.details } @dataclass class SemanticCoverageResult: """ 语义覆盖率结果 Attributes: total_function_points: 总功能点数 covered_function_points: 已覆盖功能点数 semantic_coverage: 语义覆盖率 coverage_by_type: 按类型统计的覆盖率 uncovered_important: 未覆盖的高重要性功能点 """ total_function_points: int = 0 covered_function_points: int = 0 semantic_coverage: float = 0.0 coverage_by_type: Dict[str, float] = field(default_factory=dict) uncovered_important: List[Dict[str, Any]] = field(default_factory=list) def to_dict(self) -> Dict[str, Any]: """转换为字典""" return { 'total_function_points': self.total_function_points, 'covered_function_points': self.covered_function_points, 'semantic_coverage': round(self.semantic_coverage, 4), 'coverage_by_type': self.coverage_by_type, 'uncovered_important': self.uncovered_important } @dataclass class FunctionCoverageState: """ 功能点覆盖状态 Attributes: name: 功能点名称 fp_type: 功能点类型 importance: 重要性评分 covered: 是否已覆盖 covered_by: 覆盖该功能点的测试用例ID列表 last_check_iteration: 最后检查的迭代次数 """ name: str fp_type: str importance: float covered: bool = False covered_by: List[str] = field(default_factory=list) last_check_iteration: int = 0 # ============================================================================ # 编辑距离计算器 # ============================================================================ class EditDistanceCalculator: """编辑距离计算器""" @staticmethod def levenshtein_distance(s1: str, s2: str) -> int: """ 计算Levenshtein编辑距离 Args: s1: 字符串1 s2: 字符串2 Returns: 编辑距离 """ if len(s1) < len(s2): return EditDistanceCalculator.levenshtein_distance(s2, s1) if len(s2) == 0: return len(s1) previous_row = range(len(s2) + 1) for i, c1 in enumerate(s1): current_row = [i + 1] for j, c2 in enumerate(s2): # 插入、删除、替换 insertions = previous_row[j + 1] + 1 deletions = current_row[j] + 1 substitutions = previous_row[j] + (c1 != c2) current_row.append(min(insertions, deletions, substitutions)) previous_row = current_row return previous_row[-1] @staticmethod def normalized_distance(s1: str, s2: str) -> float: """ 计算归一化的编辑距离 (0-1范围) Args: s1: 字符串1 s2: 字符串2 Returns: 归一化编辑距离 (0表示相同,1表示完全不同) """ if not s1 and not s2: return 0.0 max_len = max(len(s1), len(s2)) if max_len == 0: return 0.0 distance = EditDistanceCalculator.levenshtein_distance(s1, s2) return distance / max_len @staticmethod def similarity(s1: str, s2: str) -> float: """ 计算相似度 (1 - 归一化编辑距离) Args: s1: 字符串1 s2: 字符串2 Returns: 相似度 (1表示相同,0表示完全不同) """ return 1.0 - EditDistanceCalculator.normalized_distance(s1, s2) # ============================================================================ # 序列特征提取器 # ============================================================================ class SequenceFeatureExtractor: """序列特征提取器""" @staticmethod def extract_features(code: str) -> Dict[str, Any]: """ 从代码中提取序列特征 Args: code: 测试代码 Returns: 特征字典 """ features = { 'signal_assignments': [], # 信号赋值序列 'delay_patterns': [], # 延时模式 'control_structures': [], # 控制结构 'signal_values': {}, # 信号值映射 'operation_sequence': [], # 操作序列 'code_hash': '' # 代码哈希 } # 提取信号赋值 assign_pattern = r'(\w+)\s*=\s*([^;]+);' for match in re.finditer(assign_pattern, code): signal = match.group(1) value = match.group(2).strip() features['signal_assignments'].append((signal, value)) if signal not in features['signal_values']: features['signal_values'][signal] = [] features['signal_values'][signal].append(value) # 提取延时模式 delay_pattern = r'#(\d+)' delays = [int(d) for d in re.findall(delay_pattern, code)] features['delay_patterns'] = delays # 提取repeat循环 repeat_pattern = r'repeat\s*\(\s*(\d+)\s*\)' repeats = [int(r) for r in re.findall(repeat_pattern, code)] features['control_structures'].extend([('repeat', r) for r in repeats]) # 提取posedge/negedge edge_pattern = r'@(?:posedge|negedge)\s+(\w+)' edges = re.findall(edge_pattern, code) features['control_structures'].extend([('edge', e) for e in edges]) # 构建操作序列 all_operations = [] # 按位置排序的所有操作 for match in re.finditer(r'((?:\w+\s*=\s*[^;]+;)|(?:#\d+;)|(?:repeat\s*\(\d+\)[^;]+;)|(?:@\([^)]+\)))', code): all_operations.append(match.group(1).strip()) features['operation_sequence'] = all_operations # 计算代码哈希 normalized_code = re.sub(r'\s+', ' ', code).strip() features['code_hash'] = hashlib.md5(normalized_code.encode()).hexdigest()[:16] return features @staticmethod def extract_signal_sequence(code: str, signals: List[str] = None) -> List[Tuple[str, str, str]]: """ 提取信号赋值序列 Args: code: 测试代码 signals: 关注的信号列表(可选) Returns: (信号名, 值, 上下文) 元组列表 """ sequences = [] # 按行处理,保持上下文 lines = code.split('\n') context = "" for line in lines: stripped = line.strip() # 更新上下文 if stripped.startswith('//'): context = stripped continue # 提取赋值 assign_match = re.match(r'(\w+)\s*=\s*([^;]+);', stripped) if assign_match: signal = assign_match.group(1) value = assign_match.group(2).strip() # 如果指定了信号列表,只提取关注的信号 if signals is None or signal in signals: sequences.append((signal, value, context)) return sequences # ============================================================================ # 多样性评估器 # ============================================================================ class DiversityEvaluator: """ 多样性评估器 四维度多样性评估: 1. 输入序列多样性:计算与已有序列的编辑距离 2. 语义向量多样性:计算代码特征向量的相似度 3. 执行路径多样性:计算新覆盖代码行的比例 4. 功能覆盖多样性:计算新覆盖功能点的比例 """ def __init__(self): """初始化多样性评估器""" self.history: List[Dict[str, Any]] = [] self.feature_extractor = SequenceFeatureExtractor() self.edit_distance_calc = EditDistanceCalculator() def add_to_history(self, code: str, covered_lines: Set[int] = None, covered_functions: List[str] = None, test_id: str = ""): """ 添加测试用例到历史记录 Args: code: 测试代码 covered_lines: 覆盖的代码行 covered_functions: 覆盖的功能点列表 test_id: 测试用例ID """ features = self.feature_extractor.extract_features(code) record = { 'test_id': test_id, 'code': code, 'features': features, 'covered_lines': covered_lines or set(), 'covered_functions': covered_functions or [], 'code_hash': features['code_hash'] } self.history.append(record) def evaluate(self, new_code: str, new_covered_lines: Set[int] = None, new_covered_functions: List[str] = None) -> DiversityScore: """ 评估新测试用例的多样性 Args: new_code: 新测试代码 new_covered_lines: 新覆盖的代码行 new_covered_functions: 新覆盖的功能点列表 Returns: 多样性评分 """ score = DiversityScore() if not self.history: # 第一个测试用例,给予最高多样性 score.sequence_diversity = 1.0 score.semantic_diversity = 1.0 score.path_diversity = 1.0 score.function_diversity = 1.0 score.calculate_overall() score.details = {'reason': 'first_test_case'} return score # 提取新代码特征 new_features = self.feature_extractor.extract_features(new_code) new_covered_lines = new_covered_lines or set() new_covered_functions = new_covered_functions or [] # 1. 计算输入序列多样性 score.sequence_diversity = self._evaluate_sequence_diversity(new_code, new_features) # 2. 计算语义向量多样性 score.semantic_diversity = self._evaluate_semantic_diversity(new_features) # 3. 计算执行路径多样性 score.path_diversity = self._evaluate_path_diversity(new_covered_lines) # 4. 计算功能覆盖多样性 score.function_diversity = self._evaluate_function_diversity(new_covered_functions) # 计算综合得分 score.calculate_overall() # 添加详细信息 score.details = { 'history_size': len(self.history), 'new_code_hash': new_features['code_hash'], 'signal_count': len(new_features['signal_values']), 'operation_count': len(new_features['operation_sequence']) } return score def _evaluate_sequence_diversity(self, new_code: str, new_features: Dict) -> float: """评估输入序列多样性""" if not self.history: return 1.0 # 提取操作序列 new_ops = new_features['operation_sequence'] # 计算与历史中所有测试的最小相似度(即最大差异) max_distance = 0.0 for record in self.history[-10:]: # 只比较最近10个 hist_ops = record['features']['operation_sequence'] # 将操作序列转换为字符串计算编辑距离 new_ops_str = ' '.join(new_ops) hist_ops_str = ' '.join(hist_ops) similarity = self.edit_distance_calc.similarity(new_ops_str, hist_ops_str) distance = 1.0 - similarity max_distance = max(max_distance, distance) return max_distance def _evaluate_semantic_diversity(self, new_features: Dict) -> float: """评估语义向量多样性""" if not self.history: return 1.0 # 构建特征向量 new_vector = self._build_feature_vector(new_features) # 计算与历史特征向量的最小相似度 max_distance = 0.0 for record in self.history[-10:]: hist_vector = self._build_feature_vector(record['features']) similarity = self._cosine_similarity(new_vector, hist_vector) distance = 1.0 - similarity max_distance = max(max_distance, distance) return max_distance def _evaluate_path_diversity(self, new_covered_lines: Set[int]) -> float: """评估执行路径多样性""" if not self.history: return 1.0 if not new_covered_lines: return 0.0 # 计算历史覆盖的并集 all_covered = set() for record in self.history: all_covered.update(record['covered_lines']) # 计算新覆盖的行 new_lines = new_covered_lines - all_covered if not new_covered_lines: return 0.0 # 新覆盖比例 novelty_ratio = len(new_lines) / len(new_covered_lines) return novelty_ratio def _evaluate_function_diversity(self, new_covered_functions: List[str]) -> float: """评估功能覆盖多样性""" if not self.history: return 1.0 if not new_covered_functions: return 0.0 # 计算历史覆盖的功能点并集 all_covered = set() for record in self.history: all_covered.update(record['covered_functions']) # 计算新覆盖的功能点 new_functions = set(new_covered_functions) - all_covered if not new_covered_functions: return 0.0 # 新覆盖比例 novelty_ratio = len(new_functions) / len(new_covered_functions) return novelty_ratio def _build_feature_vector(self, features: Dict) -> Dict[str, float]: """构建特征向量""" vector = {} # 信号数量 vector['signal_count'] = len(features['signal_values']) # 操作数量 vector['operation_count'] = len(features['operation_sequence']) # 延时数量 vector['delay_count'] = len(features['delay_patterns']) # 延时总和 vector['delay_sum'] = sum(features['delay_patterns']) # 控制结构数量 vector['control_count'] = len(features['control_structures']) # repeat循环数量 repeat_count = sum(1 for c in features['control_structures'] if c[0] == 'repeat') vector['repeat_count'] = repeat_count # 边沿等待数量 edge_count = sum(1 for c in features['control_structures'] if c[0] == 'edge') vector['edge_count'] = edge_count # 赋值数量 vector['assignment_count'] = len(features['signal_assignments']) return vector def _cosine_similarity(self, v1: Dict[str, float], v2: Dict[str, float]) -> float: """计算余弦相似度""" # 获取所有键 all_keys = set(v1.keys()) | set(v2.keys()) if not all_keys: return 0.0 # 计算点积和模 dot_product = 0.0 norm1 = 0.0 norm2 = 0.0 for key in all_keys: val1 = v1.get(key, 0.0) val2 = v2.get(key, 0.0) dot_product += val1 * val2 norm1 += val1 * val1 norm2 += val2 * val2 if norm1 == 0 or norm2 == 0: return 0.0 return dot_product / (norm1 ** 0.5 * norm2 ** 0.5) def get_diversity_statistics(self) -> Dict[str, Any]: """获取多样性统计信息""" # if not self.history: # return { # 'total_tests': 0, # 'unique_hashes': 0, # 'avg_diversity': 0.0 # } if not self.history: return { 'total_tests': 0, 'unique_hashes': 0, 'avg_diversity': 0.0, 'duplicate_ratio': 0.0 # ✅ 添加缺失的键 } unique_hashes = len(set(r['code_hash'] for r in self.history)) return { 'total_tests': len(self.history), 'unique_hashes': unique_hashes, 'duplicate_ratio': 1.0 - (unique_hashes / len(self.history)) if self.history else 0.0 } # ============================================================================ # 语义覆盖率计算器 # ============================================================================ class SemanticCoverageCalculator: """ 语义覆盖率计算器 计算基于功能点重要性的语义覆盖率: 语义覆盖率 = Σ(已覆盖功能点重要性) / Σ(所有功能点重要性) """ def __init__(self, function_points: List[Dict[str, Any]] = None): """ 初始化语义覆盖率计算器 Args: function_points: 功能点列表 """ self.function_points: Dict[str, FunctionCoverageState] = {} self.total_importance = 0.0 self.covered_importance = 0.0 if function_points: self.initialize(function_points) def initialize(self, function_points: List[Dict[str, Any]]) -> Dict[str, Any]: """ 初始化功能点覆盖状态 Args: function_points: 功能点列表 Returns: 初始化结果 """ self.function_points.clear() self.total_importance = 0.0 self.covered_importance = 0.0 for fp in function_points: name = fp.get('name', '') fp_type = fp.get('type', 'unknown') importance = fp.get('importance', 0.0) self.function_points[name] = FunctionCoverageState( name=name, fp_type=fp_type, importance=importance, covered=False, covered_by=[], last_check_iteration=0 ) self.total_importance += importance return { 'total_function_points': len(self.function_points), 'total_importance': self.total_importance } def update_coverage(self, covered_lines: Set[int] = None, covered_functions: List[str] = None, test_id: str = "", iteration: int = 0) -> SemanticCoverageResult: """ 更新功能点覆盖状态 Args: covered_lines: 覆盖的代码行 covered_functions: 覆盖的功能点名称列表 test_id: 测试用例ID iteration: 当前迭代次数 Returns: 语义覆盖率结果 """ # 更新覆盖状态 if covered_functions: for func_name in covered_functions: if func_name in self.function_points: fp = self.function_points[func_name] if not fp.covered: fp.covered = True fp.covered_by.append(test_id) fp.last_check_iteration = iteration self.covered_importance += fp.importance return self.calculate_coverage() def calculate_coverage(self) -> SemanticCoverageResult: """ 计算当前语义覆盖率 Returns: 语义覆盖率结果 """ result = SemanticCoverageResult() result.total_function_points = len(self.function_points) result.covered_function_points = sum(1 for fp in self.function_points.values() if fp.covered) # 计算语义覆盖率 if self.total_importance > 0: result.semantic_coverage = self.covered_importance / self.total_importance # 按类型统计 type_stats = defaultdict(lambda: {'total': 0, 'covered': 0, 'importance': 0.0, 'covered_importance': 0.0}) for fp in self.function_points.values(): type_stats[fp.fp_type]['total'] += 1 type_stats[fp.fp_type]['importance'] += fp.importance if fp.covered: type_stats[fp.fp_type]['covered'] += 1 type_stats[fp.fp_type]['covered_importance'] += fp.importance for fp_type, stats in type_stats.items(): if stats['importance'] > 0: result.coverage_by_type[fp_type] = stats['covered_importance'] / stats['importance'] else: result.coverage_by_type[fp_type] = 0.0 # 找出未覆盖的高重要性功能点 uncovered_important = [ { 'name': fp.name, 'type': fp.fp_type, 'importance': fp.importance } for fp in self.function_points.values() if not fp.covered and fp.importance >= 0.5 ] uncovered_important.sort(key=lambda x: x['importance'], reverse=True) result.uncovered_important = uncovered_important[:5] # 只返回前5个 return result def get_function_point_status(self, name: str) -> Optional[FunctionCoverageState]: """获取指定功能点的覆盖状态""" return self.function_points.get(name) def get_uncovered_function_points(self, min_importance: float = 0.0, fp_type: str = None) -> List[FunctionCoverageState]: """ 获取未覆盖的功能点 Args: min_importance: 最小重要性阈值 fp_type: 功能点类型过滤(可选) Returns: 未覆盖的功能点列表 """ uncovered = [] for fp in self.function_points.values(): if fp.covered: continue if fp.importance < min_importance: continue if fp_type and fp.fp_type != fp_type: continue uncovered.append(fp) # 按重要性排序 uncovered.sort(key=lambda x: x.importance, reverse=True) return uncovered def get_coverage_report(self) -> str: """生成覆盖率报告""" result = self.calculate_coverage() lines = [] lines.append("=" * 60) lines.append("SEMANTIC COVERAGE REPORT") lines.append("=" * 60) lines.append("") lines.append(f"Total Function Points: {result.total_function_points}") lines.append(f"Covered Function Points: {result.covered_function_points}") lines.append(f"Semantic Coverage: {result.semantic_coverage:.2%}") lines.append("") lines.append("Coverage by Type:") for fp_type, coverage in result.coverage_by_type.items(): lines.append(f" - {fp_type}: {coverage:.2%}") lines.append("") if result.uncovered_important: lines.append("Uncovered High-Importance Function Points:") for fp in result.uncovered_important: lines.append(f" - {fp['name']} ({fp['type']}): importance={fp['importance']:.2f}") lines.append("") lines.append("=" * 60) return "\n".join(lines) def to_dict(self) -> Dict[str, Any]: """转换为字典""" return { 'total_importance': self.total_importance, 'covered_importance': self.covered_importance, 'function_points': { name: { 'type': fp.fp_type, 'importance': fp.importance, 'covered': fp.covered, 'covered_by': fp.covered_by } for name, fp in self.function_points.items() } } # ============================================================================ # 质量评估器(主入口) # ============================================================================ class QualityEvaluator: """ 质量评估器 - 第3层主入口 整合多样性评估和语义覆盖率计算,提供统一的质量评估接口 """ def __init__(self, function_points: List[Dict[str, Any]] = None): """ 初始化质量评估器 Args: function_points: 功能点列表 """ self.diversity_evaluator = DiversityEvaluator() self.semantic_coverage = SemanticCoverageCalculator(function_points) self.evaluation_history: List[Dict[str, Any]] = [] def initialize(self, function_points: List[Dict[str, Any]]) -> Dict[str, Any]: """ 初始化质量评估器 Args: function_points: 功能点列表 Returns: 初始化结果 """ result = self.semantic_coverage.initialize(function_points) self.evaluation_history.clear() return result def evaluate_test_case(self, code: str, covered_lines: Set[int] = None, covered_functions: List[str] = None, test_id: str = "", iteration: int = 0) -> Dict[str, Any]: """ 评估测试用例质量 Args: code: 测试代码 covered_lines: 覆盖的代码行 covered_functions: 覆盖的功能点列表 test_id: 测试用例ID iteration: 当前迭代次数 Returns: 评估结果字典 """ # 1. 多样性评估 diversity_score = self.diversity_evaluator.evaluate( new_code=code, new_covered_lines=covered_lines, new_covered_functions=covered_functions ) # 2. 更新语义覆盖率 coverage_result = self.semantic_coverage.update_coverage( covered_lines=covered_lines, covered_functions=covered_functions, test_id=test_id, iteration=iteration ) # 3. 计算质量得分 quality_score = self._calculate_quality_score(diversity_score, coverage_result) # 4. 记录评估历史 evaluation_result = { 'test_id': test_id, 'iteration': iteration, 'diversity': diversity_score.to_dict(), 'coverage': coverage_result.to_dict(), 'quality_score': quality_score } self.evaluation_history.append(evaluation_result) # 5. 添加到多样性历史 self.diversity_evaluator.add_to_history( code=code, covered_lines=covered_lines, covered_functions=covered_functions, test_id=test_id ) return evaluation_result def _calculate_quality_score(self, diversity: DiversityScore, coverage: SemanticCoverageResult) -> float: """ 计算综合质量得分 Args: diversity: 多样性评分 coverage: 语义覆盖率结果 Returns: 质量得分 (0-1) """ # 多样性权重 diversity_weight = 0.4 # 覆盖率增量权重 coverage_weight = 0.6 # 综合得分 score = ( diversity_weight * diversity.overall_score + coverage_weight * coverage.semantic_coverage ) return min(1.0, max(0.0, score)) def should_accept(self, evaluation_result: Dict[str, Any], min_diversity: float = QualityConfig.MIN_DIVERSITY_THRESHOLD) -> Tuple[bool, str]: """ 判断是否应该接受该测试用例 Args: evaluation_result: 评估结果 min_diversity: 最低多样性阈值 Returns: (是否接受, 原因) """ diversity = evaluation_result.get('diversity', {}) overall_diversity = diversity.get('overall_score', 0.0) if overall_diversity < min_diversity: return False, f"Diversity too low: {overall_diversity:.2f} < {min_diversity}" return True, "Passed quality check" def get_statistics(self) -> Dict[str, Any]: """获取统计信息""" diversity_stats = self.diversity_evaluator.get_diversity_statistics() coverage_result = self.semantic_coverage.calculate_coverage() return { 'diversity': diversity_stats, 'coverage': coverage_result.to_dict(), 'total_evaluations': len(self.evaluation_history) } def generate_report(self) -> str: """生成完整报告""" lines = [] lines.append("=" * 70) lines.append("QUALITY EVALUATION REPORT - LAYER 3") lines.append("=" * 70) lines.append("") # 多样性统计 stats = self.get_statistics() lines.append("[DIVERSITY STATISTICS]") lines.append(f"Total Tests: {stats['diversity']['total_tests']}") lines.append(f"Unique Tests: {stats['diversity']['unique_hashes']}") lines.append(f"Duplicate Ratio: {stats['diversity']['duplicate_ratio']:.2%}") lines.append("") # 语义覆盖率 lines.append("[SEMANTIC COVERAGE]") lines.append(self.semantic_coverage.get_coverage_report()) lines.append("") # 质量趋势 if self.evaluation_history: lines.append("[QUALITY TREND]") avg_quality = sum(e['quality_score'] for e in self.evaluation_history) / len(self.evaluation_history) avg_diversity = sum(e['diversity']['overall_score'] for e in self.evaluation_history) / len(self.evaluation_history) lines.append(f"Average Quality Score: {avg_quality:.2f}") lines.append(f"Average Diversity Score: {avg_diversity:.2f}") lines.append("") lines.append("=" * 70) return "\n".join(lines) # ============================================================================ # 便捷函数 # ============================================================================ def create_quality_evaluator(function_points: List[Dict[str, Any]] = None) -> QualityEvaluator: """ 创建质量评估器 Args: function_points: 功能点列表 Returns: 初始化完成的质量评估器 """ return QualityEvaluator(function_points=function_points) def evaluate_diversity(code1: str, code2: str) -> float: """ 快速评估两个代码的多样性 Args: code1: 代码1 code2: 代码2 Returns: 多样性得分 (0-1, 1表示完全不同) """ calc = EditDistanceCalculator() return calc.normalized_distance(code1, code2)