eaebec39创建于 2024年10月24日历史提交
package scientific.matplot

import std.math.*
import std.unittest.*
import std.unittest.testmacro.*

import scientific.numbers.*
import scientific.linear.*
import scientific.stats.random.*
import scientific.stats.normal.*

/* Type for weights, x_data, y_data, z_data, line_widths: Float64
   Type for edges: Int64 */
foreign func c_graph(edges: CPointer<Unit>, row: Int64, col: Int64, line_spec: CString): CPointer<Unit>
foreign func c_digraph(edges: CPointer<Unit>, row: Int64, col: Int64, line_spec: CString): CPointer<Unit>
foreign func c_show_labels(netw: CPointer<Unit>, b: Bool): Unit
foreign func c_edge_labels(netw: CPointer<Unit>, weights: CPointer<Unit>, len: Int64): Unit
foreign func c_edge_labels_str(netw: CPointer<Unit>, edge_labels: CPointer<CString>, len: Int64): Unit
foreign func c_node_labels(netw: CPointer<Unit>, node_labels: CPointer<CString>, len: Int64): Unit
foreign func c_x_data(netw: CPointer<Unit>, x_data: CPointer<Unit>, len: Int64): Unit
foreign func c_y_data(netw: CPointer<Unit>, y_data: CPointer<Unit>, len: Int64): Unit
foreign func c_z_data(netw: CPointer<Unit>, z_data: CPointer<Unit>, len: Int64): Unit
foreign func c_line_widths(netw: CPointer<Unit>, line_widths: CPointer<Unit>, len: Int64): Unit

public func graph(edges: Matrix<Int64>, line_spec!: String = "-o") {
    if (edges.getCols() != 2) {
        throw IllegalArgumentException("graph: input must be a matrix with 2 columns.")
    }
    var cstr_line_spec = unsafe { LibC.mallocCString(line_spec) }
    let handle = unsafe { c_graph(edges.ptr, edges.getRows(), edges.getCols(), cstr_line_spec) }
    unsafe { LibC.free(cstr_line_spec) }
    return Network(handle)
}

public func digraph(edges: Matrix<Int64>, line_spec!: String = "-o"): Network {
    if (edges.getCols() != 2) {
        throw IllegalArgumentException("digraph: input must be a matrix with 2 columns.")
    }
    var cstr_line_spec = unsafe { LibC.mallocCString(line_spec) }
    let handle = unsafe { c_digraph(edges.ptr, edges.getRows(), edges.getCols(), cstr_line_spec) }
    unsafe { LibC.free(cstr_line_spec) }
    return Network(handle)
}

public class Network {
    var ptr: CPointer<Unit>
    /* Input is a pointer to matplot::network. */
    init(ptr: CPointer<Unit>) {
        this.ptr = ptr
    }

    public func show_labels(b: Bool): Unit {
        unsafe { c_show_labels(this.ptr, b) }
    }

    public func x_data(x_data: Vector<Float64>): Unit {
        unsafe { c_x_data(this.ptr, x_data.ptr, x_data.size()) }
    }

    public func y_data(y_data: Vector<Float64>): Unit {
        unsafe { c_y_data(this.ptr, y_data.ptr, y_data.size()) }
    }

    public func z_data(z_data: Vector<Float64>): Unit {
        unsafe { c_z_data(this.ptr, z_data.ptr, z_data.size()) }
    }

    public func edge_labels(weights: Vector<Float64>): Unit {
        unsafe { c_edge_labels(this.ptr, weights.ptr, weights.size()) }
    }

    public func edge_labels(edge_labels: Array<String>): Unit {
        let size = edge_labels.size
        var a = unsafe { malloc(UIntNative(8 * size)) }
        var labels_ptr = CPointer<CString>(a)
        for (i in 0..size) {
            var cstr_edge_label = unsafe { LibC.mallocCString(edge_labels[i]) }
            unsafe { labels_ptr.write(i, cstr_edge_label) }
            unsafe { LibC.free(cstr_edge_label) }
        }
        unsafe { c_edge_labels_str(this.ptr, labels_ptr, size) }
    }

    public func node_labels(node_labels: Array<String>): Unit {
        let size = node_labels.size
        var a = unsafe { malloc(UIntNative(8 * size)) }
        var labels_ptr = CPointer<CString>(a)
        for (i in 0..size) {
            var cstr_node_label = unsafe { LibC.mallocCString(node_labels[i]) }
            unsafe { labels_ptr.write(i, cstr_node_label) }
            unsafe { LibC.free(cstr_node_label) }
        }
        unsafe { c_node_labels(this.ptr, labels_ptr, size) }
    }

    public func line_widths(line_widths: Vector<Float64>): Unit {
        unsafe { c_line_widths(this.ptr, line_widths.ptr, line_widths.size()) }
    }
}

