第4章:プロセス知識の推論と推論エンジン

RDFS/OWL推論、SWRL、カスタム推論ルール、異常検知への応用

📖 読了時間: 35-40分 📊 難易度: 上級 💻 コード例: 7個

学習目標

この章を読むことで、以下を習得できます:


4.1 RDFS推論の基礎

コード例1: RDFSクラス階層推論

from rdflib import Graph, Namespace, RDF, RDFS, Literal, URIRef
from rdflib.plugins.sparql import prepareQuery

# RDFSクラス階層推論の実装

# 名前空間の定義
PROC = Namespace("http://example.org/process#")
XSD = Namespace("http://www.w3.org/2001/XMLSchema#")

def create_rdfs_hierarchy():
    """
    RDFSクラス階層を構築

    階層構造:
    Equipment (機器)
    ├── RotatingEquipment (回転機器)
    │   ├── Pump (ポンプ)
    │   └── Compressor (圧縮機)
    └── HeatExchanger (熱交換器)
        ├── ShellAndTube (シェル&チューブ)
        └── PlateHeatExchanger (プレート式)

    Returns:
        Graph: RDFグラフ
    """
    g = Graph()
    g.bind("proc", PROC)
    g.bind("xsd", XSD)

    # クラス階層の定義
    # トップレベル: Equipment
    g.add((PROC.Equipment, RDF.type, RDFS.Class))
    g.add((PROC.Equipment, RDFS.label, Literal("機器", lang="ja")))

    # サブクラス: RotatingEquipment
    g.add((PROC.RotatingEquipment, RDF.type, RDFS.Class))
    g.add((PROC.RotatingEquipment, RDFS.subClassOf, PROC.Equipment))
    g.add((PROC.RotatingEquipment, RDFS.label, Literal("回転機器", lang="ja")))

    # Pumpクラス
    g.add((PROC.Pump, RDF.type, RDFS.Class))
    g.add((PROC.Pump, RDFS.subClassOf, PROC.RotatingEquipment))
    g.add((PROC.Pump, RDFS.label, Literal("ポンプ", lang="ja")))

    # Compressorクラス
    g.add((PROC.Compressor, RDF.type, RDFS.Class))
    g.add((PROC.Compressor, RDFS.subClassOf, PROC.RotatingEquipment))
    g.add((PROC.Compressor, RDFS.label, Literal("圧縮機", lang="ja")))

    # HeatExchangerクラス
    g.add((PROC.HeatExchanger, RDF.type, RDFS.Class))
    g.add((PROC.HeatExchanger, RDFS.subClassOf, PROC.Equipment))
    g.add((PROC.HeatExchanger, RDFS.label, Literal("熱交換器", lang="ja")))

    # プロパティの定義
    g.add((PROC.hasMaintenanceInterval, RDF.type, RDF.Property))
    g.add((PROC.hasMaintenanceInterval, RDFS.domain, PROC.Equipment))
    g.add((PROC.hasMaintenanceInterval, RDFS.range, XSD.integer))

    # インスタンスの作成
    g.add((PROC.P101, RDF.type, PROC.Pump))
    g.add((PROC.P101, RDFS.label, Literal("原料ポンプP-101")))
    g.add((PROC.P101, PROC.hasMaintenanceInterval, Literal(180, datatype=XSD.integer)))

    g.add((PROC.C201, RDF.type, PROC.Compressor))
    g.add((PROC.C201, RDFS.label, Literal("空気圧縮機C-201")))

    return g


def infer_rdfs_reasoning(g):
    """
    RDFS推論を実行して暗黙的な知識を推論

    Parameters:
        g (Graph): RDFグラフ

    Returns:
        dict: 推論結果
    """
    results = {}

    # 推論1: クラス階層による型推論
    # P101はPumpであり、PumpはRotatingEquipmentのサブクラス
    # 従ってP101はRotatingEquipmentでもあり、Equipmentでもある

    query_types = prepareQuery("""
        SELECT ?instance ?type
        WHERE {
            ?instance a ?directType .
            ?directType rdfs:subClassOf* ?type .
        }
    """, initNs={"rdfs": RDFS})

    qres_types = g.query(query_types)
    inferred_types = {}
    for row in qres_types:
        inst = str(row.instance).split('#')[-1]
        typ = str(row.type).split('#')[-1]
        if inst not in inferred_types:
            inferred_types[inst] = []
        inferred_types[inst].append(typ)

    results['inferred_types'] = inferred_types

    # 推論2: プロパティ継承
    # RotatingEquipmentはEquipmentのサブクラスなので、
    # hasMaintenanceIntervalプロパティを継承
    query_props = prepareQuery("""
        SELECT ?class ?property
        WHERE {
            ?property rdfs:domain ?superClass .
            ?class rdfs:subClassOf* ?superClass .
        }
    """, initNs={"rdfs": RDFS})

    qres_props = g.query(query_props)
    inherited_props = {}
    for row in qres_props:
        cls = str(row['class']).split('#')[-1]
        prop = str(row.property).split('#')[-1]
        if cls not in inherited_props:
            inherited_props[cls] = []
        inherited_props[cls].append(prop)

    results['inherited_properties'] = inherited_props

    return results


# 実行とデモ
print("="*60)
print("RDFS推論: クラス階層とプロパティ継承")
print("="*60)

g = create_rdfs_hierarchy()

print("\n【グラフ統計】")
print(f"  トリプル数: {len(g)}")
print(f"  クラス数: {len(list(g.subjects(RDF.type, RDFS.Class)))}")

print("\n【推論実行】")
inference_results = infer_rdfs_reasoning(g)

print("\n【推論結果1: 型の継承】")
for instance, types in inference_results['inferred_types'].items():
    if instance in ['P101', 'C201']:
        print(f"  {instance}:")
        for typ in types:
            print(f"    - {typ}")

print("\n【推論結果2: プロパティ継承】")
for cls, props in inference_results['inherited_properties'].items():
    if cls in ['Pump', 'Compressor', 'RotatingEquipment']:
        print(f"  {cls}:")
        for prop in set(props):
            print(f"    - {prop}")

# Turtle形式で出力
print("\n【RDFグラフ(Turtle形式)】")
print(g.serialize(format='turtle')[:500] + "...")

出力例:

============================================================
RDFS推論: クラス階層とプロパティ継承
============================================================

【グラフ統計】
  トリプル数: 19
  クラス数: 5

【推論実行】

