What is FGraph

The FGraph is an adaptation of a functional graph. In programming, a functional graph typically refers to a data structure or representation used to model and analyze the flow of data or the dependencies between functions in a functional programming paradigm. Functional programming emphasizes the use of pure functions and avoids mutable state, making functional graphs particularly useful for understanding and optimizing the execution of functional programs. It is compromised of a Dictionary, containing the nodeIndex as Key and the so called FContext as Value. The structure is visualised here:

Quickstart

Creating an empty graph and filling it with single elements

Begin by creating an empty graph,meaning a data structure with no nodes or edges. Then populate the graph with single elements, individual nodes are added one by one, and edges can be introduced to establish connections between them.

open Graphoscope
open FGraph

let graphToFill =

    FGraph.empty
    |> FGraph.addNode 1 "1"
    |> FGraph.addNode 2 "2"
    |> FGraph.addEdge 1 2 1.
"You have created a graph with 2 nodes and 1 edges"

Working with Graphs

Creating a Graph using FGraph

Creating an empty graph and add collections of elements

Another way of creating a graph is by filling it with collections of nodes and edges as seen below:

let graphToFill' =
    
    let nodes = List.init 100 (fun x -> x,$"{x}")

    let edges = List.init 45 (fun x -> x,x*2,1.)

    FGraph.empty
    |> FGraph.addNodes nodes
    |> FGraph.addEdges edges
"You have created a graph with 100 nodes and 45 edges"

Removing Nodes and Edges

To remove Nodes or Edges you can just use the remove functions provided:

let graphWithRemovedElements =
    graphToFill'
    |> FGraph.removeEdge 1 2
    |> FGraph.removeNode 0
"You have reduced the graph to 99 nodes and 43 edges"

From Data

Import a graph

This directed network contains observed grooming episodes between free ranging rhesus macaques (Macaca mulatta) in Cayo Santiago during a two month period in 1963. Cayo Santiago is an island off the coast of Puerto Rico, also known as Isla de los monos (Island of the monkeys). A node represents a monkey and a directed edge A → B denotes that the rhesus macaque A groomed rhesus macaque B. The integer edge weights indicate how often this behaviour was observed.

open Graphoscope

open FSharpAux.IO
open FSharpAux.IO.SchemaReader.Attribute

First we model the input domain as a reccord type and read a sequence of MonkeyEdges

type MonkeyEdge = {
    [<Field(0)>] Source  : int
    [<Field(1)>] Target  : int
    [<Field(2)>] Groomed : int
}

let monkeyEdges =
    Seq.fromFileWithCsvSchema<MonkeyEdge>("D:/Source/Graphoscope/tests/Graphoscope.Tests/ReferenceGraphs/out.moreno_rhesus_rhesus.txt",' ',false,skipLines=2 )

Convert a MonkeyEdge record to a sequence of graph elements (sourceKey * sourceData * targetKey * targetData * edgeData)

let monkeyGraph =
    monkeyEdges
    |> Seq.map (fun mke ->
        mke.Source, sprintf "Monkey_%i" mke.Source,mke.Target,sprintf "Monkey_%i" mke.Target,float mke.Groomed)
    |> FGraph.ofSeq

let's use Cytoscape.NET for visualization:

open Cytoscape.NET
let vizGraph =
    CyGraph.initEmpty ()
    |> CyGraph.withElements [
            for (sk,s,tk,t,el) in (FGraph.toSeq monkeyGraph) do
                let sk, tk = (string sk), (string tk)
                yield Elements.node sk [ CyParam.label s ]
                yield Elements.node tk [ CyParam.label t ]
                yield Elements.edge  (sprintf "%s_%s" sk tk) sk tk [ CyParam.label el ]
        ]
    |> CyGraph.withStyle "node"     
        [
            CyParam.content =. CyParam.label
            CyParam.color "#A00975"
        ]
No value returned by any evaluator
namespace Graphoscope
Multiple items
module FGraph from Graphoscope

