FuzzyCognitiveMaps
This is a Julia package for working with fuzzy cognitive maps (FCMs). It has fairly flexible facilities for constructing and analysing FCMs, as well as limited import (from CSV) and export (to DOT) functionality.
Each fuzzy cognitive map is represented by a MetaGraph object, created by the new_fcm() function. The MetaGraph type is defined by the MetaGraphsNext package, which is also compatible with the Graphs API, and thus with the wider JuliaGraphs ecosystem.
Usage
The package is not (yet) registered in the Julia Package Registry, so for now it must be added to your project by repo URL. For example, using the REPL interface to Pkg after pressing ],
pkg> add https://gitlab.sintef.no/lars.kyllingstad/FuzzyCognitiveMaps.gitExample
The FCM in the following example was inspired by Figure 1 in the paper “Context modeling with Evolutionary Fuzzy Cognitive Map in interactive storytelling” by Cai et al. (2008).
The graphics are generated with Makie, using the GraphMakie extension to display the FCM itself.
using CairoMakie, GraphMakie
using FuzzyCognitiveMaps
using Graphs
# Construct FCM
fcm = new_fcm()
add_concept!(fcm, :BadWeather; text = "Bad weather")
add_concept!(fcm, :Congestion; text = "Traffic congestion")
add_concept!(fcm, :Accidents; text = "Auto accidents")
add_concept!(fcm, :RiskAversion; text = "Driver risk aversion")
add_concept!(fcm, :Patrols; text = "Patrol frequency")
add_concept!(fcm, :Speed; text = "Driving speed")
add_link!(fcm, :BadWeather, :Accidents, 0.5)
add_link!(fcm, :BadWeather, :Congestion, 1.0)
add_link!(fcm, :Congestion, :Accidents, 0.5)
add_link!(fcm, :Congestion, :Speed, -0.75)
add_link!(fcm, :Accidents, :Congestion, 0.75)
add_link!(fcm, :Accidents, :RiskAversion, 0.25)
add_link!(fcm, :Accidents, :Patrols, 0.5)
add_link!(fcm, :Patrols, :Accidents, -0.25)
add_link!(fcm, :Patrols, :RiskAversion, 0.75)
add_link!(fcm, :RiskAversion, :Speed, -0.25)
# Display resulting graph using GraphMakie
fig, ax, plt = graphplot(fcm;
ilabels = replace.(concept_texts(fcm), " " => "\n"),
elabels = string.(getproperty.(links(fcm), :weight)),
arrow_shift = :end)
limits!(ax, -3.0, 2.4, -3.2, 2.4)
hidedecorations!(ax)
hidespines!(ax)
ax.aspect = DataAspect()
fig
# Perform inference
initial_values = [0.4, 0.3, 0.1, 0.7, 0.1, 0.5]
initial_state = FCMInferenceState(fcm, initial_values; drivers = [:BadWeather])
final_state, trajectories, converged = infer(initial_state; atol = 1e-3)
# Plot inference results
fig = Figure()
steps = 0:size(trajectories, 2)-1
ax = Axis(fig[1, 1];
xlabel = "Inference steps", xticks = steps,
ylabel = "Concept values")
ylims!(ax, (-0.1, 1.1))
for i in 1:nv(fcm)
lines!(ax, steps, trajectories[i, :])
text!(size(trajectories, 2) - 1, trajectories[i, end];
text = concept_texts(fcm)[i], align=(:right, :bottom))
end
fig