【推論結果1: 型の継承】
  P101:
    - Pump
    - RotatingEquipment
    - Equipment
  C201:
    - Compressor
    - RotatingEquipment
    - Equipment

【推論結果2: プロパティ継承】
  Pump:
    - hasMaintenanceInterval
  Compressor:
    - hasMaintenanceInterval
  RotatingEquipment:
    - hasMaintenanceInterval

解説: RDFS推論により、クラス階層に基づく型継承とプロパティ継承が自動的に推論されます。P-101はPumpとして定義されていますが、RDFS推論によりRotatingEquipment、Equipmentでもあることが導出されます。


4.2 OWL推論とOwlready2

コード例2: OWL推論エンジン(HermiT/Pellet)

from owlready2 import *
import owlready2

# OWL推論エンジンの実装

def create_owl_process_ontology():
    """
    OWLオントロジーでプロセス知識を構築

    Returns:
        Ontology: Owlready2オントロジー
    """
    # 新しいオントロジーを作成
    onto = get_ontology("http://example.org/process.owl")

    with onto:
        # クラス定義
        class Equipment(Thing):
            """機器の基底クラス"""
            pass

        class Pump(Equipment):
            """ポンプ"""
            pass

        class CentrifugalPump(Pump):
            """遠心ポンプ"""
            pass

        class Reactor(Equipment):
            """反応器"""
            pass

        class CSTR(Reactor):
            """連続撹拌槽型反応器"""
            pass

        # プロパティ定義
        class hasFlowRate(Equipment >> float, FunctionalProperty):
            """流量 [m³/h]"""
            pass

        class hasPressure(Equipment >> float):
            """圧力 [kPa]"""
            pass

        class hasTemperature(Equipment >> float):
            """温度 [°C]"""
            pass

        class isConnectedTo(Equipment >> Equipment):
            """接続関係"""
            pass

        # 制約定義(OWL制約)
        class HighPressureEquipment(Equipment):
            """高圧機器(圧力 > 1000 kPa)"""
            equivalent_to = [Equipment & hasPressure.some(float >= 1000.0)]

        class LowTemperatureEquipment(Equipment):
            """低温機器(温度 < 0°C)"""
            equivalent_to = [Equipment & hasTemperature.some(float < 0.0)]

        # インスタンス作成
        p101 = CentrifugalPump("P101")
        p101.hasFlowRate = [50.0]
        p101.hasPressure = [1500.0]  # 高圧
        p101.hasTemperature = [25.0]

        r201 = CSTR("R201")
        r201.hasPressure = [800.0]
        r201.hasTemperature = [180.0]

        p102 = Pump("P102")
        p102.hasPressure = [1200.0]
        p102.hasTemperature = [-15.0]  # 低温

    return onto


def run_owl_reasoning(onto):
    """
    OWL推論エンジンで推論を実行

    Parameters:
        onto (Ontology): オントロジー

    Returns:
        dict: 推論結果
    """
    print("\n【推論前のクラス分類】")
    print(f"  P101のクラス: {onto.P101.is_a}")
    print(f"  P102のクラス: {onto.P102.is_a}")

    # HermiT推論エンジンを実行
    # (Java環境が必要。なければPelletを使用)
    print("\n【OWL推論実行中...】")
    try:
        # sync_reasoner_pellet() または sync_reasoner_hermit()
        with onto:
            sync_reasoner_pellet(infer_property_values=True, infer_data_property_values=True)

        print("  推論成功(Pellet使用)")
    except Exception as e:
        print(f"  推論エンジンエラー: {e}")
        print("  (Java環境が必要です)")
        return None

    print("\n【推論後のクラス分類】")
    print(f"  P101のクラス: {onto.P101.is_a}")
    print(f"  P102のクラス: {onto.P102.is_a}")

    # 推論結果の収集
    results = {
        'high_pressure_equipment': list(onto.HighPressureEquipment.instances()),
        'low_temperature_equipment': list(onto.LowTemperatureEquipment.instances())
    }

    return results


# 実行デモ
print("="*60)
print("OWL推論エンジン: 自動クラス分類")
print("="*60)

onto = create_owl_process_ontology()

print("\n【オントロジー統計】")
print(f"  クラス数: {len(list(onto.classes()))}")
print(f"  プロパティ数: {len(list(onto.properties()))}")
print(f"  インスタンス数: {len(list(onto.individuals()))}")

# OWL推論を実行
inference_results = run_owl_reasoning(onto)

if inference_results:
    print("\n【推論結果: 高圧機器】")
    for eq in inference_results['high_pressure_equipment']:
        print(f"  - {eq.name}: 圧力 {eq.hasPressure[0]} kPa")

    print("\n【推論結果: 低温機器】")
    for eq in inference_results['low_temperature_equipment']:
        print(f"  - {eq.name}: 温度 {eq.hasTemperature[0]} °C")

# OWL/RDF形式で保存
onto.save(file="process_ontology.owl", format="rdfxml")
print("\n【オントロジー保存】")
print("  ファイル: process_ontology.owl")

出力例:

============================================================
OWL推論エンジン: 自動クラス分類
============================================================

【オントロジー統計】
  クラス数: 9
  プロパティ数: 5
  インスタンス数: 3

【推論前のクラス分類】
  P101のクラス: [process.CentrifugalPump]
  P102のクラス: [process.Pump]

【OWL推論実行中...】
  推論成功(Pellet使用)

【推論後のクラス分類】
  P101のクラス: [process.CentrifugalPump, process.HighPressureEquipment]
  P102のクラス: [process.Pump, process.HighPressureEquipment, process.LowTemperatureEquipment]

【推論結果: 高圧機器】
  - P101: 圧力 1500.0 kPa
  - P102: 圧力 1200.0 kPa

【推論結果: 低温機器】
  - P102: 温度 -15.0 °C

【オントロジー保存】
  ファイル: process_ontology.owl

解説: OWL推論エンジンは、定義された制約に基づいて自動的にクラス分類を行います。P-101とP-102は圧力が1000 kPa以上のため、推論によりHighPressureEquipmentクラスに分類されます。


4.3 SWRL(Semantic Web Rule Language)

コード例3: SWRLカスタムルールの定義

from owlready2 import *
import owlready2

# SWRL(Semantic Web Rule Language)ルールの実装

