Skip to content

Let's build a fuzzy automaton

If you haven’t already, we recommend starting with the Fuzzy Fever Guide. It introduces the basics of fuzzy logic using a simple clinical example, perfect for getting up to speed. Once you’re familiar with fuzzy sets and truth values, come back here to explore a more advanced use case: a fuzzy-state automaton for clinical monitoring.

What is an automaton?

An automaton (plural: automata) is a simple model used to represent how a system moves between different states based on input or conditions. Each state represents a specific situation, and transitions define how the system moves from one state to another. You can think of them as rules or triggers that move you from one state to the next. These models are often drawn as diagrams, with circles (states) and arrows (transitions), making them easy to understand visually. As a preview, here is the visual representation of what we are going to build: DFA.

This depicts a deterministic automata, that will additionally be fuzzy due to fuzzy state definitions and transitions.

ARDS severity check

Similar to how we modeled fever using a fuzzy set, we can apply the same approach to ARDS (Acute Respiratory Distress Syndrome), a serious lung condition where early recognition and proper classification are key to improving outcomes. In this MLM we define three fuzzy states: mild, moderate, and severe ARDS.

We’ll use two clinical parameters as input:

  • PaO₂ (arterial oxygen pressure)
  • FiO₂ (fraction of inspired oxygen)

The ratio of PaO₂ to FiO₂ determines how severe the condition is:

arden-syntax
knowledge:
    type: data_driven;;
    data: 
        (PaO2, FiO2) := Argument;
        // Fuzzy set definitions
        ARDS_severe := fuzzy set (100, truth value 1), (110, truth value 0);
        ARDS_moderate := fuzzy set (100, truth value 0), (110, truth value 1), (190, truth value 1), (200, truth value 0);
        ARDS_mild := fuzzy set (190, truth value 0), (200, truth value 1), (300, truth value 1), (310, truth value 0);
    ;;
    priority: 50;;
    evoke: ;;
    logic:
        if (PaO2/ FiO2) is in ARDS_severe then
            severe := "Patient suffers from severe ARDS.";
        endif aggregate;
        if (PaO2/ FiO2) is in ARDS_moderate then
            moderate := "Patient suffers from moderate ARDS.";
        endif aggregate;
        if (PaO2/ FiO2) is in ARDS_mild then
            mild := "Patient suffers from mild ARDS.";
        endif aggregate;

        conclude true;;
    action: return severe, moderate, mild;;
    urgency: 50;;

States & Transitions

Let's start simple and first encode what the following automata

DFA.

To properly use the first thing we need is to define the two circled states: normal and hypoxic. Hypoxic means, a state of the body so to speak.

arden-syntax
data:
    state_normal := "Patient has normal oxygen levels";
    state_hypoxic := "Patient is hypoxic";

Now we also need to define A transition is the prevalence f a condition,

arden-syntax
data:
    def_hypoxemia := fuzzy set (0.87, truth value 0), (0.9, truth value 1), (0.93, truth value 1), (0.97, truth value 0);
    hypoxemia := SaO2 is in def_hypoxemia;

This time, we’re working with a fuzzy set that has both an increasing and a decreasing slope. First, we define how the membership gradually increases toward 1 and then how it tapers off back to 0. This creates a peak in the middle, where the membership is highest.

Implementation

Now that we’ve defined our fuzzy set, let’s plug in some values and simulate a simple fuzzy automaton. Ours will consist of just:

  • Two states: start and hypoxic
  • One transition: To move from start to hypoxic, two conditions must be met:
  1. The system must currently be in the start state
  2. The input condition (e.g., Hypoxemia) must be true to some degree

In classical logic, we’d simply use an AND operator. But in fuzzy logic, there are multiple ways to define AND. Here, we use Zadeh semantics, where:

x AND Y = min(x,y).

This means the degree to which both conditions are true is determined by the lower of the two values. Let's run our simple scenario: We start by assigning a truth value of 1 to the Start state (fully active). We then provide an input value of 0.2 for Hypoxemia and the output state then is Hypoxic to a degree of min(1, 0.2)= 0.2- reflecting that the condition is only partially met.

What we just described in words can also be expressed directly in Arden Syntax:

arden-syntax
logic:
    // start state has no incoming transitions 
    state_start := 0; 
    let applicability of state_start be 1;      // initialization, technically not needed as 1 is the default value 

    hypoxemia := 0;
    let applicability of hypoxemia be 0.2;

    // incoming "Hypoxemia" transition from "Start" state
    state_hypoxic := (applicability of state_start) and (applicability of hypoxemia);
    
    // now, what should the degree of applicability be in the state we transitioned from?
    // 0 in this case because there are no other incoming transitions and we just moved away from it
    state_start := 0
    
    conclude true;;
    action: return state_start, hypoxemia, state_hypoxic;;

Equivalenty to state_hypoxic := (applicability of state_start) and (applicability of hypoxemia) we can write: let applicability of state_hypoxic be (state_start as truth value and Hypoxemia as truth value);

The result? A new truth degree for state_hypoxic and it's 0.2.

Full ARDS Monitoring Automaton

Now that you've seen how to build a simple fuzzy automaton with just two states, let’s take it a few steps further.

For such an automaton to be useful in clinical monitoring we need multiple states, more transitions, and more complex rules that respond to a variety of fuzzy inputs. You’ll find an example below that uses multiple states and conditions to model a more realistic patient monitoring scenario, along with some helpful comments.