--------------------
type FGraph = new: unit -> FGraph static member addEdge: nk1: 'NodeKey -> nk2: 'NodeKey -> ed: 'EdgeData -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison) static member addEdges: edgeSeq: seq<'NodeKey * 'NodeKey * 'EdgeData> -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison) static member addElement: nk1: 'NodeKey -> nd1: 'NodeData -> nk2: 'NodeKey -> nd2: 'NodeData -> ed: 'EdgeData -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison) static member addNode: nk: 'NodeKey -> nd: 'NodeData -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison) static member addNodes: nodeSeq: seq<'NodeKey * 'NodeData> -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison) static member clone: graph: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison) static member containsEdge: v1: 'NodeKey -> v2: 'NodeKey -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> bool (requires comparison) static member containsNode: vk: 'NodeKey -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> bool (requires comparison) static member countEdges: g: FGraph<'NodeKey,'NodeData,'EdgeData> -> int (requires comparison) ...

--------------------
type FGraph<'NodeKey,'NodeData,'EdgeData (requires comparison)> = System.Collections.Generic.Dictionary<'NodeKey,FContext<'NodeKey,'NodeData,'EdgeData>>

--------------------
new: unit -> FGraph
val graphToFill: FGraph<int,string,float>
val empty<'NodeKey,'NodeData,'EdgeData (requires comparison)> : FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
<summary> Returns a new, empty graph </summary>
<returns>Empty FGraph</returns>
static member FGraph.addNode: nk: 'NodeKey -> nd: 'NodeData -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
static member FGraph.addEdge: nk1: 'NodeKey -> nk2: 'NodeKey -> ed: 'EdgeData -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
val graphToFillOutput: string
val sprintf: format: Printf.StringFormat<'T> -> 'T
<summary>Print to a string using the given format.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
<example>See <c>Printf.sprintf</c> (link: <see cref="M:Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThen``1" />) for examples.</example>
static member FGraph.countNodes: g: FGraph<'NodeKey,'NodeData,'EdgeData> -> int (requires comparison)
static member FGraph.countEdges: g: FGraph<'NodeKey,'NodeData,'EdgeData> -> int (requires comparison)
val graphToFill': FGraph<int,string,float>
val nodes: (int * string) list
Multiple items
module List from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.list`1" />.</summary>
<namespacedoc><summary>Operations for collections such as lists, arrays, sets, maps and sequences. See also <a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/fsharp-collection-types">F# Collection Types</a> in the F# Language Guide. </summary></namespacedoc>


--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T member IsEmpty: bool member Item: index: int -> 'T with get ...
<summary>The type of immutable singly-linked lists.</summary>
<remarks>Use the constructors <c>[]</c> and <c>::</c> (infix) to create values of this type, or the notation <c>[1;2;3]</c>. Use the values in the <c>List</c> module to manipulate values of this type, or pattern match against the values directly. </remarks>
<exclude />
val init: length: int -> initializer: (int -> 'T) -> 'T list
<summary>Creates a list by calling the given generator on each index.</summary>
<param name="length">The length of the list to generate.</param>
<param name="initializer">The function to generate an element from an index.</param>
<exception cref="T:System.ArgumentException">Thrown when the input length is negative.</exception>
<returns>The list of generated elements.</returns>
<example id="init-1"><code lang="fsharp"> List.init 4 (fun v -&gt; v + 5) </code> Evaluates to <c>[5; 6; 7; 8]</c></example>
<example id="init-2"><code lang="fsharp"> List.init -5 (fun v -&gt; v + 5) </code> Throws <c>ArgumentException</c></example>
val x: int
val edges: (int * int * float) list
static member FGraph.addNodes: nodeSeq: seq<'NodeKey * 'NodeData> -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
static member FGraph.addEdges: edgeSeq: seq<'NodeKey * 'NodeKey * 'EdgeData> -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
val graphToFill2Output: string
val graphWithRemovedElements: FGraph<int,string,float>
static member FGraph.removeEdge: nkSource: 'NodeKey -> nkTarget: 'NodeKey -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
static member FGraph.removeNode: nk: 'NodeKey -> g: FGraph<'NodeKey,'NodeData,'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
val removing: string
namespace FSharpAux
namespace FSharpAux.IO
module SchemaReader from FSharpAux.IO
module Attribute from FSharpAux.IO.SchemaReader
<summary> Attributes to be added to fields of a schema record </summary>
type MonkeyEdge = { Source: int Target: int Groomed: int }
Multiple items
type FieldAttribute = inherit Attribute new: indexTag: FieldIndex -> FieldAttribute + 5 overloads member IndexTag: FieldIndex
<summary> An attribute to be added to fields of a schema record type to indicate the column used in the data format for the schema as index </summary>

--------------------
new: indexTag: SchemaReader.FieldIndex -> FieldAttribute
new: index: int -> FieldAttribute
new: index: string -> FieldAttribute
new: indices: int[] -> FieldAttribute
new: indices: string[] -> FieldAttribute
new: indexFrom: int * indexTo: int -> FieldAttribute
MonkeyEdge.Source: int
Multiple items
val int: value: 'T -> int (requires member op_Explicit)
<summary>Converts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Int32.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted int</returns>
<example id="int-example"><code lang="fsharp"></code></example>


--------------------
[<Struct>] type int = int32
<summary>An abbreviation for the CLI type <see cref="T:System.Int32" />.</summary>
<category>Basic Types</category>


--------------------
type int<'Measure> = int
<summary>The type of 32-bit signed integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Int32" />.</summary>
<category>Basic Types with Units of Measure</category>
MonkeyEdge.Target: int
MonkeyEdge.Groomed: int
val monkeyEdges: seq<MonkeyEdge>
Multiple items
module Seq from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.seq`1" />.</summary>