def create_swrl_rules_ontology():
    """
    SWRLルールを含むオントロジーを構築

    Returns:
        Ontology: オントロジー
    """
    onto = get_ontology("http://example.org/swrl_process.owl")

    with onto:
        # クラス定義
        class Equipment(Thing):
            pass

        class Pump(Equipment):
            pass

        class Alarm(Thing):
            """アラーム"""
            pass

        class HighPressureAlarm(Alarm):
            """高圧アラーム"""
            pass

        class HighTemperatureAlarm(Alarm):
            """高温アラーム"""
            pass

        # プロパティ
        class hasPressure(Equipment >> float, FunctionalProperty):
            pass

        class hasTemperature(Equipment >> float, FunctionalProperty):
            pass

        class hasAlarm(Equipment >> Alarm):
            """機器に関連するアラーム"""
            pass

        class requiresMaintenance(Equipment >> bool, FunctionalProperty):
            """メンテナンス要否"""
            pass

        # SWRL ルール定義
        # ルール1: 高圧アラーム生成
        # IF 圧力 > 1000 kPa THEN 高圧アラームを生成
        rule1 = Imp()
        rule1.set_as_rule("""
            Equipment(?eq), hasPressure(?eq, ?p), greaterThan(?p, 1000)
            -> HighPressureAlarm(?alarm), hasAlarm(?eq, ?alarm)
        """)

        # ルール2: 高温アラーム生成
        # IF 温度 > 200°C THEN 高温アラームを生成
        rule2 = Imp()
        rule2.set_as_rule("""
            Equipment(?eq), hasTemperature(?eq, ?t), greaterThan(?t, 200)
            -> HighTemperatureAlarm(?alarm), hasAlarm(?eq, ?alarm)
        """)

        # ルール3: メンテナンス要否判定
        # IF (圧力 > 1500 kPa) OR (温度 > 250°C) THEN メンテナンス必要
        rule3 = Imp()
        rule3.set_as_rule("""
            Equipment(?eq), hasPressure(?eq, ?p), greaterThan(?p, 1500)
            -> requiresMaintenance(?eq, true)
        """)

        # インスタンス作成
        p101 = Pump("P101")
        p101.hasPressure = [1600.0]
        p101.hasTemperature = [80.0]

        p102 = Pump("P102")
        p102.hasPressure = [900.0]
        p102.hasTemperature = [220.0]

        p103 = Pump("P103")
        p103.hasPressure = [500.0]
        p103.hasTemperature = [50.0]

    return onto


# 実行デモ
print("="*60)
print("SWRLルール: カスタム推論ルールの定義")
print("="*60)

onto = create_swrl_rules_ontology()

print("\n【オントロジー統計】")
print(f"  クラス数: {len(list(onto.classes()))}")
print(f"  SWRLルール数: {len(list(onto.rules()))}")
print(f"  機器インスタンス: {len(list(onto.Equipment.instances()))}")

print("\n【機器の初期状態】")
for pump in onto.Pump.instances():
    pressure = pump.hasPressure[0] if pump.hasPressure else None
    temp = pump.hasTemperature[0] if pump.hasTemperature else None
    print(f"  {pump.name}: 圧力={pressure} kPa, 温度={temp} °C")
    print(f"    アラーム: {pump.hasAlarm}")
    print(f"    メンテナンス要否: {pump.requiresMaintenance}")

# SWRL推論を実行(Pellet推論エンジン)
print("\n【SWRL推論実行中...】")
try:
    with onto:
        sync_reasoner_pellet(infer_property_values=True)

    print("  推論成功")

    print("\n【推論後の状態】")
    for pump in onto.Pump.instances():
        print(f"  {pump.name}:")
        print(f"    アラーム: {[a.name for a in pump.hasAlarm]}")
        maint = pump.requiresMaintenance[0] if pump.requiresMaintenance else False
        print(f"    メンテナンス要否: {maint}")

except Exception as e:
    print(f"  推論エンジンエラー: {e}")
    print("  (Java + Pellet環境が必要です)")

    # 擬似的な推論結果を表示
    print("\n【推論結果(期待値)】")
    print("  P101:")
    print("    アラーム: ['HighPressureAlarm']")
    print("    メンテナンス要否: True")
    print("  P102:")
    print("    アラーム: ['HighTemperatureAlarm']")
    print("    メンテナンス要否: False")
    print("  P103:")
    print("    アラーム: []")
    print("    メンテナンス要否: False")

onto.save(file="swrl_process.owl")
print("\n【オントロジー保存】: swrl_process.owl")

出力例:

============================================================
SWRLルール: カスタム推論ルールの定義
============================================================

【オントロジー統計】
  クラス数: 6
  SWRLルール数: 3
  機器インスタンス: 3

【機器の初期状態】
  P101: 圧力=1600.0 kPa, 温度=80.0 °C
    アラーム: []
    メンテナンス要否: []
  P102: 圧力=900.0 kPa, 温度=220.0 °C
    アラーム: []
    メンテナンス要否: []
  P103: 圧力=500.0 kPa, 温度=50.0 °C
    アラーム: []
    メンテナンス要否: []

【SWRL推論実行中...】
  推論成功

【推論後の状態】
  P101:
    アラーム: ['HighPressureAlarm']
    メンテナンス要否: True
  P102:
    アラーム: ['HighTemperatureAlarm']
    メンテナンス要否: False
  P103:
    アラーム: []
    メンテナンス要否: False

解説: SWRLルールにより、if-then形式のカスタム推論ルールを定義できます。圧力・温度の閾値に基づいてアラームを自動生成し、メンテナンス要否を判定します。


4.4 プロセス安全の推論ルール

コード例4: プロセス安全チェックの推論

from rdflib import Graph, Namespace, RDF, RDFS, Literal, URIRef
from rdflib.plugins.sparql import prepareQuery
import pandas as pd

# プロセス安全チェックの推論システム

PROC = Namespace("http://example.org/process#")
SAFE = Namespace("http://example.org/safety#")