arden-syntax
maintenance:
    title:          ARDS_DFA;;
    mlmname:        ARDS_DFA;;
    arden:          version 3;;
    version:        1.0;;
    institution:    Medexter Healthcare;;
    author:         Medexter;;
    specialist:     Medexter;;
    date:           2025-04-16;;
    validation:     testing;;
library:
    purpose: Implements a deterministic, finite state automata (DFA) for monitoring the blood oxygenation for patients with acute respiratory distress syndrome (ARDS);;
    explanation: states: normal (init), hypoxic, responsive and non-responsive to high FiO2. transitions: adequate oxygenation, hypoxemia, high Fi02, low Fi02, improving oxygenation;;
    keywords: ;;
    citations: ;;
    links: ;;
knowledge:
    type: data_driven;;
    data: 
        // patient data
        last_Sao2 := 0.7;
        SaO2 := 0.92;
        FiO2 := 0.6;

        // Fuzzy set definitions
        def_adeq_oxy := fuzzy set (0.93, truth value 0), (0.97, truth value 1);
        def_hypoxemia := fuzzy set (0.87, truth value 0), (0.9, truth value 1), (0.93, truth value 1), (0.97, truth value 0);
        def_high_FiO2 := fuzzy set (0.6, truth value 0), (0.61, truth value 1);
        def_low_FiO2 := fuzzy set (0.6, truth value 1), (0.61, truth value 0);
        def_improved_oxy_begin := fuzzy set (0.85, truth value 0), (0.87, truth value 1), (0.95, truth value 1), (0.99, truth value 0);
        def_improved_oxy_end := fuzzy set (0.93, truth value 0), (0.97, truth value 1);
        
        // State definitions
        state_normal := "Patient has normal oxygen levels";
        state_hypoxic := "Patient is hypoxic";
        state_responsive_high_FiO2 := "Patient is responsive to high FiO2";
        state_non_responsive_high_FiO2 := "Patient is non-responsive to high FiO2";

        // Set conditions at start
        let applicability of state_normal be 1;
        let applicability of state_hypoxic be 0;
        let applicability of state_responsive_high_FiO2 be 0;
        let applicability of state_non_responsive_high_FiO2 be 0;

        // Define transitions
        adeq_oxy := SaO2 is in def_adeq_oxy;
        hypoxemia := SaO2 is in def_hypoxemia;
        low_FiO2 := FiO2 is in def_low_FiO2;
        high_FiO2 := Fi02 is in def_high_FiO2;
        improved_oxy := last_Sao2 is in def_improved_oxy_begin and SaO2 is in def_improved_oxy_end;

        ;;
    priority: 50;;
    evoke: ;;
    logic:
        // Normal state has two incoming transitions: 
        let applicability of state_normal be
            // Keep current membership degree
            (applicability of state_normal) or 
            // Rule 1: Hypoxic and adequate oxygenation and low FiO2
            (applicability of state_hypoxic and applicability of adeq_oxy and applicability of low_FiO2) or
            // Rule 2: Responsive to high FiO2 and adequate oxygenation
            (applicability of state_responsive_high_FiO2 and applicability of adeq_oxy);
        
        // Hypoxic state has three incoming transitions: 
        let applicability of state_hypoxic be
            // Keep current membership degree
            (applicability of state_hypoxic) or 
            // Rule 3: Normal and hypoxemia
            (applicability of state_hypoxic and applicability of hypoxemia) or
            // Rule 4: Responsive to high FiO2 and hypoxemia
            (applicability of state_responsive_high_FiO2 and applicability of hypoxemia) or
            // Rule 5: Non-responsive to high FiO2 and hypoxemia or low FiO2
            (applicability of state_non_responsive_high_FiO2 and (applicability of hypoxemia or applicability of low_FiO2));

        // Responsive to high FiO2 state has two incoming transitions: 
        let applicability of state_responsive_high_FiO2 be
            // Keep current membership degree
            (applicability of state_responsive_high_FiO2) or 
            // Rule 6: Hypoxic and high FiO2 and improved_oxy
            (applicability of state_hypoxic and applicability of adeq_oxy and applicability of high_FiO2 and applicability of improved_oxy) or
            // Rule 7: Non-responsive to high FiO2 and adequate oxygenation
            (applicability of state_non_responsive_high_FiO2 and applicability of adeq_oxy and applicability of high_FiO2);
        
        // Non-responsive to high FiO2 has one incoming transition: 
        let applicability of state_non_responsive_high_FiO2 be
            // Keep current membership degree
            (applicability of state_non_responsive_high_FiO2) or 
            // Rule 8: Hypoxic and adequate oxygenation and low FiO2
            (applicability of state_hypoxic and applicability of hypoxemia and applicability of high_FiO2);
        
    conclude true;;
    action: return state_normal, state_hypoxic, state_responsive_high_FiO2, state_non_responsive_high_FiO2;;
    urgency: 50;;
resources:
    default: en;;
    language: en;;
    end:

To turn this automaton into a continuous monitoring tool, we treat its output as the input for the next cycle.

Congratulations! You’ve just learned how to:

  • Define fuzzy sets to model real-world conditions
  • Create state-based logic using fuzzy transitions
  • Use automata to simulate and monitor clinical conditions