--------------------
type Seq = static member CSV: separator: string -> header: bool -> flatten: bool -> data: seq<'a> -> seq<string> static member CSVwith: valFunc: ('a -> ('a -> obj)[]) -> strFunc: (string -> bool -> obj -> obj -> string) -> separator: string -> header: bool -> flatten: bool -> data: seq<'a> -> seq<string> static member fromFile: filePath: string -> seq<string> static member fromFileWithCsvSchema: filePath: string * separator: char * firstLineHasHeader: bool * ?skipLines: int * ?skipLinesBeforeHeader: int * ?schemaMode: SchemaModes -> seq<'schema> static member fromFileWithSep: separator: char -> filePath: string -> seq<string[]> static member stringFunction: separator: string -> flatten: bool -> input: 'a -> (obj -> string) static member valueFunction: dataEntry: 'a -> ('a -> obj)[] static member write: path: string -> data: seq<'a> -> unit static member writeOrAppend: path: string -> data: seq<'a> -> unit
static member Seq.fromFileWithCsvSchema: filePath: string * separator: char * firstLineHasHeader: bool * ?skipLines: int * ?skipLinesBeforeHeader: int * ?schemaMode: SchemaReader.Csv.SchemaModes -> seq<'schema>
val monkeyGraph: FGraph<int,string,float>
val map: mapping: ('T -> 'U) -> source: seq<'T> -> seq<'U>
<summary>Builds a new collection whose elements are the results of applying the given function to each of the elements of the collection. The given function will be applied as elements are demanded using the <c>MoveNext</c> method on enumerators retrieved from the object.</summary>
<remarks>The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently.</remarks>
<param name="mapping">A function to transform items from the input sequence.</param>
<param name="source">The input sequence.</param>
<returns>The result sequence.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input sequence is null.</exception>
<example id="item-1"><code lang="fsharp"> let inputs = ["a"; "bbb"; "cc"] inputs |&gt; Seq.map (fun x -&gt; x.Length) </code> Evaluates to a sequence yielding the same results as <c>seq { 1; 3; 2 }</c></example>
val mke: MonkeyEdge
Multiple items
val float: value: 'T -> float (requires member op_Explicit)
<summary>Converts the argument to 64-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Double.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted float</returns>
<example id="float-example"><code lang="fsharp"></code></example>