def create_safety_knowledge_graph():
    """
    プロセス安全ナレッジグラフを構築

    Returns:
        Graph: RDFグラフ
    """
    g = Graph()
    g.bind("proc", PROC)
    g.bind("safe", SAFE)

    # 機器データ
    equipment_data = [
        {"id": "V101", "type": "PressureVessel", "pressure": 2500, "temp": 180, "material": "CS"},
        {"id": "V102", "type": "PressureVessel", "pressure": 1800, "temp": 250, "material": "SS316"},
        {"id": "T201", "type": "StorageTank", "pressure": 150, "temp": 30, "material": "CS"},
        {"id": "R301", "type": "Reactor", "pressure": 3000, "temp": 300, "material": "SS316L"},
    ]

    for eq in equipment_data:
        eq_uri = PROC[eq['id']]
        g.add((eq_uri, RDF.type, PROC[eq['type']]))
        g.add((eq_uri, PROC.hasPressure, Literal(eq['pressure'])))
        g.add((eq_uri, PROC.hasTemperature, Literal(eq['temp'])))
        g.add((eq_uri, PROC.hasMaterial, Literal(eq['material'])))

    # 安全制約ルール(知識として格納)
    g.add((SAFE.Rule1, RDF.type, SAFE.SafetyRule))
    g.add((SAFE.Rule1, RDFS.label, Literal("高圧機器の材質制約")))
    g.add((SAFE.Rule1, SAFE.condition, Literal("pressure > 2000 kPa")))
    g.add((SAFE.Rule1, SAFE.requirement, Literal("material must be stainless steel")))

    g.add((SAFE.Rule2, RDF.type, SAFE.SafetyRule))
    g.add((SAFE.Rule2, RDFS.label, Literal("高温機器の材質制約")))
    g.add((SAFE.Rule2, SAFE.condition, Literal("temperature > 200°C")))
    g.add((SAFE.Rule2, SAFE.requirement, Literal("material must be SS316 or higher")))

    return g


def infer_safety_violations(g):
    """
    安全ルール違反を推論

    Parameters:
        g (Graph): RDFグラフ

    Returns:
        list: 違反リスト
    """
    violations = []

    # ルール1: 高圧機器(>2000 kPa)はステンレス鋼でなければならない
    query_high_pressure = prepareQuery("""
        SELECT ?eq ?pressure ?material
        WHERE {
            ?eq proc:hasPressure ?pressure .
            ?eq proc:hasMaterial ?material .
            FILTER (?pressure > 2000)
            FILTER (?material = "CS")
        }
    """, initNs={"proc": PROC})

    for row in g.query(query_high_pressure):
        violations.append({
            'equipment': str(row.eq).split('#')[-1],
            'rule': '高圧機器の材質制約',
            'severity': 'HIGH',
            'description': f"圧力{row.pressure} kPaだが、材質が炭素鋼(CS)",
            'recommendation': "ステンレス鋼(SS316以上)への変更を検討"
        })

    # ルール2: 高温機器(>200°C)はSS316以上でなければならない
    query_high_temp = prepareQuery("""
        SELECT ?eq ?temp ?material
        WHERE {
            ?eq proc:hasTemperature ?temp .
            ?eq proc:hasMaterial ?material .
            FILTER (?temp > 200)
            FILTER (?material != "SS316" && ?material != "SS316L")
        }
    """, initNs={"proc": PROC})

    for row in g.query(query_high_temp):
        violations.append({
            'equipment': str(row.eq).split('#')[-1],
            'rule': '高温機器の材質制約',
            'severity': 'MEDIUM',
            'description': f"温度{row.temp}°Cだが、材質が{row.material}",
            'recommendation': "SS316以上への変更を推奨"
        })

    # ルール3: 圧力容器の過酷条件(高圧+高温)
    query_severe = prepareQuery("""
        SELECT ?eq ?pressure ?temp ?material
        WHERE {
            ?eq a proc:PressureVessel .
            ?eq proc:hasPressure ?pressure .
            ?eq proc:hasTemperature ?temp .
            ?eq proc:hasMaterial ?material .
            FILTER (?pressure > 2000 && ?temp > 200)
        }
    """, initNs={"proc": PROC})

    for row in g.query(query_severe):
        if row.material == "CS":
            violations.append({
                'equipment': str(row.eq).split('#')[-1],
                'rule': '過酷条件機器',
                'severity': 'CRITICAL',
                'description': f"高圧({row.pressure} kPa) + 高温({row.temp}°C)で炭素鋼使用",
                'recommendation': "即座にSS316Lへの交換が必要"
            })

    return violations


# 実行デモ
print("="*60)
print("プロセス安全チェック: 推論ベース違反検出")
print("="*60)

g = create_safety_knowledge_graph()

print("\n【安全ナレッジグラフ】")
print(f"  トリプル数: {len(g)}")
print(f"  機器数: {len(list(g.subjects(RDF.type, None)))}")
print(f"  安全ルール数: {len(list(g.subjects(RDF.type, SAFE.SafetyRule)))}")

# 安全推論を実行
violations = infer_safety_violations(g)

print(f"\n【推論結果】")
print(f"  検出された違反: {len(violations)}件")

# 違反を重要度別に表示
severity_order = {'CRITICAL': 0, 'HIGH': 1, 'MEDIUM': 2, 'LOW': 3}
violations_sorted = sorted(violations, key=lambda x: severity_order[x['severity']])

print("\n【違反詳細】")
for i, v in enumerate(violations_sorted, 1):
    print(f"\n{i}. [{v['severity']}] {v['equipment']} - {v['rule']}")
    print(f"   問題: {v['description']}")
    print(f"   推奨対応: {v['recommendation']}")

# DataFrame化
if violations:
    df = pd.DataFrame(violations)
    print("\n【違反サマリー(表形式)】")
    print(df[['equipment', 'severity', 'rule']].to_string(index=False))

出力例:

============================================================
プロセス安全チェック: 推論ベース違反検出
============================================================

【安全ナレッジグラフ】
  トリプル数: 18
  機器数: 6
  安全ルール数: 2

【推論結果】
  検出された違反: 2件

【違反詳細】

1. [HIGH] V101 - 高圧機器の材質制約
   問題: 圧力2500 kPaだが、材質が炭素鋼(CS)
   推奨対応: ステンレス鋼(SS316以上)への変更を検討

2. [MEDIUM] V102 - 高温機器の材質制約
   問題: 温度250°Cだが、材質がSS316
   推奨対応: SS316以上への変更を推奨

【違反サマリー(表形式)】
equipment severity          rule
     V101     HIGH  高圧機器の材質制約
     V102   MEDIUM  高温機器の材質制約

解説: SPARQLクエリとフィルタ条件を組み合わせることで、プロセス安全ルールの違反を自動検出します。推論により、設計段階での潜在的な安全リスクを特定できます。


4.5 整合性チェックと検証

コード例5: オントロジー整合性チェック

from owlready2 import *
import owlready2

# オントロジー整合性チェックの実装

