Source: CNATool.js

/**
 * @license
 * Copyright 2020 Roberto Luiz Souza Monteiro,
 *                Renata Souza Barreto,
 *                Hernane Borges de Barros Pereira.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * CNATool core class.
 * @class
 */
function CNATool() {
    init();

    /**
     * Creates the attributes of the class.
     */
    function init() {
        // Class attributes goes here.
    }

    /**
     * Calculates the average shortest path.
     * @param {object}   property - Network properties (n, m and directed).
     * @param {boolean}  useGPU - Uses the GPU to speed up calculations.
     * @return           Graph properties.
     */
    this.calculateAverageShortestPath = function(property, useGPU) {
        if (typeof useGPU == 'undefined') {
            var useGPU = false;
        }
        
        var booleanAdj = core.copyMatrix(property.adj);

        var dimAdj = core.dim(booleanAdj);
        var dimJ = dimAdj[0];
        var dimK = dimAdj[1];

        for (var j = 0; j < dimJ; j++) {
            for (var k = 0; k < dimK; k++) {
                if (booleanAdj[j][k] != 0) {
                    booleanAdj[j][k] = 1;
                }
            }
        }

        property.networkShortestPath = cna.getShortestPath(booleanAdj, useGPU);
        property.networkAverageShortestPath = cna.getAverageShortestPath(property.networkShortestPath);
    }

    /**
     * Calculates graph properties.
     * @param {object}   property - Network properties (n, m and directed).
     * @param {boolean}  useGPU - Uses the GPU to speed up calculations.
     * @return           Graph properties.
     */
    this.calculateProperties = function(property, useGPU) {
        if (typeof useGPU == 'undefined') {
            var useGPU = false;
        }
        
        var booleanAdj = core.copyMatrix(property.adj);
        var dimAdj = core.dim(booleanAdj);
        var dimJ = dimAdj[0];
        var dimK = dimAdj[1];
        for (var j = 0; j < dimJ; j++) {
            for (var k = 0; k < dimK; k++) {
                if (booleanAdj[j][k] != 0) {
                    booleanAdj[j][k] = 1;
                }
            }
        }

        property.networkLabel = cna.getLabels(property.adj);
        property.networkDegree = cna.getDegrees(booleanAdj, property.directed);
        property.networkAverageDegree = cna.getAverageDegree(property.networkDegree);
        property.networkDensity = cna.getDensity(booleanAdj, property.directed);
        property.networkClustering = cna.getClustering(booleanAdj, property.directed);
        property.networkAverageClustering = cna.getAverageClustering(property.networkClustering);

        property.networkShortestPath = cna.getShortestPath(booleanAdj, useGPU);

        property.networkAverageShortestPath = cna.getAverageShortestPath(property.networkShortestPath);
        property.networkDiameter = cna.getDiameter(property.networkShortestPath);
        property.networkVertexEfficiency = cna.getVertexEfficiency(property.networkShortestPath);
        property.networkGlobalEfficiency = cna.getGlobalEfficiency(property.networkVertexEfficiency);
    }

    /**
     * Create summary report.
     * @param {object}   property - Network properties (n, m and directed).
     * @param {boolean}  includeDegDist - Include degree distribution in report.
     * @return           Summary report in HTML format.
     */
    this.getSummaryReport = function(property, includeDegDist) {
        if (typeof includeDegDist == 'undefined') {
            var includeDegDist = true;
        }
        if (includeDegDist) {
            property.networkDegreeDistribution = cna.getDegreeDistribution(property.networkDegree)
            dimNetworkDegreeDistribution = core.dim(property.networkDegreeDistribution)
        }
        var html = '';
        html = html + '<table style="margin-left: auto; margin-right: auto; border: 1px solid black;">'
        html = html + '<caption style="text-align: center; font-family: Arial; font-weight: bold;">Network Properties</caption>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Vertices:</th><td style="text-align: right; padding: 2px;">' + core.toString(property.n) + '</td></tr>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Edges:</th><td style="text-align: right; padding: 2px;">' + core.toString(property.m) + '</td></tr>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Density:</th><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkDensity) + '</td></tr>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Avg. Degree:</th><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkAverageDegree) + '</td></tr>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Avg. Clustering Coef.:</th><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkAverageClustering) + '</td></tr>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Avg. Shortest Path:</th><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkAverageShortestPath) + '</td></tr>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Diameter:</th><td style="text-align: right; padding: 2px;">' + core.toString(property.networkDiameter) + '</td></tr>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Global Efficiency:</th><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkGlobalEfficiency) + '</td></tr>'
        html = html + '</table>'
        html = html + '<br />'
        if (includeDegDist) {
            html = html + '<table style="margin-left: auto; margin-right: auto; border: 1px solid black;">'
            html = html + '<caption style="text-align: center; font-family: Arial; font-weight: bold;">Degree Disribuion</caption>'
            html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Cluster</th><th style="text-align: left; font-family: Arial; font-weight: bold;">Frequency</th><th style="text-align: left; font-family: Arial; font-weight: bold;">Frequency(%)</th></tr>'
            for (i = 0; i < dimNetworkDegreeDistribution[0]; i = i + 1) {
                html = html + '<tr><td style="text-align: right; padding: 2px;">' + core.toString(property.networkDegreeDistribution[i][0]) + '</td><td style="text-align: right; padding: 2px;">' + core.toString(property.networkDegreeDistribution[i][1]) + '</td><td style="text-align: right; padding: 2px;">' + string.sprintf('%.2f', property.networkDegreeDistribution[i][2]) + '</td></tr>'
            }
            html = html + '</table>'
            html = html + '<br />'
        }
        return html;
    }

    /**
     * Create vertices degrees report.
     * @param {object}   property - Network properties (n, m and directed).
     * @return           Vertices degrees report in HTML format.
     */
    this.getDegreesReport = function(property) {
        dimNetworkLabel = core.dim(property.networkLabel)

        var html = '';
        html = html + '<table style="margin-left: auto; margin-right: auto; border: 1px solid black;">'
        html = html + '<caption style="text-align: center; font-family: Arial; font-weight: bold;">Vertices Degrees</caption>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Vertex</th><th style="text-align: left; font-family: Arial; font-weight: bold;">Out-degree</th><th style="text-align: left; font-family: Arial; font-weight: bold;">In-degree</th><th style="text-align: left; font-family: Arial; font-weight: bold;">Degree</th></tr>'
        for (i = 1; i < dimNetworkLabel[0]; i = i + 1) {
            html = html + '<tr><td style="text-align: right; padding: 2px;">' + property.networkLabel[i] + '</td><td style="text-align: right; padding: 2px;">' + core.toString(property.networkDegree[i][0]) + '</td><td style="text-align: right; padding: 2px;">' + core.toString(property.networkDegree[i][1]) + '</td><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkDegree[i][2]) + '</td></tr>'
        }
        html = html + '</table>'
        html = html + '<br />'

        return html;
    }

    /**
     * Create vertices clustering report.
     * @param {object}   property - Network properties (n, m and directed).
     * @return           Vertices clustering report in HTML format.
     */
    this.getClusteringReport = function(property) {
        dimNetworkLabel = core.dim(property.networkLabel)

        var html = '';
        html = html + '<table style="margin-left: auto; margin-right: auto; border: 1px solid black;">'
        html = html + '<caption style="text-align: center; font-family: Arial; font-weight: bold;">Vertices Clustering</caption>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Vertex</th><th style="text-align: left; font-family: Arial; font-weight: bold;">Clustering</th></tr>'
        for (i = 1; i < dimNetworkLabel[0]; i = i + 1) {
            html = html + '<tr><td style="text-align: right; padding: 2px;">' + property.networkLabel[i] + '</td><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkClustering[i][0]) + '</td></tr>'
        }
        html = html + '</table>'
        html = html + '<br />'

        return html;
    }

    /**
     * Create vertices centralities report.
     * @param {object}   property - Network properties (n, m and directed).
     * @return           Vertices centralities report in HTML format.
     */
    this.getCentralitiesReport = function(property) {
        dimNetworkLabel = core.dim(property.networkLabel)

        property.networkCentrality = cna.getCentrality(property.adj, property.networkShortestPath, property.directed)

        var html = '';
        html = html + '<table style="margin-left: auto; margin-right: auto; border: 1px solid black;">'
        html = html + '<caption style="text-align: center; font-family: Arial; font-weight: bold;">Vertices Centralities</caption>'
        html = html + '<tr><th style="text-align: left; font-family: Arial; font-weight: bold;">Vertex</th><th style="text-align: left; font-family: Arial; font-weight: bold;">Geodesics</th><th style="text-align: left; font-family: Arial; font-weight: bold;">Closeness</th><th style="text-align: left; font-family: Arial; font-weight: bold;">Betweenness</th><th style="text-align: left; font-family: Arial; font-weight: bold;">nCloseness</th><th style="text-align: left; font-family: Arial; font-weight: bold;">nBetweenness</th></tr>'
        for (i = 1; i < dimNetworkLabel[0]; i = i + 1) {
            html = html + '<tr><td style="text-align: right; padding: 2px;">' + property.networkLabel[i] + '</td><td style="text-align: right; padding: 2px;">' + core.toString(property.networkCentrality[i][4]) + '</td><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkCentrality[i][0]) + '</td><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkCentrality[i][1]) + '</td><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkCentrality[i][2]) + '</td><td style="text-align: right; padding: 2px;">' + string.sprintf('%.4f', property.networkCentrality[i][3]) + '</td></tr>'
        }
        html = html + '</table>'
        html = html + '<br />'

        return html;
    }

    /**
     * Interpret the options passed on the command line,
     * process the files and generate the requested reports.
     */
    this.run = function() {
        // Supports only the Node.js interpreter.
        if (typeof process !== 'undefined') {
            var command = 'node';
            var argv = process.argv.slice();
            var fs = require('fs');
            var readTextFile = fs.readFileSync;

            // Read file callback.
            function read(input) {
                if (/^{.*}$/.test(input)) {
                    return input.substring(1, input.length - 1);
                } else {
                    var content = readTextFile(input, 'utf-8');
                    return content.length > 0 && content.charCodeAt(0) == 0xFEFF ? content.substring(1) : content;
                }
            }
            
            // Command line arguments.
            system.argv = argv.slice();
            system.argc = argv.length;

            // Command line options.
            var inputFile = '';
            var outputFile = '';
            var propertiesFile = '';
            var csvFile = '';
            var jsonFile = '';
            var logFile = '';
            var columnSeparator = ',';
            var replaceCommas = false;
            var includeAll = false;
            var includeClustering = false;
            var includeCentralities = false;
            var includeDegrees = false;
            var onlyAvgShortestpath = false;
            var useGPU = false;
            var buildGraph = false;
            var isWeighted = false;
            var calculateIncidenceFidelity = false;
            var createGraph = false;
            var isDirected = false;
            var exportGraph = false;
            var saveInJson = false;
            var allowLoops = false;
            var topology = '';
            var prefix = '';
            var vertices = 0;
            var edges = 0;
            var probability = 0
            var avgdegree = 0;
            var minw = '';
            var maxw = '';
            var minsd = '';
            var maxsd = '';
            var nfiles = 1;
            var vinc = 0;
            var einc = 0;
            var dinc = 0;

            // Properties object.
            var property = {
                'adj': [],
                'n': 0,
                'm': 0,
                'directed': false,
                'networkLabel': [],
                'networkDegree': [],
                'networkAverageDegree': 0,
                'networkDegreeDistribution': [],
                'networkDensity': 0,
                'networkClustering': [],
                'networkAverageClustering': 0,
                'networkShortestPath': [],
                'networkAverageShortestPath': 0,
                'networkDiameter': 0,
                'networkCentrality': [],
                'networkVertexEfficiency': [],
                'networkGlobalEfficiency': 0
            };

            // Get command line arguments.
            if (argv.length > 2) {
                var i = 2;
                while (i < argv.length) {
                    if (argv[i] == '-c') {
                        justCompile = true;
                    } else if ((argv[i] == '-h') || (argv[i] == '--help')) {
                        system.log('CNATool Command Line Interface (CLI)');
                        system.log('Usage: cnatool [options] [network.net] [--] [arguments]');
                        system.log('Options:');
                        system.log('-h     --help               Displays this help message;');
                        system.log('       --all                Include all properties in report;');
                        system.log('       --cen                Include vertices centralities in report;');
                        system.log('       --clu                Include vertices clustering in report;');
                        system.log('       --deg                Include vertices degrees in report;');
                        system.log('       --spath              Include only average shortest path in report;');
                        system.log('       --gpu                Uses the GPU to speed up calculations;');
                        system.log('       --csv                CSV output file name;');
                        system.log('-j                          JSON output file name;');
                        system.log('-l                          Log output file name;');
                        system.log('-o     [report.html]        Output report file name;');
                        system.log('-p     [properties.json]    Properties file name;');
                        system.log('-r                          Replace commas by dots in CSV numeric columns;');
                        system.log('-s                          CSV column separator;');
                        system.log('       --build              Builds a semantic network from a file in DLF format;');
                        system.log('       --weighted           The created network must be weighted based');
                        system.log('                            on the number of occurrences of the connections');
                        system.log('                            between the vertices;');
                        system.log('       --if                 Calculate the incidence fidelity index');
                        system.log('       --create             Creates a network file in Pajek format;');
                        system.log('       --directed           Network is a directed graph;');
                        system.log('       --export             Exports the network file in Pajek format;');
                        system.log('       --json               Save the network file in JSON format;');
                        system.log('       --loops              Allow loops;');
                        system.log('       --topology           Graph topology (complete, random, scalefree, smallworld or hybrid.');
                        system.log('                            For semantic networks it can be: chain, circle or clique);');
                        system.log('       --prefix             File name prefix for multiple file creation;');
                        system.log('       --vertices           Number of vertices;');
                        system.log('       --edges              Number of edges;');
                        system.log('       --probability        Edge probability;');
                        system.log('       --avgdeg             Average degree;');
                        system.log('       --minw               Minimum weight;');
                        system.log('       --maxw               Maximum weight;');
                        system.log('       --minsd              Percentage of the standard deviation that will be added to the');
                        system.log('                            average value of the weights to determine the existence of an edge.');
                        system.log('                            Will be used to determine the minw parameter;');
                        system.log('       --maxsd              Percentage of the standard deviation that will be added to the');
                        system.log('                            average value of the weights to determine the existence of an edge.');
                        system.log('                            Will be used to determine the maxw parameter;');
                        system.log('       --nfiles             number of files to create;');
                        system.log('       --vinc               increment to number of vertices;');
                        system.log('       --einc               increment to number of edges;');
                        system.log('       --dinc               increment to average degree.');
                        process.exit(0);
                    } else if (argv[i] == '--all') {
                        includeAll = true;
                    } else if (argv[i] == '--cen') {
                        includeCentralities = true;
                    } else if (argv[i] == '--clu') {
                        includeClustering = true;
                    } else if (argv[i] == '--deg') {
                        includeDegrees = true;
                    } else if (argv[i] == '--spath') {
                        onlyAvgShortestpath = true;
                    } else if (argv[i] == '--gpu') {
                        useGPU = true;
                    } else if (argv[i] == '--csv') {
                        i++;
                        csvFile = argv[i];
                    } else if (argv[i] == '-j') {
                        i++;
                        jsonFile = argv[i];
                    } else if (argv[i] == '-l') {
                        i++;
                        logFile = argv[i];
                    } else if (argv[i] == '-o') {
                        i++;
                        outputFile = argv[i];
                    } else if (argv[i] == '-p') {
                        i++;
                        propertiesFile = argv[i];
                    } else if (argv[i] == '-r') {
                        replaceCommas = true;
                    } else if (argv[i] == '-s') {
                        i++;
                        columnSeparator = argv[i];
                    } else if (argv[i] == '--build') {
                        buildGraph = true;
                    } else if (argv[i] == '--weighted') {
                        isWeighted = true;
                    } else if (argv[i] == '--if') {
                        calculateIncidenceFidelity = true;
                    } else if (argv[i] == '--create') {
                        createGraph = true;
                    } else if (argv[i] == '--directed') {
                        isDirected = true;
                    } else if (argv[i] == '--export') {
                        exportGraph = true;
                    } else if (argv[i] == '--json') {
                        saveInJson = true;
                    } else if (argv[i] == '--loops') {
                        allowLoops = true;
                    } else if (argv[i] == '--topology') {
                        i++;
                        topology = argv[i];
                    } else if (argv[i] == '--prefix') {
                        i++;
                        prefix = argv[i];
                    } else if (argv[i] == '--vertices') {
                        i++;
                        vertices = core.toNumber(argv[i]);
                    } else if (argv[i] == '--edges') {
                        i++;
                        edges = core.toNumber(argv[i]);
                    } else if (argv[i] == '--probability') {
                        i++;
                        probability = core.toNumber(argv[i]);
                    } else if (argv[i] == '--avgdeg') {
                        i++;
                        avgdegree = core.toNumber(argv[i]);
                    } else if (argv[i] == '--minw') {
                        i++;
                        minw = core.toNumber(argv[i]);
                    } else if (argv[i] == '--maxw') {
                        i++;
                        maxw = core.toNumber(argv[i]);
                    } else if (argv[i] == '--minsd') {
                        i++;
                        minsd = core.toNumber(argv[i]);
                    } else if (argv[i] == '--maxsd') {
                        i++;
                        maxsd = core.toNumber(argv[i]);
                    } else if (argv[i] == '--nfiles') {
                        i++;
                        nfiles = core.toNumber(argv[i]);
                    } else if (argv[i] == '--vinc') {
                        i++;
                        vinc = core.toNumber(argv[i]);
                    } else if (argv[i] == '--einc') {
                        i++;
                        einc = core.toNumber(argv[i]);
                    } else if (argv[i] == '--dinc') {
                        i++;
                        dinc = core.toNumber(argv[i]);
                    } else {
                        inputFile = argv[i];
                        break;
                    }
                    i++;
                }
                system.argv = argv.slice(i);
                system.argc = system.argv.length;

                if (createGraph) {
                    if (topology == '') {
                        topology = 'random';
                    }
                    if (prefix == '') {
                        prefix = topology;
                    }
                    for (var i = 1; i <= nfiles; i++) {
                        property = {
                            'adj': [],
                            'n': 0,
                            'm': 0,
                            'directed': false,
                            'networkLabel': [],
                            'networkDegree': [],
                            'networkAverageDegree': 0,
                            'networkDegreeDistribution': [],
                            'networkDensity': 0,
                            'networkClustering': [],
                            'networkAverageClustering': 0,
                            'networkShortestPath': [],
                            'networkAverageShortestPath': 0,
                            'networkDiameter': 0,
                            'networkCentrality': [],
                            'networkVertexEfficiency': [],
                            'networkGlobalEfficiency': 0
                        };

                        property.adj = cna.createNetwork(topology, vertices, edges, probability, avgdegree);
                        var fileIndex = string.sprintf('%0' + core.toString(core.length(core.toString(nfiles))) + '.' + core.toString(core.length(core.toString(nfiles))) + 'd', i);
                        var pajekFileContents = cna.createPajekFile(property.adj, 'edges');
                        if (saveInJson) {
                            var outputFileName = prefix + '-' + fileIndex + '.json';
                            var jsonContents = cna.pajekFileToJson(pajekFileContents);
                            var outputFileContents = JSON.stringify(jsonContents);
                        } else {
                            var outputFileName = prefix + '-' + fileIndex + '.net';
                            var outputFileContents = pajekFileContents;
                        }
                        fs.writeFile(outputFileName, outputFileContents, function(err) {
                            if (err) {
                                throw err;
                            }
                        });
                        if (vinc != 0) {
                            vertices = vertices + vinc;
                        }
                        if (einc != 0) {
                            edges = edges + einc;
                        }
                        if (dinc != 0) {
                            avgdegree = avgdegree + dinc;
                        }
                    }
                }

                if (inputFile != '') {
                    var Glob = require('glob');
                    // Process each file based on glob pattern.
                    function processFiles(er, files) {
                        if (files.length == 0) {
                            system.log('CNATool Command Line Interface (CLI)');
                            system.log('Usage: cnatool [options] [network.net] [--] [arguments]');
                        } else {
                            property = {
                                'adj': [],
                                'n': 0,
                                'm': 0,
                                'directed': false,
                                'networkLabel': [],
                                'networkDegree': [],
                                'networkAverageDegree': 0,
                                'networkDegreeDistribution': [],
                                'networkDensity': 0,
                                'networkClustering': [],
                                'networkAverageClustering': 0,
                                'networkShortestPath': [],
                                'networkAverageShortestPath': 0,
                                'networkDiameter': 0,
                                'networkCentrality': [],
                                'networkVertexEfficiency': [],
                                'networkGlobalEfficiency': 0
                            };
                            var graphsData = [];
                            var csvData = 'fileName' +
                                          columnSeparator +
                                          'n' +
                                          columnSeparator +
                                          'm' +
                                          columnSeparator +
                                          'networkAverageDegree' +
                                          columnSeparator +
                                          'networkDensity' +
                                          columnSeparator +
                                          'networkAverageClustering' +
                                          columnSeparator +
                                          'networkAverageShortestPath' +
                                          columnSeparator +
                                          'networkDiameter' +
                                          columnSeparator +
                                          'networkGlobalEfficiency' +
                                          '\r\n';
                            var logData = 'fileName' + columnSeparator + 'elapsedTime' + '\r\n';
                                
                            for (var i = 0; i < files.length; i++) {
                                file = files[i];
                                
                                var fileName = file.split('.').shift();
                                var fileExtension = file.split('.').pop();

                                if (propertiesFile == '') {
                                    propertiesFile = fileName + '-properties.json';
                                }

                                var fileContents = read(String(file));

                                if (buildGraph) {
                                    if (topology == '') {
                                        topology = 'chain';
                                    }

                                    var outputFileName = fileName + '-net.json';
                                    
                                    if (isDirected) {
                                        property.directed = true;
                                    }
                                    
                                    if (fileExtension == 'json') {
                                        var jsonData = JSON.parse(fileContents);
                                        graphsData = snet.createFromJson(jsonData, property, topology, isWeighted, allowLoops);
                                    } else {
                                        graphsData = snet.createFromDlf(fileContents, property, topology, isWeighted, allowLoops);
                                    }

                                    if (calculateIncidenceFidelity) {
                                        var ifDataOutputFileName = fileName + '-if.json';
                                        var ifData = snet.calculateIncidenceFidelity(graphsData,true);

                                        fs.writeFile(ifDataOutputFileName, JSON.stringify(ifData), function(err) {
                                            if (err) {
                                                throw err;
                                            }
                                        });

                                        var ifDataCsvOutputFileName = fileName + '-if.csv';
                                        var ifCsvData = ''

                                        ifCsvData += 'Network file: ' + fileName + '\n';
                                        ifCsvData += 'Total of sentences: ' + ifData.numberOfSentences + '\n';
                                        ifCsvData += 'Vocabulary: ' + ifData.vocabulary + '\n';
                                        ifCsvData += 'Vocabulary / Number of sentences: ' + ifData.vocabularyByNumberOfSentences + '\n';
                                        ifCsvData += '\n';
                                        ifCsvData += 'Id;Pair;QtSentencesPhi;QtSentencesPsi;FreqOfPair;Incidence;Fidelity;IF\n';

                                        for (j = 0; j < ifData.rows.length; j++) {
                                            var row = ifData.rows[j].join(';');
                                            ifCsvData += row + '\n';
                                        }
                                        
                                        fs.writeFile(ifDataCsvOutputFileName, ifCsvData, function(err) {
                                            if (err) {
                                                throw err;
                                            }
                                        });
                                    }

                                    var dansityDataCsvOutputFileName = fileName + '-density.csv';
                                    var densityCsvData = ""
                                    for (k = 0; k < graphsData.density.length; k++) {
                                        let density = graphsData.density[k]
                                        densityCsvData = densityCsvData + density + "\r\n"
                                    }
                                    fs.writeFile(dansityDataCsvOutputFileName, densityCsvData, function(err) {
                                        if (err) {
                                            throw err;
                                        }
                                    });

                                    fs.writeFile(outputFileName, JSON.stringify(graphsData), function(err) {
                                        if (err) {
                                            throw err;
                                        }
                                    });
                                } else {
                                    if (!exportGraph) {
                                        if (outputFile == '') {
                                            outputFile = fileName + '.html';
                                        }

                                        if (fileExtension == 'csv') {
                                            property.adj = cna.parseMatrixFile(fileContents, property, columnSeparator, replaceCommas);
                                        } else if (fileExtension == 'json') {
                                            var network = JSON.parse(fileContents);
                                            var pajekFileContents = cna.jsonToPajekFile(network);
                                            property.adj = cna.parsePajekFile(pajekFileContents, property);
                                        } else if (fileExtension == 'net') {
                                            property.adj = cna.parsePajekFile(fileContents, property);
                                        } else {
                                            system.log('Unsupported file format when processing file ' + file + '');
                                        }

                                        if (isDirected) {
                                            property.directed = true;
                                        }

                                        system.log('Processing file: ' + file + ' ...\n');
                                        if (onlyAvgShortestpath) {
                                            var startTime = new Date();
                                            cnatool.calculateAverageShortestPath(property, useGPU);
                                            var endTime = new Date();
                                        } else {
                                            var startTime = new Date();
                                            cnatool.calculateProperties(property, useGPU);
                                            var endTime = new Date();
                                        }
                                        var elapsedTime = endTime - startTime;
                                        system.log('Elapsed time: ' + elapsedTime + ' ms\n');

                                        var html = '<!DOCTYPE html>';
                                        html = html + '<html lang="en"><head><meta charset="UTF-8"><title>Network Properties Report' + file + '</title></head>';
                                        html = html + '<body>';
                                        if ((property.n > 0) && (property.m > 0)) {
                                            html = html + cnatool.getSummaryReport(property, !onlyAvgShortestpath);
                                            if (includeDegrees || includeAll) {
                                                html = html + cnatool.getDegreesReport(property);
                                            }
                                            if (includeClustering || includeAll) {
                                                html = html + cnatool.getClusteringReport(property);
                                            }
                                            if (includeCentralities || includeAll) {
                                                html = html + cnatool.getCentralitiesReport(property);
                                            }
                                        }
                                        html = html + '</body>';
                                        html = html + '</html>';
                                        fs.writeFile(outputFile, html, function(err) {
                                            if (err) {
                                                throw err;
                                            }
                                        });
                                    } else {
                                        var outputFileType = 'edges';

                                        if (isDirected) {
                                            outputFileType = 'arcs'
                                        }

                                        if (fileExtension == 'csv') {
                                            property.adj = cna.parseMatrixFile(fileContents, property, columnSeparator, replaceCommas);

                                            var dimAdj = core.dim(property.adj);
                                            var dimJ = dimAdj[0];
                                            var dimK = dimAdj[1];
                                            
                                            if (!allowLoops) {
                                                for (var j = 1; j < dimJ; j++) {
                                                    for (var k = 1; k < dimK; k++) {
                                                        if (j == k) {
                                                            property.adj[j][k] = 0;
                                                        }
                                                    }
                                                }
                                            }
                                            
                                            minValue = matrix.min(property.adj, 1, 1, dimJ - 1, dimK - 1);
                                            maxValue = matrix.max(property.adj, 1, 1, dimJ - 1, dimK - 1);
                                            var mtxAvgDev = matrix.avg(property.adj, 1, 1, dimJ - 1, dimK - 1);

                                            var avgReport = '';
                                            avgReport += 'Min: ' + minValue + '\n';
                                            avgReport += 'Max: ' + maxValue + '\n';
                                            avgReport += 'Avg: ' + mtxAvgDev.avg + '\n';
                                            avgReport += 'Dev: ' + mtxAvgDev.dev + '\n';
                                            
                                            if (minsd === '') {
                                                if (minw === '') {
                                                    minw = minValue;
                                                }
                                            } else {
                                                minw = mtxAvgDev.avg + (mtxAvgDev.dev / 100.0) * minsd;
                                                avgReport += 'Factor (avg + ' + minsd + ' * dev / 100): ' + minw + '\n';
                                            }
                                            if (maxsd === '') {
                                                if (maxw === '') {
                                                    maxw = maxValue;
                                                }
                                            } else {
                                                maxw = mtxAvgDev.avg + (mtxAvgDev.dev / 100.0) * maxsd;
                                                avgReport += 'Factor (avg + ' + maxsd + ' * dev / 100): ' + maxw + '\n';
                                            }

                                            for (var j = 1; j < dimJ; j++) {
                                                for (var k = 1; k < dimK; k++) {
                                                    if ((property.adj[j][k] < minw) || (property.adj[j][k] > maxw)) {
                                                        property.adj[j][k] = 0;
                                                    }
                                                }
                                            }

                                            var outputFileContents = cna.createPajekFile(property.adj, outputFileType);
                                        } else if (fileExtension == 'json') {
                                            var network = JSON.parse(fileContents);
                                            property.n = network.nodes.length;
                                            property.m = network.edges.length;
                                            var outputFileContents = cna.jsonToPajekFile(network, outputFileType);
                                        } else {
                                            system.log('Unsupported file format when processing file ' + file + '');
                                            var outputFileContents = '';
                                        }
                                        
                                        var outputFileName = fileName + '.net';
                                        fs.writeFile(outputFileName, outputFileContents, function(err) {
                                            if (err) {
                                                throw err;
                                            }
                                        });

                                        if (avgReport != '') {
                                            if (avgReport != undefined) {
                                                var outputFileName = fileName + '-average.txt';
                                                fs.writeFile(outputFileName, avgReport, function(err) {
                                                    if (err) {
                                                        throw err;
                                                    }
                                                });
                                            }
                                        }
                                    }
                                    
                                    if (propertiesFile != '') {
                                        fs.writeFile(propertiesFile, JSON.stringify(property), function(err) {
                                            if (err) {
                                                throw err;
                                            }
                                        });
                                    }

                                    outputFile = '';
                                    propertiesFile = '';

                                    if (csvFile != '') {
                                        csvData += file +
                                                columnSeparator +
                                                property.n +
                                                columnSeparator +
                                                property.m +
                                                columnSeparator +
                                                property.networkAverageDegree +
                                                columnSeparator +
                                                property.networkDensity +
                                                columnSeparator +
                                                property.networkAverageClustering +
                                                columnSeparator +
                                                property.networkAverageShortestPath +
                                                columnSeparator +
                                                property.networkDiameter +
                                                columnSeparator +
                                                property.networkGlobalEfficiency +
                                                '\r\n';
                                    }
                                    if (jsonFile != '') {
                                        graphProperty = {
                                            'fileName': file,
                                            'properties': {
                                                'n': property.n,
                                                'm': property.m,
                                                'networkAverageDegree': property.networkAverageDegree,
                                                'networkDensity': property.networkDensity,
                                                'networkAverageClustering': property.networkAverageClustering,
                                                'networkAverageShortestPath': property.networkAverageShortestPath,
                                                'networkDiameter': property.networkDiameter,
                                                'networkGlobalEfficiency': property.networkGlobalEfficiency
                                            }
                                        };
                                        graphsData.push(graphProperty);
                                    }
                                    if (logFile != '') {
                                        logData += file + columnSeparator + elapsedTime + '\r\n';
                                    }
                                }
                            }
                            
                            if (csvFile != '') {
                                fs.writeFile(csvFile, csvData, function(err) {
                                    if (err) {
                                        throw err;
                                    }
                                });
                            }
                            if (jsonFile != '') {
                                fs.writeFile(jsonFile, JSON.stringify(graphsData), function(err) {
                                    if (err) {
                                        throw err;
                                    }
                                });
                            }
                            if (logFile != '') {
                                fs.writeFile(logFile, logData, function(err) {
                                    if (err) {
                                        throw err;
                                    }
                                });
                            }
                        }
                    }

                    options = {};

                    // Get all file names based on glob pattern.
                    var glob = new Glob(inputFile, options, processFiles);
                } else {
                    if (!createGraph) {
                        system.log('CNATool Command Line Interface (CLI)');
                        system.log('Usage: cnatool [options] [network.net] [--] [arguments]');
                    }
                }
            } else {
                system.log('CNATool Command Line Interface (CLI)');
                system.log('Usage: cnatool [options] [network.net] [--] [arguments]');
            }
        }
    }
}

cnatool = new CNATool();

/*
 * Run CNATool code if this script has been invoked
 * from the command line.
 */
if (typeof process !== 'undefined') {
    // Emulate DOM.
    const jsdom = require('jsdom');
    const {
        JSDOM
    } = jsdom;
    var doc = new JSDOM();
    var DOMParser = doc.window.DOMParser;

    var alert = system.log;

    cnatool.run();
}