public func testGraph1() {
    let edges = matrix<Int64>([
        [0, 0],   [1, 0],   [5, 0],   [0, 1],   [1, 1],   [2, 1],   [6, 1],
        [1, 2],   [2, 2],   [3, 2],   [7, 2],   [2, 3],   [3, 3],   [4, 3],
        [8, 3],   [3, 4],   [4, 4],   [9, 4],   [0, 5],   [5, 5],   [6, 5],
        [10, 5],  [1, 6],   [5, 6],   [6, 6],   [7, 6],   [11, 6],  [2, 7],
        [6, 7],   [7, 7],   [8, 7],   [12, 7],  [3, 8],   [7, 8],   [8, 8],
        [9, 8],   [13, 8],  [4, 9],   [8, 9],   [9, 9],   [14, 9],  [5, 10],
        [10, 10], [11, 10], [15, 10], [6, 11],  [10, 11], [11, 11], [12, 11],
        [16, 11], [7, 12],  [11, 12], [12, 12], [13, 12], [17, 12], [8, 13],
        [12, 13], [13, 13], [14, 13], [18, 13], [9, 14],  [13, 14], [14, 14],
        [19, 14], [10, 15], [15, 15], [16, 15], [20, 15], [11, 16], [15, 16],
        [16, 16], [17, 16], [21, 16], [12, 17], [16, 17], [17, 17], [18, 17],
        [22, 17], [13, 18], [17, 18], [18, 18], [19, 18], [23, 18], [14, 19],
        [18, 19], [19, 19], [24, 19], [15, 20], [20, 20], [21, 20], [25, 20],
        [16, 21], [20, 21], [21, 21], [22, 21], [26, 21], [17, 22], [21, 22],
        [22, 22], [23, 22], [27, 22], [18, 23], [22, 23], [23, 23], [24, 23],
        [28, 23], [19, 24], [23, 24], [24, 24], [29, 24], [20, 25], [25, 25],
        [26, 25], [35, 25], [21, 26], [25, 26], [26, 26], [27, 26], [36, 26],
        [22, 27], [26, 27], [27, 27], [28, 27], [37, 27], [23, 28], [27, 28],
        [28, 28], [29, 28], [38, 28], [24, 29], [28, 29], [29, 29], [30, 29],
        [39, 29], [29, 30], [30, 30], [31, 30], [40, 30], [30, 31], [31, 31],
        [32, 31], [41, 31], [31, 32], [32, 32], [33, 32], [42, 32], [32, 33],
        [33, 33], [34, 33], [43, 33], [33, 34], [34, 34], [44, 34], [25, 35],
        [35, 35], [36, 35], [45, 35], [26, 36], [35, 36], [36, 36], [37, 36],
        [46, 36], [27, 37], [36, 37], [37, 37], [38, 37], [47, 37], [28, 38],
        [37, 38], [38, 38], [39, 38], [48, 38], [29, 39], [38, 39], [39, 39],
        [40, 39], [49, 39], [30, 40], [39, 40], [40, 40], [41, 40], [50, 40],
        [31, 41], [40, 41], [41, 41], [42, 41], [51, 41], [32, 42], [41, 42],
        [42, 42], [43, 42], [52, 42], [33, 43], [42, 43], [43, 43], [44, 43],
        [53, 43], [34, 44], [43, 44], [44, 44], [54, 44], [35, 45], [45, 45],
        [46, 45], [55, 45], [36, 46], [45, 46], [46, 46], [47, 46], [56, 46],
        [37, 47], [46, 47], [47, 47], [48, 47], [57, 47], [38, 48], [47, 48],
        [48, 48], [49, 48], [58, 48], [39, 49], [48, 49], [49, 49], [50, 49],
        [59, 49], [40, 50], [49, 50], [50, 50], [51, 50], [60, 50], [41, 51],
        [50, 51], [51, 51], [52, 51], [61, 51], [42, 52], [51, 52], [52, 52],
        [53, 52], [62, 52], [43, 53], [52, 53], [53, 53], [54, 53], [63, 53],
        [44, 54], [53, 54], [54, 54], [64, 54], [45, 55], [55, 55], [56, 55],
        [65, 55], [46, 56], [55, 56], [56, 56], [57, 56], [66, 56], [47, 57],
        [56, 57], [57, 57], [58, 57], [67, 57], [48, 58], [57, 58], [58, 58],
        [59, 58], [68, 58], [49, 59], [58, 59], [59, 59], [60, 59], [69, 59],
        [50, 60], [59, 60], [60, 60], [61, 60], [70, 60], [51, 61], [60, 61],
        [61, 61], [62, 61], [71, 61], [52, 62], [61, 62], [62, 62], [63, 62],
        [72, 62], [53, 63], [62, 63], [63, 63], [64, 63], [73, 63], [54, 64],
        [63, 64], [64, 64], [74, 64], [55, 65], [65, 65], [66, 65], [56, 66],
        [65, 66], [66, 66], [67, 66], [57, 67], [66, 67], [67, 67], [68, 67],
        [58, 68], [67, 68], [68, 68], [69, 68], [59, 69], [68, 69], [69, 69],
        [70, 69], [60, 70], [69, 70], [70, 70], [71, 70], [61, 71], [70, 71],
        [71, 71], [72, 71], [62, 72], [71, 72], [72, 72], [73, 72], [63, 73],
        [72, 73], [73, 73], [74, 73], [64, 74], [73, 74], [74, 74]
    ])
    graph(edges)
    save("./tests/imgs/graph/graph1.png", "png")
    clear()
}