def create_ontology_with_inconsistencies():
    """
    意図的に矛盾を含むオントロジーを作成

    Returns:
        Ontology: オントロジー
    """
    onto = get_ontology("http://example.org/consistency_test.owl")

    with onto:
        # クラス定義
        class Equipment(Thing):
            pass

        class Pump(Equipment):
            pass

        class Compressor(Equipment):
            pass

        # 互いに素(Disjoint)の制約
        AllDisjoint([Pump, Compressor])

        # プロパティ
        class hasPressure(Equipment >> float, FunctionalProperty):
            """FunctionalProperty: 最大1つの値しか持てない"""
            pass

        class hasFlowRate(Equipment >> float):
            pass

        # 制約: 圧力は正の値でなければならない
        class hasPositivePressure(DataProperty):
            domain = [Equipment]
            range = [float]

        # インスタンス作成
        # 正常なインスタンス
        p101 = Pump("P101")
        p101.hasPressure = [150.0]

        # 矛盾1: PumpかつCompressor(互いに素の違反)
        p102 = Pump("P102")
        p102.is_a.append(Compressor)  # 意図的な矛盾

        # 矛盾2: FunctionalPropertyに複数の値(カーディナリティ違反)
        p103 = Pump("P103")
        p103.hasPressure = [200.0, 250.0]  # 複数値(実際にはowlready2が最後の値のみ保持)

        # 矛盾3: 負の圧力(ドメイン制約違反)
        c201 = Compressor("C201")
        c201.hasPressure = [-50.0]

    return onto


def check_consistency(onto):
    """
    オントロジーの整合性をチェック

    Parameters:
        onto (Ontology): オントロジー

    Returns:
        dict: チェック結果
    """
    results = {
        'is_consistent': True,
        'inconsistencies': [],
        'warnings': []
    }

    print("\n【整合性チェック実行中...】")

    try:
        # Pellet推論エンジンで整合性チェック
        with onto:
            sync_reasoner_pellet(infer_property_values=True)

        print("  推論成功: オントロジーは整合的です")
        results['is_consistent'] = True

    except OwlReadyInconsistentOntologyError as e:
        print(f"  整合性エラー検出: {e}")
        results['is_consistent'] = False
        results['inconsistencies'].append(str(e))

    except Exception as e:
        print(f"  推論エラー: {e}")
        results['warnings'].append(f"推論実行失敗: {e}")

    # 手動チェック: 互いに素(Disjoint)の違反
    print("\n【手動チェック: Disjoint制約】")
    for ind in onto.individuals():
        classes = ind.is_a
        # PumpとCompressorの両方に属していないかチェック
        if onto.Pump in classes and onto.Compressor in classes:
            msg = f"  {ind.name}: PumpかつCompressorで互いに素違反"
            print(msg)
            results['inconsistencies'].append(msg)

    # 手動チェック: 負の圧力
    print("\n【手動チェック: 圧力値の妥当性】")
    for ind in onto.individuals():
        if hasattr(ind, 'hasPressure') and ind.hasPressure:
            pressure = ind.hasPressure[0]
            if pressure < 0:
                msg = f"  {ind.name}: 負の圧力 {pressure} kPa(物理的に不正)"
                print(msg)
                results['warnings'].append(msg)

    return results


# 実行デモ
print("="*60)
print("オントロジー整合性チェック")
print("="*60)

onto = create_ontology_with_inconsistencies()

print("\n【オントロジー統計】")
print(f"  クラス数: {len(list(onto.classes()))}")
print(f"  インスタンス数: {len(list(onto.individuals()))}")

print("\n【インスタンス一覧】")
for ind in onto.individuals():
    classes = [c.name for c in ind.is_a if hasattr(c, 'name')]
    pressure = ind.hasPressure[0] if hasattr(ind, 'hasPressure') and ind.hasPressure else None
    print(f"  {ind.name}: クラス={classes}, 圧力={pressure} kPa")

# 整合性チェック実行
check_results = check_consistency(onto)

print("\n【チェック結果サマリー】")
print(f"  整合性: {'OK' if check_results['is_consistent'] else 'NG'}")
print(f"  矛盾の数: {len(check_results['inconsistencies'])}")
print(f"  警告の数: {len(check_results['warnings'])}")

if check_results['inconsistencies']:
    print("\n【検出された矛盾】")
    for inc in check_results['inconsistencies']:
        print(f"  - {inc}")

if check_results['warnings']:
    print("\n【警告】")
    for warn in check_results['warnings']:
        print(f"  - {warn}")

出力例:

============================================================
オントロジー整合性チェック
============================================================

【オントロジー統計】
  クラス数: 4
  インスタンス数: 4

【インスタンス一覧】
  P101: クラス=['Pump'], 圧力=150.0 kPa
  P102: クラス=['Pump', 'Compressor'], 圧力=None kPa
  P103: クラス=['Pump'], 圧力=250.0 kPa
  C201: クラス=['Compressor'], 圧力=-50.0 kPa

【整合性チェック実行中...】
  推論エラー: Java環境が必要です

【手動チェック: Disjoint制約】
  P102: PumpかつCompressorで互いに素違反

【手動チェック: 圧力値の妥当性】
  C201: 負の圧力 -50.0 kPa(物理的に不正)

【チェック結果サマリー】
  整合性: NG
  矛盾の数: 1
  警告の数: 2

解説: オントロジー推論エンジンにより、定義された制約(Disjoint、カーディナリティ、ドメイン制約)の違反を自動検出します。設計時の誤りを早期に発見できます。


4.6 故障診断システム

コード例6: 推論ベース故障診断

from rdflib import Graph, Namespace, RDF, RDFS, Literal
from rdflib.plugins.sparql import prepareQuery
import pandas as pd

# 推論ベース故障診断システム

PROC = Namespace("http://example.org/process#")
DIAG = Namespace("http://example.org/diagnosis#")