--------------------
[<Struct>] type float = System.Double
<summary>An abbreviation for the CLI type <see cref="T:System.Double" />.</summary>
<category>Basic Types</category>


--------------------
type float<'Measure> = float
<summary>The type of double-precision floating point numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Double" />.</summary>
<category index="6">Basic Types with Units of Measure</category>
static member FGraph.ofSeq: edgelist: seq<'NodeKey * 'NodeData * 'NodeKey * 'NodeData * 'EdgeData> -> FGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
namespace Cytoscape
namespace Cytoscape.NET
val vizGraph: CyGraph.CyGraph
module CyGraph from Cytoscape.NET
val initEmpty: unit -> CyGraph.CyGraph
val withElements: elems: seq<CytoscapeModel.Element> -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
val sk: int
val s: string
val tk: int
val t: string
val el: float
static member FGraph.toSeq: graph: FGraph<'NodeKey,'NodeData,'EdgeData> -> seq<'NodeKey * 'NodeData * 'NodeKey * 'NodeData * 'EdgeData> (requires comparison)
val sk: string
val tk: string
Multiple items
val string: value: 'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>
<example id="string-example"><code lang="fsharp"></code></example>


--------------------
type string = System.String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
module Elements from Cytoscape.NET
val node: id: string -> dataAttributes: CyParam.CyStyleParam list -> Elements.Node
module CyParam from Cytoscape.NET
val label: v: 'a -> CyParam.CyStyleParam
val edge: id: string -> sourceId: string -> targetId: string -> dataAttributes: CyParam.CyStyleParam list -> Elements.Edge
val withStyle: selector: string -> cyStyles: seq<CyParam.CyStyleParam> -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
val content: v: 'a -> CyParam.CyStyleParam
val color: v: 'a -> CyParam.CyStyleParam
val withZoom: zoom: CytoscapeModel.Zoom -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
namespace Cytoscape.NET.CytoscapeModel
Multiple items
type Zoom = inherit DynamicObj new: unit -> Zoom static member Init: ?Level: float * ?Position: (int * int) * ?RenderedPosition: (int * int) * ?ZoomingEnabled: bool -> Zoom static member Update: ?Level: float * ?Position: (int * int) * ?RenderedPosition: (int * int) * ?ZoomingEnabled: bool -> (Zoom -> Zoom)

--------------------
new: unit -> CytoscapeModel.Zoom
static member CytoscapeModel.Zoom.Init: ?Level: float * ?Position: (int * int) * ?RenderedPosition: (int * int) * ?ZoomingEnabled: bool -> CytoscapeModel.Zoom
val withSize: width: int * height: int -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
type HTML = static member CreateGraphHTML: graphData: string * zooming: string * divId: string * cytoscapeReference: CytoscapeJSReference * ?Width: int * ?Height: int -> XmlNode list static member CreateGraphScript: graphData: string * zooming: string * cytoscapeReference: CytoscapeJSReference -> XmlNode static member Doc: graphHTML: XmlNode list * cytoscapeReference: CytoscapeJSReference * ?AdditionalHeadTags: XmlNode list -> XmlNode static member show: cy: Cytoscape * ?DisplayOpts: DisplayOptions -> unit static member toEmbeddedHTML: ?DisplayOpts: DisplayOptions -> (Cytoscape -> string) static member toGraphHTML: ?DisplayOpts: DisplayOptions -> (Cytoscape -> string) static member toGraphHTMLNodes: ?DisplayOpts: DisplayOptions -> (Cytoscape -> XmlNode list)
<summary> HTML template for Cytoscape </summary>
static member HTML.toGraphHTML: ?DisplayOpts: DisplayOptions -> (CytoscapeModel.Cytoscape -> string)