Download validators/physics_validator.py from 77yasu77/groxy: direct link, hf CLI and curl.
- Browser
- Download file 34.1 kB
-
https://huggingface.co/spaces/77yasu77/groxy/resolve/main/validators/physics_validator.py
- Command line
-
hf download hf://spaces/77yasu77/groxy/validators/physics_validator.py
-
curl -L -o physics_validator.py https://huggingface.co/spaces/77yasu77/groxy/resolve/main/validators/physics_validator.py
34.1 kB
| import re | |
| import ast | |
| import numpy as np | |
| from typing import Dict, Any, List, Optional, Set, Tuple | |
| from validators.base import BaseValidator, Validator | |
| class PhysicsValidator(BaseValidator, Validator): | |
| """物理シミュレーションのコード検証を行うクラス""" | |
| def __init__(self, client=None): | |
| """物理シミュレーション検証クラスの初期化""" | |
| super().__init__(client) | |
| self.validation_results = {} | |
| # 物理法則および単位関連のキーワード辞書 | |
| self.physics_keywords = { | |
| "mechanics": [ | |
| "force", "acceleration", "velocity", "position", "momentum", "energy", | |
| "力", "加速度", "速度", "位置", "運動量", "エネルギー", "質量", "重力" | |
| ], | |
| "fluid_dynamics": [ | |
| "pressure", "density", "viscosity", "flow", "drag", "lift", "reynolds", | |
| "圧力", "密度", "粘性", "流れ", "抵抗", "揚力", "レイノルズ" | |
| ], | |
| "thermodynamics": [ | |
| "temperature", "heat", "entropy", "thermal", "specific_heat", | |
| "温度", "熱", "エントロピー", "熱的", "比熱" | |
| ], | |
| "electromagnetism": [ | |
| "charge", "field", "magnetic", "electric", "potential", "current", | |
| "電荷", "場", "磁気", "電気", "ポテンシャル", "電流" | |
| ], | |
| "units": [ | |
| "meter", "kilogram", "second", "ampere", "kelvin", "newton", "joule", "watt", "pascal", | |
| "メートル", "キログラム", "秒", "アンペア", "ケルビン", "ニュートン", "ジュール", "ワット", "パスカル" | |
| ], | |
| "constants": [ | |
| "gravity", "g", "lightspeed", "c", "planck", "boltzmann", "avogadro", | |
| "重力定数", "光速", "プランク定数", "ボルツマン定数", "アボガドロ定数" | |
| ] | |
| } | |
| # 物理法則に関するパターン | |
| self.physics_patterns = { | |
| "newton_laws": [ | |
| r"F\s*=\s*m\s*[*]\s*a", # 運動の第2法則 | |
| r"force\s*=\s*mass\s*[*]\s*acceleration", | |
| r"action\s*[.=]\s*reaction", # 作用・反作用の法則 | |
| r"運動方程式", | |
| r"作用反作用" | |
| ], | |
| "conservation": [ | |
| r"energy\s*conserv", # エネルギー保存則 | |
| r"momentum\s*conserv", # 運動量保存則 | |
| r"エネルギー保存", | |
| r"運動量保存" | |
| ], | |
| "fluid_equations": [ | |
| r"bernoulli", # ベルヌーイの定理 | |
| r"navier[\s-]*stokes", # ナビエ・ストークス方程式 | |
| r"reynolds", # レイノルズ数 | |
| r"ベルヌーイ", | |
| r"ナビエ[・\s]*ストークス", | |
| r"レイノルズ数" | |
| ], | |
| "integration_methods": [ | |
| r"euler\s*method", # オイラー法 | |
| r"runge[\s-]*kutta", # ルンゲ・クッタ法 | |
| r"verlet", # ヴェルレ法 | |
| r"leapfrog", # リープフロッグ法 | |
| r"オイラー法", | |
| r"ルンゲ[・\s]*クッタ", | |
| r"ヴェルレ", | |
| r"リープフロッグ" | |
| ] | |
| } | |
| # 物理シミュレーションでよく使用される数値ライブラリ | |
| self.physics_libraries = { | |
| "python": ["numpy", "scipy", "matplotlib", "sympy", "pandas"], | |
| "cpp": ["eigen", "armadillo", "boost", "odeint", "gsl"], | |
| "julia": ["DifferentialEquations", "Flux", "Optim", "StaticArrays"] | |
| } | |
| # 物理シミュレーションの精度と安定性に関する問題パターン | |
| self.numerical_issues = [ | |
| r"dt\s*>\s*[0-9.]+", # タイムステップが大きすぎる | |
| r"step\s*>\s*[0-9.]+", | |
| r"dx\s*>\s*[0-9.]+", # 空間刻みが大きすぎる | |
| r"float", # 精度が低い型を使用(doubleの方が望ましい場合が多い) | |
| r"divide\s*by\s*zero", # ゼロ除算 | |
| r"sqrt\s*\(\s*-", # 負の数の平方根 | |
| r"log\s*\(\s*[0<]", # 負または0の対数 | |
| r"overflow", # オーバーフロー | |
| r"ゼロ除算", | |
| r"精度" | |
| ] | |
| async def validate(self, code, context=None): | |
| """物理シミュレーションの検証を実行する(インターフェース実装)""" | |
| physics_analysis = self.analyze_physics_simulation(code) | |
| if physics_analysis["is_physics_simulation"]: | |
| physics_correctness = self.analyze_physical_correctness( | |
| code, physics_analysis["physics_domain"] | |
| ) | |
| edge_cases = self.detect_edge_cases(code) | |
| self.validation_results = { | |
| "physics_analysis": physics_analysis, | |
| "physics_correctness": physics_correctness, | |
| "edge_cases": edge_cases | |
| } | |
| # 問題点を元のコードに注釈として追加 | |
| if not physics_correctness["is_physically_correct"]: | |
| code = self._add_physics_issues_as_comments(code, physics_correctness["issues"]) | |
| else: | |
| self.validation_results = {"is_physics_simulation": False} | |
| return code | |
| def get_result_summary(self): | |
| """検証結果の要約を返す(インターフェース実装)""" | |
| if not self.validation_results: | |
| return "物理シミュレーション検証はまだ実行されていません。" | |
| if not self.validation_results.get("is_physics_simulation", False): | |
| return "物理シミュレーションとして認識されませんでした。" | |
| correctness = self.validation_results.get("physics_correctness", {}) | |
| if correctness.get("is_physically_correct", True): | |
| return "物理シミュレーションは正確です。" | |
| issues = correctness.get("issues", []) | |
| return f"物理シミュレーションに問題があります: {', '.join(issues[:3])}" | |
| def _add_physics_issues_as_comments(self, code, issues): | |
| """物理的問題を元のコードに注釈として追加する""" | |
| # 新しいユーティリティメソッド | |
| header = "# 物理シミュレーションの問題点:\n" | |
| comments = "\n".join([f"# - {issue}" for issue in issues]) | |
| return f"{header}{comments}\n\n{code}" | |
| def analyze_physics_simulation(self, code: str, language: str = "python") -> Dict[str, Any]: | |
| """物理シミュレーションコードを分析する""" | |
| result = { | |
| "is_physics_simulation": False, | |
| "physics_domain": None, | |
| "implemented_laws": [], | |
| "numerical_method": None, | |
| "issues": [], | |
| "missing_elements": [], | |
| "stability_concerns": [], | |
| "accuracy_score": 0.0, | |
| "recommendations": [] | |
| } | |
| # Step 1: 物理シミュレーションかどうかを判定 | |
| physics_terms_count = 0 | |
| for domain, terms in self.physics_keywords.items(): | |
| for term in terms: | |
| if re.search(r'\b' + re.escape(term) + r'\b', code, re.IGNORECASE): | |
| physics_terms_count += 1 | |
| if result["physics_domain"] is None and domain not in ["units", "constants"]: | |
| result["physics_domain"] = domain | |
| # 少なくとも5つ以上の物理用語が含まれていれば物理シミュレーションと判定 | |
| if physics_terms_count >= 5: | |
| result["is_physics_simulation"] = True | |
| else: | |
| # 物理シミュレーションでない場合は早期リターン | |
| return result | |
| # Step 2: 実装されている物理法則を特定 | |
| for law_type, patterns in self.physics_patterns.items(): | |
| for pattern in patterns: | |
| if re.search(pattern, code, re.IGNORECASE): | |
| result["implemented_laws"].append(law_type) | |
| break # 同じ法則タイプで複数のパターンにマッチしても1回だけカウント | |
| # 重複を削除 | |
| result["implemented_laws"] = list(set(result["implemented_laws"])) | |
| # Step 3: 数値計算法を特定 | |
| if any(re.search(pattern, code, re.IGNORECASE) for pattern in self.physics_patterns["integration_methods"]): | |
| for pattern in self.physics_patterns["integration_methods"]: | |
| match = re.search(pattern, code, re.IGNORECASE) | |
| if match: | |
| result["numerical_method"] = match.group(0) | |
| break | |
| else: | |
| # 明示的な数値計算法が見つからない場合は問題として記録 | |
| result["missing_elements"].append("explicit_numerical_method") | |
| result["recommendations"].append("明示的な数値積分法(オイラー法、ルンゲ・クッタ法など)を実装することを推奨します。") | |
| # Step 4: 数値の安定性に関する問題をチェック | |
| for issue_pattern in self.numerical_issues: | |
| if re.search(issue_pattern, code, re.IGNORECASE): | |
| result["stability_concerns"].append(issue_pattern) | |
| # タイムステップの処理 | |
| time_step_match = re.search(r'dt\s*=\s*([0-9.]+)', code) | |
| if time_step_match: | |
| dt_value = float(time_step_match.group(1)) | |
| if dt_value > 0.1: # 経験的に大きすぎるタイムステップ | |
| result["stability_concerns"].append("large_time_step") | |
| result["recommendations"].append(f"タイムステップ値({dt_value})が大きすぎる可能性があります。より小さな値を検討してください。") | |
| # Step 5: 単位の一貫性をチェック | |
| units_used = [] | |
| for unit in self.physics_keywords["units"]: | |
| if re.search(r'\b' + re.escape(unit) + r'\b', code, re.IGNORECASE): | |
| units_used.append(unit) | |
| if not units_used: | |
| result["missing_elements"].append("explicit_units") | |
| result["recommendations"].append("単位系を明示的に定義することを推奨します(例:SI単位系)。") | |
| # Step 6: エネルギー保存や運動量保存の確認 | |
| if "conservation" not in result["implemented_laws"]: | |
| result["missing_elements"].append("conservation_laws") | |
| result["recommendations"].append("エネルギー保存則や運動量保存則の実装を検討してください。") | |
| # Step 7: 境界条件の確認 | |
| if not re.search(r'boundary|境界条件|境界', code, re.IGNORECASE): | |
| result["missing_elements"].append("boundary_conditions") | |
| result["recommendations"].append("境界条件の明示的な処理を実装することを推奨します。") | |
| # Step 8: 精度スコアの算出(0.0〜5.0の範囲) | |
| accuracy_score = 0.0 | |
| # 適切な数値計算法を使用している場合 | |
| if result["numerical_method"] is not None: | |
| if "runge" in result["numerical_method"].lower() or "クッタ" in result["numerical_method"]: | |
| accuracy_score += 2.0 # ルンゲクッタ法は高精度 | |
| elif "verlet" in result["numerical_method"].lower() or "ヴェルレ" in result["numerical_method"]: | |
| accuracy_score += 1.5 # ヴェルレ法も比較的高精度 | |
| else: | |
| accuracy_score += 1.0 # その他の明示的な数値計算法 | |
| # 保存則を考慮している場合 | |
| if "conservation" in result["implemented_laws"]: | |
| accuracy_score += 1.0 | |
| # 単位を明示的に扱っている場合 | |
| if units_used: | |
| accuracy_score += 0.5 | |
| # 境界条件を考慮している場合 | |
| if "boundary_conditions" not in result["missing_elements"]: | |
| accuracy_score += 0.5 | |
| # 安定性の問題がない場合 | |
| if not result["stability_concerns"]: | |
| accuracy_score += 1.0 | |
| result["accuracy_score"] = min(5.0, accuracy_score) # 最大5.0に制限 | |
| # 追加の分析とレコメンデーション | |
| self._add_additional_recommendations(result, code, language) | |
| return result | |
| def _add_additional_recommendations(self, result: Dict[str, Any], code: str, language: str) -> None: | |
| """追加の分析と推奨事項を生成する""" | |
| # 言語固有のライブラリの使用をチェック | |
| if language in self.physics_libraries: | |
| recommended_libraries = self.physics_libraries[language] | |
| libraries_used = [] | |
| for lib in recommended_libraries: | |
| if re.search(r'(import|using|include).*\b' + re.escape(lib) + r'\b', code, re.IGNORECASE): | |
| libraries_used.append(lib) | |
| # 推奨ライブラリの使用率 | |
| usage_ratio = len(libraries_used) / len(recommended_libraries) | |
| if usage_ratio < 0.3 and result["is_physics_simulation"]: | |
| missing_libs = [lib for lib in recommended_libraries if lib not in libraries_used] | |
| result["recommendations"].append(f"物理シミュレーションに有用なライブラリの使用を検討してください: {', '.join(missing_libs[:3])}") | |
| # エッジケース検出(極端な入力値や境界条件での安定性) | |
| if not re.search(r'(test|check|verify|validate).*edge.*case', code, re.IGNORECASE) and not re.search(r'境界|エッジケース|極端', code, re.IGNORECASE): | |
| result["recommendations"].append("極端な入力値や境界条件でのテストコードを追加することを推奨します。") | |
| # 精度と速度のバランスに関する分析 | |
| if result["numerical_method"] is not None: | |
| if "euler" in result["numerical_method"].lower() or "オイラー" in result["numerical_method"]: | |
| # オイラー法は単純だが精度が低い | |
| result["recommendations"].append("オイラー法は単純ですが精度が低いです。より高精度な数値積分法(ルンゲクッタ法など)の使用を検討してください。") | |
| elif "runge" in result["numerical_method"].lower() or "クッタ" in result["numerical_method"]: | |
| # ルンゲクッタ法は計算コストが高い場合がある | |
| if not re.search(r'adaptive|step.*size|可変|ステップ.*サイズ', code, re.IGNORECASE): | |
| result["recommendations"].append("適応的なステップサイズ制御を使用して計算効率を向上させることを検討してください。") | |
| # 安定性解析のための用語検出 | |
| stability_terms = ["stability", "cfl", "courant", "安定性", "クーラン"] | |
| has_stability_analysis = any(re.search(r'\b' + re.escape(term) + r'\b', code, re.IGNORECASE) for term in stability_terms) | |
| if not has_stability_analysis: | |
| result["recommendations"].append("数値安定性の解析(CFLなど)を追加することを推奨します。") | |
| # エラー評価または検証の検出 | |
| validation_terms = ["error", "validate", "verification", "accuracy", "誤差", "検証", "精度"] | |
| has_validation = any(re.search(r'\b' + re.escape(term) + r'\b', code, re.IGNORECASE) for term in validation_terms) | |
| if not has_validation: | |
| result["recommendations"].append("シミュレーション結果の誤差評価または検証の追加を検討してください。") | |
| def analyze_physical_correctness(self, code: str, physics_type: str = None) -> Dict[str, Any]: | |
| """物理シミュレーションの物理的正確性を分析する""" | |
| result = { | |
| "is_physically_correct": True, | |
| "issues": [], | |
| "correctness_score": 0.0 | |
| } | |
| # まず基本的な物理シミュレーション分析を実行 | |
| basic_analysis = self.analyze_physics_simulation(code) | |
| # 物理シミュレーションでない場合は早期リターン | |
| if not basic_analysis["is_physics_simulation"]: | |
| result["is_physically_correct"] = False | |
| result["issues"].append("物理シミュレーションとして認識できるコードではありません。") | |
| return result | |
| # 物理ドメインの特定(指定がなければ自動検出) | |
| physics_domain = physics_type or basic_analysis["physics_domain"] | |
| # 物理的正確性の確認(ドメイン特有のチェック) | |
| if physics_domain == "mechanics": | |
| # 力学シミュレーションの正確性チェック | |
| self._check_mechanics_correctness(code, result) | |
| elif physics_domain == "fluid_dynamics": | |
| # 流体力学シミュレーションの正確性チェック | |
| self._check_fluid_dynamics_correctness(code, result) | |
| elif physics_domain == "thermodynamics": | |
| # 熱力学シミュレーションの正確性チェック | |
| self._check_thermodynamics_correctness(code, result) | |
| elif physics_domain == "electromagnetism": | |
| # 電磁気学シミュレーションの正確性チェック | |
| self._check_electromagnetism_correctness(code, result) | |
| # 一般的な物理的正確性のチェック | |
| self._check_general_physics_correctness(code, result) | |
| # 基本分析の問題点を統合 | |
| for missing in basic_analysis["missing_elements"]: | |
| if missing == "conservation_laws": | |
| result["is_physically_correct"] = False | |
| result["issues"].append("保存則(エネルギー保存、運動量保存など)が実装されていません。") | |
| elif missing == "boundary_conditions": | |
| result["issues"].append("境界条件の明示的な処理が見つかりません。") | |
| for concern in basic_analysis["stability_concerns"]: | |
| result["issues"].append(f"数値的安定性の問題: {concern}") | |
| # 正確性スコアの計算(0.0〜10.0の範囲) | |
| correctness_score = basic_analysis["accuracy_score"] * 2.0 # 基本スコアを2倍(最大10.0) | |
| # 重大な問題があれば減点 | |
| correctness_score -= len(result["issues"]) * 0.5 | |
| # 最終スコアの範囲調整 | |
| result["correctness_score"] = max(0.0, min(10.0, correctness_score)) | |
| # 物理的正確性の最終判定 | |
| result["is_physically_correct"] = result["correctness_score"] >= 7.0 and not any("保存則" in issue for issue in result["issues"]) | |
| return result | |
| def _check_mechanics_correctness(self, code: str, result: Dict[str, Any]) -> None: | |
| """力学シミュレーションの正確性をチェックする""" | |
| # 運動方程式の検証 | |
| if not re.search(r'F\s*=\s*m\s*[*]\s*a|force\s*=\s*mass\s*[*]\s*acceleration|運動方程式', code, re.IGNORECASE): | |
| result["is_physically_correct"] = False | |
| result["issues"].append("ニュートンの運動方程式(F = ma)が明示的に実装されていません。") | |
| # 重力の適切な処理 | |
| if re.search(r'gravity|重力', code, re.IGNORECASE) and not re.search(r'9\.8|G\s*=\s*6\.67', code): | |
| result["issues"].append("重力定数の適切な値が使用されていない可能性があります。") | |
| # 衝突処理の確認 | |
| if re.search(r'collision|衝突', code, re.IGNORECASE): | |
| if not re.search(r'elastic|inelastic|coefficient\s*of\s*restitution|反発係数|弾性', code, re.IGNORECASE): | |
| result["issues"].append("衝突処理において反発係数や弾性/非弾性の区別が明確でありません。") | |
| def _check_fluid_dynamics_correctness(self, code: str, result: Dict[str, Any]) -> None: | |
| """流体力学シミュレーションの正確性をチェックする""" | |
| # 連続の式のチェック | |
| if not re.search(r'continuity|divergence|連続の式|発散', code, re.IGNORECASE): | |
| result["is_physically_correct"] = False | |
| result["issues"].append("流体の連続の式が実装されていません。") | |
| # ナビエ・ストークス方程式または簡略化されたバージョンのチェック | |
| if not re.search(r'navier[\s-]*stokes|ナビエ[・\s]*ストークス', code, re.IGNORECASE): | |
| if not re.search(r'bernoulli|euler\s*equation|ベルヌーイ|オイラー方程式', code, re.IGNORECASE): | |
| result["issues"].append("標準的な流体方程式(ナビエ・ストークス、オイラー、ベルヌーイなど)が見つかりません。") | |
| # 粘性の考慮 | |
| if re.search(r'viscos|粘性', code, re.IGNORECASE): | |
| if not re.search(r'reynolds|レイノルズ', code, re.IGNORECASE): | |
| result["issues"].append("粘性流体のレイノルズ数による特性評価が見つかりません。") | |
| def _check_thermodynamics_correctness(self, code: str, result: Dict[str, Any]) -> None: | |
| """熱力学シミュレーションの正確性をチェックする""" | |
| # 熱力学第一法則のチェック | |
| if not re.search(r'first\s*law|熱力学第一法則|エネルギー保存', code, re.IGNORECASE): | |
| result["is_physically_correct"] = False | |
| result["issues"].append("熱力学第一法則(エネルギー保存則)が実装されていません。") | |
| # エントロピーの考慮(第二法則) | |
| if not re.search(r'entropy|second\s*law|エントロピー|熱力学第二法則', code, re.IGNORECASE): | |
| result["issues"].append("熱力学第二法則(エントロピー増大の法則)が考慮されていません。") | |
| # 絶対温度の使用 | |
| if re.search(r'temperature|温度', code, re.IGNORECASE) and not re.search(r'kelvin|ケルビン|絶対温度', code, re.IGNORECASE): | |
| if re.search(r'<\s*0', code): # 温度が0未満になる可能性がある | |
| result["issues"].append("温度が絶対零度未満になる可能性があります。絶対温度(ケルビン)を使用してください。") | |
| def _check_electromagnetism_correctness(self, code: str, result: Dict[str, Any]) -> None: | |
| """電磁気学シミュレーションの正確性をチェックする""" | |
| # マクスウェル方程式のチェック | |
| maxwell_terms = ["maxwell", "gauss", "ampere", "faraday", "マクスウェル", "ガウス", "アンペール", "ファラデー"] | |
| has_maxwell = any(re.search(r'\b' + re.escape(term) + r'\b', code, re.IGNORECASE) for term in maxwell_terms) | |
| if not has_maxwell: | |
| result["is_physically_correct"] = False | |
| result["issues"].append("マクスウェル方程式または関連法則(ガウス、アンペール、ファラデーなど)が実装されていません。") | |
| # クーロンの法則のチェック | |
| if re.search(r'charge|電荷', code, re.IGNORECASE) and not re.search(r'coulomb|クーロン', code, re.IGNORECASE): | |
| result["issues"].append("電荷間の相互作用にクーロンの法則が使用されていない可能性があります。") | |
| # 磁場と電場の結合 | |
| if re.search(r'(electric.*magnetic|磁場.*電場|電場.*磁場)', code, re.IGNORECASE): | |
| if not re.search(r'lorentz|ローレンツ', code, re.IGNORECASE): | |
| result["issues"].append("電磁場における荷電粒子の運動にローレンツ力が考慮されていない可能性があります。") | |
| def _check_general_physics_correctness(self, code: str, result: Dict[str, Any]) -> None: | |
| """一般的な物理シミュレーションの正確性をチェックする""" | |
| # 単位の一貫性 | |
| units_pattern = r'\b(meters?|kilograms?|seconds?|amperes?|kelvins?|newtons?|joules?|watts?|pascals?|メートル|キログラム|秒|アンペア|ケルビン|ニュートン|ジュール|ワット|パスカル)\b' | |
| units_mentioned = re.findall(units_pattern, code, re.IGNORECASE) | |
| if units_mentioned: | |
| # SI単位系の使用を確認 | |
| si_units = ["meter", "kilogram", "second", "ampere", "kelvin", "メートル", "キログラム", "秒", "アンペア", "ケルビン"] | |
| non_si_units = ["feet", "pound", "mile", "gallon", "フィート", "ポンド", "マイル", "ガロン"] | |
| uses_si = any(re.search(r'\b' + re.escape(unit) + r'\b', code, re.IGNORECASE) for unit in si_units) | |
| uses_non_si = any(re.search(r'\b' + re.escape(unit) + r'\b', code, re.IGNORECASE) for unit in non_si_units) | |
| if uses_si and uses_non_si: | |
| result["is_physically_correct"] = False | |
| result["issues"].append("SI単位系と非SI単位系が混在しています。単位系を統一してください。") | |
| # 数値定数の桁数と精度 | |
| physics_constants = { | |
| "gravity": r"g\s*=\s*9\.8", | |
| "light_speed": r"c\s*=\s*299792458", | |
| "planck": r"h\s*=\s*6\.626", | |
| "boltzmann": r"k\s*=\s*1\.380649", | |
| "gravitational": r"G\s*=\s*6\.674", | |
| "avogadro": r"N_A\s*=\s*6\.022" | |
| } | |
| for const_name, pattern in physics_constants.items(): | |
| if re.search(r'\b' + const_name + r'\b', code, re.IGNORECASE) and not re.search(pattern, code): | |
| approximate_pattern = pattern.split('.')[0] + r"\." # 最初の小数点まで | |
| if not re.search(approximate_pattern, code): | |
| result["issues"].append(f"{const_name}定数の値が標準的な物理定数と一致していない可能性があります。") | |
| # 初期条件と境界条件の存在確認 | |
| if not re.search(r'initial\s*condition|初期条件', code, re.IGNORECASE): | |
| result["issues"].append("明示的な初期条件の設定が見つかりません。") | |
| if not re.search(r'boundary\s*condition|境界条件', code, re.IGNORECASE): | |
| result["issues"].append("明示的な境界条件の設定が見つかりません。") | |
| # 時間発展の方向性(物理法則の時間反転対称性を考慮) | |
| if re.search(r'time\s*step|time\s*evolution|dt\s*=|時間ステップ|時間発展', code, re.IGNORECASE): | |
| if not re.search(r'forward|backward|前進|後退', code, re.IGNORECASE): | |
| result["issues"].append("時間発展の方向性(前進法/後退法)が明示されていません。") | |
| def detect_edge_cases(self, code: str) -> List[Dict[str, Any]]: | |
| """物理シミュレーションコードにおけるエッジケースを検出する""" | |
| edge_cases = [] | |
| # 1. ゼロ除算の可能性 | |
| division_patterns = [ | |
| r'/\s*0', # 直接的なゼロ除算 | |
| r'/\s*\(\s*[a-zA-Z_]\w*\s*\)', # 変数による除算 | |
| r'/\s*\(\s*.*\s*\)' # 式による除算 | |
| ] | |
| for pattern in division_patterns: | |
| for match in re.finditer(pattern, code): | |
| context = code[max(0, match.start() - 20):min(len(code), match.end() + 20)] | |
| edge_cases.append({ | |
| "type": "zero_division", | |
| "pattern": pattern, | |
| "location": match.span(), | |
| "context": context, | |
| "description": "ゼロ除算の可能性があります。分母がゼロになる場合の処理を追加してください。" | |
| }) | |
| # 2. 負の平方根 | |
| sqrt_patterns = [ | |
| r'sqrt\s*\(\s*-', # 直接的な負の平方根 | |
| r'sqrt\s*\(\s*[a-zA-Z_]\w*\s*\)' # 変数の平方根 | |
| ] | |
| for pattern in sqrt_patterns: | |
| for match in re.finditer(pattern, code): | |
| context = code[max(0, match.start() - 20):min(len(code), match.end() + 20)] | |
| edge_cases.append({ | |
| "type": "negative_sqrt", | |
| "pattern": pattern, | |
| "location": match.span(), | |
| "context": context, | |
| "description": "平方根の引数が負になる可能性があります。値のチェックを追加してください。" | |
| }) | |
| # 3. 対数の無効な引数(ゼロまたは負) | |
| log_patterns = [ | |
| r'log\s*\(\s*0', # ゼロの対数 | |
| r'log\s*\(\s*-', # 負の数の対数 | |
| r'log\s*\(\s*[a-zA-Z_]\w*\s*\)' # 変数の対数 | |
| ] | |
| for pattern in log_patterns: | |
| for match in re.finditer(pattern, code): | |
| context = code[max(0, match.start() - 20):min(len(code), match.end() + 20)] | |
| edge_cases.append({ | |
| "type": "invalid_log", | |
| "pattern": pattern, | |
| "location": match.span(), | |
| "context": context, | |
| "description": "対数の引数がゼロまたは負になる可能性があります。値のチェックを追加してください。" | |
| }) | |
| # 4. 配列の範囲外アクセス | |
| array_access_patterns = [ | |
| r'\[\s*i\s*\]', # インデックスiによるアクセス | |
| r'\[\s*j\s*\]', # インデックスjによるアクセス | |
| r'\[\s*k\s*\]', # インデックスkによるアクセス | |
| r'\[\s*i\s*\+', # i+何かによるアクセス | |
| r'\[\s*i\s*\-', # i-何かによるアクセス | |
| ] | |
| for pattern in array_access_patterns: | |
| for match in re.finditer(pattern, code): | |
| # 範囲チェックがあるか確認 | |
| context_start = max(0, match.start() - 50) | |
| context_end = min(len(code), match.end() + 50) | |
| context = code[context_start:context_end] | |
| # 範囲チェックのパターン | |
| range_check = re.search(r'if\s*\(\s*[ijk]\s*[<>=]', context) | |
| if not range_check: | |
| edge_cases.append({ | |
| "type": "index_out_of_bounds", | |
| "pattern": pattern, | |
| "location": match.span(), | |
| "context": context, | |
| "description": "配列の範囲外アクセスの可能性があります。インデックスの範囲チェックを追加してください。" | |
| }) | |
| # 5. 無限ループの可能性 | |
| loop_patterns = [ | |
| r'while\s*\(\s*true\s*\)', # while(true) | |
| r'while\s*\(\s*1\s*\)', # while(1) | |
| r'for\s*\(\s*;', # 無限for文 | |
| r'while\s*\(\s*[a-zA-Z_]\w*\s*\)' # 変数条件のwhile | |
| ] | |
| for pattern in loop_patterns: | |
| for match in re.finditer(pattern, code): | |
| # 脱出条件があるか確認 | |
| context_start = match.end() | |
| context_end = min(len(code), match.end() + 200) # ループ内を確認 | |
| loop_body = code[context_start:context_end] | |
| # 脱出条件のパターン | |
| break_condition = re.search(r'break|return|exit', loop_body) | |
| if not break_condition: | |
| edge_cases.append({ | |
| "type": "infinite_loop", | |
| "pattern": pattern, | |
| "location": match.span(), | |
| "context": code[max(0, match.start() - 20):match.end() + 20], | |
| "description": "無限ループの可能性があります。脱出条件を追加してください。" | |
| }) | |
| # 6. 物理的に不適切な値(負の質量、負の密度など) | |
| physics_var_patterns = [ | |
| (r'mass\s*=\s*-', "負の質量"), | |
| (r'density\s*=\s*-', "負の密度"), | |
| (r'temperature\s*=\s*-273', "絶対零度以下の温度"), | |
| (r'速度\s*=\s*[0-9.]+e[+]?[0-9]+', "光速を超える可能性のある速度"), | |
| (r'velocity\s*=\s*[0-9.]+e[+]?[0-9]+', "光速を超える可能性のある速度") | |
| ] | |
| for pattern, desc in physics_var_patterns: | |
| for match in re.finditer(pattern, code): | |
| edge_cases.append({ | |
| "type": "invalid_physics_value", | |
| "pattern": pattern, | |
| "location": match.span(), | |
| "context": code[max(0, match.start() - 20):min(len(code), match.end() + 20)], | |
| "description": f"物理的に不適切な値の可能性: {desc}. 値の範囲チェックを追加してください。" | |
| }) | |
| return edge_cases |