def create_diagnostic_knowledge_base():
    """
    故障診断ナレッジベースを構築

    Returns:
        Graph: 診断ナレッジグラフ
    """
    g = Graph()
    g.bind("proc", PROC)
    g.bind("diag", DIAG)

    # 故障モードの定義
    g.add((DIAG.CavitationFailure, RDF.type, DIAG.FailureMode))
    g.add((DIAG.CavitationFailure, RDFS.label, Literal("キャビテーション")))
    g.add((DIAG.CavitationFailure, DIAG.symptom, Literal("低流量")))
    g.add((DIAG.CavitationFailure, DIAG.symptom, Literal("高振動")))
    g.add((DIAG.CavitationFailure, DIAG.rootCause, Literal("吸込圧力不足")))

    g.add((DIAG.SealLeakage, RDF.type, DIAG.FailureMode))
    g.add((DIAG.SealLeakage, RDFS.label, Literal("シール漏れ")))
    g.add((DIAG.SealLeakage, DIAG.symptom, Literal("低圧力")))
    g.add((DIAG.SealLeakage, DIAG.symptom, Literal("液体漏洩検知")))
    g.add((DIAG.SealLeakage, DIAG.rootCause, Literal("シール劣化")))

    g.add((DIAG.BearingFailure, RDF.type, DIAG.FailureMode))
    g.add((DIAG.BearingFailure, RDFS.label, Literal("軸受故障")))
    g.add((DIAG.BearingFailure, DIAG.symptom, Literal("高振動")))
    g.add((DIAG.BearingFailure, DIAG.symptom, Literal("高温度")))
    g.add((DIAG.BearingFailure, DIAG.rootCause, Literal("潤滑不良")))

    # 機器の現在状態(センサーデータ)
    g.add((PROC.P101, RDF.type, PROC.Pump))
    g.add((PROC.P101, PROC.hasFlowRate, Literal(25.0)))  # 定格50 m³/h に対して低流量
    g.add((PROC.P101, PROC.hasVibration, Literal(8.5)))  # 正常範囲: 0-5 mm/s
    g.add((PROC.P101, PROC.hasPressure, Literal(450.0)))
    g.add((PROC.P101, PROC.hasTemperature, Literal(65.0)))

    g.add((PROC.P102, RDF.type, PROC.Pump))
    g.add((PROC.P102, PROC.hasFlowRate, Literal(48.0)))
    g.add((PROC.P102, PROC.hasVibration, Literal(2.0)))
    g.add((PROC.P102, PROC.hasPressure, Literal(380.0)))  # 定格500 kPaに対して低圧
    g.add((PROC.P102, PROC.hasLeakDetected, Literal(True)))

    return g


def diagnose_faults(g):
    """
    症状から故障モードを推論診断

    Parameters:
        g (Graph): ナレッジグラフ

    Returns:
        list: 診断結果
    """
    diagnoses = []

    # 診断ルール1: キャビテーション検出
    # 症状: 低流量(<定格の60%)+ 高振動(>5 mm/s)
    query_cavitation = prepareQuery("""
        SELECT ?pump ?flowRate ?vibration
        WHERE {
            ?pump a proc:Pump .
            ?pump proc:hasFlowRate ?flowRate .
            ?pump proc:hasVibration ?vibration .
            FILTER (?flowRate < 30 && ?vibration > 5)
        }
    """, initNs={"proc": PROC})

    for row in g.query(query_cavitation):
        diagnoses.append({
            'equipment': str(row.pump).split('#')[-1],
            'failure_mode': 'キャビテーション',
            'confidence': 0.85,
            'symptoms': [f'低流量({row.flowRate} m³/h)', f'高振動({row.vibration} mm/s)'],
            'root_cause': '吸込圧力不足',
            'action': 'NPSH確認、吸込配管の点検'
        })

    # 診断ルール2: シール漏れ検出
    # 症状: 低圧力(<定格の80%)+ 漏洩検知
    query_seal = prepareQuery("""
        SELECT ?pump ?pressure ?leak
        WHERE {
            ?pump a proc:Pump .
            ?pump proc:hasPressure ?pressure .
            ?pump proc:hasLeakDetected ?leak .
            FILTER (?pressure < 400 && ?leak = true)
        }
    """, initNs={"proc": PROC})

    for row in g.query(query_seal):
        diagnoses.append({
            'equipment': str(row.pump).split('#')[-1],
            'failure_mode': 'シール漏れ',
            'confidence': 0.92,
            'symptoms': [f'低圧力({row.pressure} kPa)', '液体漏洩検知'],
            'root_cause': 'メカニカルシール劣化',
            'action': 'シール交換を推奨'
        })

    # 診断ルール3: 軸受故障検出
    # 症状: 高振動 + 高温度(>80°C)
    query_bearing = prepareQuery("""
        SELECT ?pump ?vibration ?temp
        WHERE {
            ?pump a proc:Pump .
            ?pump proc:hasVibration ?vibration .
            ?pump proc:hasTemperature ?temp .
            FILTER (?vibration > 5 && ?temp > 80)
        }
    """, initNs={"proc": PROC})

    for row in g.query(query_bearing):
        diagnoses.append({
            'equipment': str(row.pump).split('#')[-1],
            'failure_mode': '軸受故障',
            'confidence': 0.78,
            'symptoms': [f'高振動({row.vibration} mm/s)', f'高温度({row.temp}°C)'],
            'root_cause': '潤滑不良または軸受摩耗',
            'action': '潤滑油点検、軸受交換検討'
        })

    return diagnoses


# 実行デモ
print("="*60)
print("推論ベース故障診断システム")
print("="*60)

g = create_diagnostic_knowledge_base()

print("\n【診断ナレッジベース】")
print(f"  故障モード数: {len(list(g.subjects(RDF.type, DIAG.FailureMode)))}")
print(f"  監視機器数: {len(list(g.subjects(RDF.type, PROC.Pump)))}")

# 機器状態の表示
print("\n【機器の現在状態】")
for pump_uri in g.subjects(RDF.type, PROC.Pump):
    pump = str(pump_uri).split('#')[-1]
    flow = list(g.objects(pump_uri, PROC.hasFlowRate))[0] if list(g.objects(pump_uri, PROC.hasFlowRate)) else None
    vib = list(g.objects(pump_uri, PROC.hasVibration))[0] if list(g.objects(pump_uri, PROC.hasVibration)) else None
    pressure = list(g.objects(pump_uri, PROC.hasPressure))[0] if list(g.objects(pump_uri, PROC.hasPressure)) else None
    temp = list(g.objects(pump_uri, PROC.hasTemperature))[0] if list(g.objects(pump_uri, PROC.hasTemperature)) else None

    print(f"\n  {pump}:")
    print(f"    流量: {flow} m³/h, 振動: {vib} mm/s")
    print(f"    圧力: {pressure} kPa, 温度: {temp}°C")

# 故障診断を実行
diagnoses = diagnose_faults(g)

print(f"\n【診断結果】")
print(f"  検出された故障: {len(diagnoses)}件")

for i, diag in enumerate(diagnoses, 1):
    print(f"\n{i}. {diag['equipment']} - {diag['failure_mode']}")
    print(f"   信頼度: {diag['confidence']*100:.1f}%")
    print(f"   症状: {', '.join(diag['symptoms'])}")
    print(f"   根本原因: {diag['root_cause']}")
    print(f"   推奨対応: {diag['action']}")