public func testGraph2() {
    let edges = matrix<Int64>([
        [0, 1],   [0, 4],   [0, 5],   [1, 2],   [1, 10],  [2, 3],   [2, 15],
        [3, 4],   [3, 20],  [4, 25],  [5, 6],   [5, 9],   [6, 7],   [6, 29],
        [7, 8],   [7, 41],  [8, 9],   [8, 37],  [9, 11],  [10, 11], [10, 14],
        [11, 12], [12, 13], [12, 36], [13, 14], [13, 32], [14, 16], [15, 16],
        [15, 19], [16, 17], [17, 18], [17, 31], [18, 19], [18, 52], [19, 21],
        [20, 21], [20, 24], [21, 22], [22, 23], [22, 51], [23, 24], [23, 47],
        [24, 26], [25, 26], [25, 29], [26, 27], [27, 28], [27, 46], [28, 29],
        [28, 42], [30, 31], [30, 34], [30, 53], [31, 32], [32, 33], [33, 34],
        [33, 35], [34, 55], [35, 36], [35, 39], [36, 37], [37, 38], [38, 39],
        [38, 40], [39, 56], [40, 41], [40, 44], [41, 42], [42, 43], [43, 44],
        [43, 45], [44, 57], [45, 46], [45, 49], [46, 47], [47, 48], [48, 49],
        [48, 50], [49, 58], [50, 51], [50, 54], [51, 52], [52, 53], [53, 54],
        [54, 59], [55, 56], [55, 59], [56, 57], [57, 58], [58, 59]
    ])
    graph(edges, line_spec: "-.dr").show_labels(false)
    save("./tests/imgs/graph/graph2.png", "png")
    clear()
}

public func testGraph3() {
    let edges = matrix<Int64>([
        [0, 1], [0, 2],  [0, 3], [0, 4], [0, 6],  [0, 9], [1, 5],
        [1, 6], [2, 5],  [2, 9], [3, 7], [3, 9],  [4, 6], [4, 7],
        [5, 8], [5, 10], [6, 8], [7, 8], [7, 10], [9, 10]
    ])

    let weights = vector<Float64>([
        1.0, 1.0, 1.0, 1.0, 3.0, 3.0, 2.0,  4.0,  1.0,  6.0,
        2.0, 8.0, 8.0, 9.0, 3.0, 2.0, 10.0, 12.0, 15.0, 16.0
    ])

    var g = graph(edges)
    g.x_data(vector<Float64>([0.0, 0.5, -0.5, -0.5, 0.5, 0.0, 1.5, 0.0, 2.0, -1.5, -2.0]))
    g.y_data(vector<Float64>([0.0, 0.5, 0.5, -0.5, -0.5, 2.0, 0.0, -2.0, 0.0, 0.0, 0.0]))
    g.z_data(vector<Float64>([5.0, 3.0, 3.0, 3.0, 3.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]))

    g.edge_labels(weights)
    view(2)

    save("./tests/imgs/graph/graph3.png", "png")
    clear()
}

public func testGraph4() {
    let edges = matrix<Int64>([
        [0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 5],
        [2, 5], [3, 4], [3, 6], [4, 6], [5, 6]
    ])

    let weights = vector<Float64>([
        50.0, 10.0, 20.0, 80.0, 90.0, 90.0, 30.0, 20.0, 100.0, 40.0, 60.0])

    var g = graph(edges)
    g.edge_labels(weights)

    let m_weight = max(weights)
    var line_widths = weights.apply({w: Float64 => 5.0 * w / m_weight})
    g.line_widths(line_widths)

    save("./tests/imgs/graph/graph4.svg", "svg")
    clear()
}

public func testDiGraph1() {
    let edges = matrix<Int64>([
        [0, 1],   [0, 2],   [0, 3],   [0, 4],   [1, 5],  [1, 6],  [1, 7],
        [1, 8],   [1, 9],   [1, 10],  [1, 11],  [1, 12], [1, 13], [1, 14],
        [14, 15], [14, 16], [14, 17], [14, 18], [14, 19]
    ])
    digraph(edges)
    save("./tests/imgs/graph/digraph1.png", "png")
    clear()
}

public func testDiGraph2() {
    let edges = matrix<Int64>([
        [0, 1], [0, 2], [0, 3], [1, 4], [1, 5], [2, 4],
        [2, 6], [3, 5], [3, 6], [4, 7], [5, 7], [6, 7]
    ])
    var g = digraph(edges)
    g.edge_labels(["x", "y", "z", "y", "z", "x", "z", "x", "y", "z", "y", "x"])
    g.node_labels(["{0}", "{x}", "{y}", "{z}", "{x,y}", "{x,z}", "{y,z}", "{x,y,z}"])

    save("./tests/imgs/graph/digraph2.png", "png")
    clear()
}

public func testGraph() {
    testGraph1()
    testGraph2()
    testGraph3()
    testGraph4()
    testDiGraph1()
    testDiGraph2()
}