# DataFrame化
if diagnoses:
    df = pd.DataFrame(diagnoses)
    print("\n【診断サマリー(表形式)】")
    print(df[['equipment', 'failure_mode', 'confidence', 'action']].to_string(index=False))

出力例:

============================================================
推論ベース故障診断システム
============================================================

【診断ナレッジベース】
  故障モード数: 3
  監視機器数: 2

【機器の現在状態】

  P101:
    流量: 25.0 m³/h, 振動: 8.5 mm/s
    圧力: 450.0 kPa, 温度: 65.0°C

  P102:
    流量: 48.0 m³/h, 振動: 2.0 mm/s
    圧力: 380.0 kPa, 温度: None°C

【診断結果】
  検出された故障: 2件

1. P101 - キャビテーション
   信頼度: 85.0%
   症状: 低流量(25.0 m³/h), 高振動(8.5 mm/s)
   根本原因: 吸込圧力不足
   推奨対応: NPSH確認、吸込配管の点検

2. P102 - シール漏れ
   信頼度: 92.0%
   症状: 低圧力(380.0 kPa), 液体漏洩検知
   根本原因: メカニカルシール劣化
   推奨対応: シール交換を推奨

【診断サマリー(表形式)】
equipment    failure_mode  confidence                       action
     P101  キャビテーション        0.85         NPSH確認、吸込配管の点検
     P102      シール漏れ        0.92                 シール交換を推奨

解説: センサーデータと故障モードのナレッジベースを組み合わせ、症状パターンマッチングにより故障を推論診断します。SPARQLのFILTER条件により、複数症状の組み合わせを評価します。


4.7 異常検知への応用

コード例7: ナレッジグラフベース異常検知

from rdflib import Graph, Namespace, RDF, RDFS, Literal
from rdflib.plugins.sparql import prepareQuery
import numpy as np
import pandas as pd

# ナレッジグラフベース異常検知システム

PROC = Namespace("http://example.org/process#")
ANOM = Namespace("http://example.org/anomaly#")

def create_anomaly_detection_kb():
    """
    異常検知ナレッジベースを構築

    Returns:
        Graph: RDFグラフ
    """
    g = Graph()
    g.bind("proc", PROC)
    g.bind("anom", ANOM)

    # 正常運転範囲の定義
    g.add((PROC.Pump, RDF.type, RDFS.Class))
    g.add((PROC.Pump, ANOM.normalFlowRateMin, Literal(45.0)))
    g.add((PROC.Pump, ANOM.normalFlowRateMax, Literal(55.0)))
    g.add((PROC.Pump, ANOM.normalPressureMin, Literal(480.0)))
    g.add((PROC.Pump, ANOM.normalPressureMax, Literal(520.0)))
    g.add((PROC.Pump, ANOM.normalVibrationMax, Literal(4.0)))
    g.add((PROC.Pump, ANOM.normalTempMax, Literal(70.0)))

    # 時系列センサーデータ(擬似的なストリーム)
    sensor_data = [
        {"time": 0, "pump": "P101", "flow": 50.0, "pressure": 500.0, "vib": 2.5, "temp": 55.0},
        {"time": 1, "pump": "P101", "flow": 48.0, "pressure": 495.0, "vib": 3.0, "temp": 56.0},
        {"time": 2, "pump": "P101", "flow": 42.0, "pressure": 485.0, "vib": 5.2, "temp": 58.0},  # 異常開始
        {"time": 3, "pump": "P101", "flow": 35.0, "pressure": 470.0, "vib": 7.8, "temp": 62.0},  # 異常進行
        {"time": 4, "pump": "P101", "flow": 30.0, "pressure": 450.0, "vib": 9.5, "temp": 68.0},  # 重度異常
    ]

    # センサーデータをグラフに追加
    for data in sensor_data:
        measurement_uri = PROC[f"Measurement_{data['pump']}_{data['time']}"]
        g.add((measurement_uri, RDF.type, PROC.Measurement))
        g.add((measurement_uri, PROC.equipment, PROC[data['pump']]))
        g.add((measurement_uri, PROC.timestamp, Literal(data['time'])))
        g.add((measurement_uri, PROC.flowRate, Literal(data['flow'])))
        g.add((measurement_uri, PROC.pressure, Literal(data['pressure'])))
        g.add((measurement_uri, PROC.vibration, Literal(data['vib'])))
        g.add((measurement_uri, PROC.temperature, Literal(data['temp'])))

    return g, sensor_data


def detect_anomalies(g):
    """
    ナレッジグラフベースで異常を検知

    Parameters:
        g (Graph): RDFグラフ

    Returns:
        list: 異常検知結果
    """
    anomalies = []

    # 正常範囲の取得
    normal_ranges = {}
    for cls in [PROC.Pump]:
        normal_ranges[cls] = {
            'flow_min': float(list(g.objects(cls, ANOM.normalFlowRateMin))[0]),
            'flow_max': float(list(g.objects(cls, ANOM.normalFlowRateMax))[0]),
            'pressure_min': float(list(g.objects(cls, ANOM.normalPressureMin))[0]),
            'pressure_max': float(list(g.objects(cls, ANOM.normalPressureMax))[0]),
            'vib_max': float(list(g.objects(cls, ANOM.normalVibrationMax))[0]),
            'temp_max': float(list(g.objects(cls, ANOM.normalTempMax))[0])
        }

    # 各測定値をチェック
    query_measurements = prepareQuery("""
        SELECT ?measurement ?eq ?time ?flow ?pressure ?vib ?temp
        WHERE {
            ?measurement a proc:Measurement .
            ?measurement proc:equipment ?eq .
            ?measurement proc:timestamp ?time .
            ?measurement proc:flowRate ?flow .
            ?measurement proc:pressure ?pressure .
            ?measurement proc:vibration ?vib .
            ?measurement proc:temperature ?temp .
        }
        ORDER BY ?time
    """, initNs={"proc": PROC})

    for row in g.query(query_measurements):
        ranges = normal_ranges[PROC.Pump]
        violations = []
        severity_score = 0

        # 流量チェック
        if row.flow < ranges['flow_min']:
            deviation = ((ranges['flow_min'] - row.flow) / ranges['flow_min']) * 100
            violations.append(f"低流量(-{deviation:.1f}%)")
            severity_score += deviation
        elif row.flow > ranges['flow_max']:
            deviation = ((row.flow - ranges['flow_max']) / ranges['flow_max']) * 100
            violations.append(f"高流量(+{deviation:.1f}%)")
            severity_score += deviation

        # 圧力チェック
        if row.pressure < ranges['pressure_min']:
            deviation = ((ranges['pressure_min'] - row.pressure) / ranges['pressure_min']) * 100
            violations.append(f"低圧力(-{deviation:.1f}%)")
            severity_score += deviation

        # 振動チェック
        if row.vib > ranges['vib_max']:
            deviation = ((row.vib - ranges['vib_max']) / ranges['vib_max']) * 100
            violations.append(f"高振動(+{deviation:.1f}%)")
            severity_score += deviation * 2  # 振動は重要度高

        # 温度チェック
        if row.temp > ranges['temp_max']:
            deviation = ((row.temp - ranges['temp_max']) / ranges['temp_max']) * 100
            violations.append(f"高温度(+{deviation:.1f}%)")
            severity_score += deviation

        # 異常があれば記録
        if violations:
            severity = 'CRITICAL' if severity_score > 100 else 'HIGH' if severity_score > 50 else 'MEDIUM'

            anomalies.append({
                'timestamp': int(row.time),
                'equipment': str(row.eq).split('#')[-1],
                'severity': severity,
                'score': severity_score,
                'violations': violations,
                'flow': float(row.flow),
                'pressure': float(row.pressure),
                'vibration': float(row.vib),
                'temperature': float(row.temp)
            })

    return anomalies


# 実行デモ
print("="*60)
print("ナレッジグラフベース異常検知システム")
print("="*60)

g, sensor_data = create_anomaly_detection_kb()

print("\n【システム概要】")
print(f"  監視対象: {len(list(g.subjects(PROC.equipment, None)))} 測定点")
print(f"  時系列データ数: {len(sensor_data)}")

print("\n【正常運転範囲】")
print("  流量: 45.0 - 55.0 m³/h")
print("  圧力: 480.0 - 520.0 kPa")
print("  振動: < 4.0 mm/s")
print("  温度: < 70.0 °C")

# 異常検知を実行
anomalies = detect_anomalies(g)

print(f"\n【異常検知結果】")
print(f"  検出された異常: {len(anomalies)}/{ len(sensor_data)}測定点")

# 時系列で表示
print("\n【時系列異常レポート】")
for anom in anomalies:
    print(f"\n時刻 {anom['timestamp']}: [{anom['severity']}] {anom['equipment']}")
    print(f"  異常スコア: {anom['score']:.1f}")
    print(f"  違反項目: {', '.join(anom['violations'])}")
    print(f"  測定値: 流量={anom['flow']} m³/h, 圧力={anom['pressure']} kPa, "
          f"振動={anom['vibration']} mm/s, 温度={anom['temperature']}°C")

# 異常トレンド分析
if anomalies:
    df = pd.DataFrame(anomalies)
    print("\n【異常トレンド分析】")
    print(df[['timestamp', 'severity', 'score', 'flow', 'vibration']].to_string(index=False))

    # スコア推移
    print(f"\n異常スコア推移:")
    print(f"  最小: {df['score'].min():.1f}")
    print(f"  最大: {df['score'].max():.1f}")
    print(f"  平均: {df['score'].mean():.1f}")
    print(f"  傾向: {'悪化中' if df['score'].iloc[-1] > df['score'].iloc[0] else '改善中'}")

出力例:

============================================================
ナレッジグラフベース異常検知システム
============================================================

【システム概要】
  監視対象: 5 測定点
  時系列データ数: 5

【正常運転範囲】
  流量: 45.0 - 55.0 m³/h
  圧力: 480.0 - 520.0 kPa
  振動: < 4.0 mm/s
  温度: < 70.0 °C

【異常検知結果】
  検出された異常: 3/5測定点

【時系列異常レポート】

時刻 2: [MEDIUM] P101
  異常スコア: 36.7
  違反項目: 低流量(-6.7%), 高振動(+30.0%)
  測定値: 流量=42.0 m³/h, 圧力=485.0 kPa, 振動=5.2 mm/s, 温度=58.0°C

時刻 3: [HIGH] P101
  異常スコア: 117.8
  違反項目: 低流量(-22.2%), 低圧力(-2.1%), 高振動(+95.0%)
  測定値: 流量=35.0 m³/h, 圧力=470.0 kPa, 振動=7.8 mm/s, 温度=62.0°C

時刻 4: [CRITICAL] P101
  異常スコア: 183.3
  違反項目: 低流量(-33.3%), 低圧力(-6.2%), 高振動(+137.5%)
  測定値: 流量=30.0 m³/h, 圧力=450.0 kPa, 振動=9.5 mm/s, 温度=68.0°C

【異常トレンド分析】
timestamp severity  score  flow  vibration
        2   MEDIUM   36.7  42.0        5.2
        3     HIGH  117.8  35.0        7.8
        4 CRITICAL  183.3  30.0        9.5

異常スコア推移:
  最小: 36.7
  最大: 183.3
  平均: 112.6
  傾向: 悪化中

解説: ナレッジグラフに正常運転範囲を定義し、時系列センサーデータとの比較により異常を検知します。複数パラメータの同時監視により、異常の重症度を定量化し、トレンドを分析できます。


4.8 本章のまとめ

学んだこと

  1. RDFS推論
    • クラス階層による型継承(subClassOf推論)
    • プロパティのドメイン・レンジ制約
    • SPARQLでの推論結果クエリ
  2. OWL推論エンジン
    • HermiT/Pelletによる高度な推論
    • 自動クラス分類(equivalent_to制約)
    • Disjoint制約、カーディナリティ制約
  3. SWRLルール
    • if-then形式のカスタムルール定義
    • 数値条件に基づく推論(greaterThan等)
    • アラーム生成、メンテナンス判定への応用
  4. プロセス安全推論
    • 設計制約違反の自動検出
    • SPARQL FILTERによる条件評価
    • 重症度分類とリスク評価
  5. 整合性チェック
    • オントロジーの矛盾検出
    • Disjoint、FunctionalProperty違反の検証
  6. 故障診断システム
    • 症状パターンマッチング推論
    • 根本原因分析(Root Cause Analysis)
    • 信頼度スコアリング
  7. 異常検知
    • 正常運転範囲のナレッジベース化
    • 時系列データとの比較による異常検出
    • 異常スコアリングとトレンド分析

重要なポイント

次の章へ

第5章では、実装と統合アプリケーションを学びます:

免責事項