/* Copyright © 2025 filifa This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package cmd import ( "errors" "fmt" "os" idot "scm.dairydemon.net/filifa/gv2adj/cmd/internal/graph/dot" "github.com/spf13/cobra" "gonum.org/v1/gonum/graph/encoding/dot" "gonum.org/v1/gonum/mat" ) var file string var matlabFmt bool var pythonFmt bool var oneline bool var weightAttr string var nodeOrder []string // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "gv2adj", Short: "A brief description of your application", Long: `A longer description that spans multiple lines and likely contains examples and usage of using your application. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, // Uncomment the following line if your bare application // has an action associated with it: Run: parse, } func parse(cmd *cobra.Command, args []string) { data, err := os.ReadFile(file) if err != nil { panic(err) } graph := idot.NewDOTDirectedGraph(weightAttr) err = dot.UnmarshalMulti(data, graph) if err != nil { panic(err) } matrix, err := orderedAdjMatrix(graph) if err != nil { panic(err) } outputMatrix(matrix) } func orderedAdjMatrix(g *idot.DOTDirectedGraph) (*mat.Dense, error) { matrix := g.AdjacencyMatrix() if len(nodeOrder) == 0 { return matrix, nil } nodeIndexes := make(map[string]int) for i := 0; i < len(nodeOrder); i++ { nodeIndexes[nodeOrder[i]] = i } nodes := g.Nodes() newOrder := make([]int, nodes.Len()) for nodes.Next() { node := nodes.Node().(*idot.Node) id := node.DOTID() var ok bool newOrder[node.ID()], ok = nodeIndexes[id] if !ok { return nil, errors.New("node '" + id + "' not in given order") } } matrix.PermuteRows(newOrder, true) matrix.PermuteCols(newOrder, true) return matrix, nil } func outputMatrix(matrix mat.Matrix) { fmtOptions := make([]mat.FormatOption, 0) if matlabFmt { fmtOptions = append(fmtOptions, mat.FormatMATLAB()) } else if pythonFmt { fmtOptions = append(fmtOptions, mat.FormatPython()) } out := mat.Formatted(matrix, fmtOptions...) // for matlab and python formats, %#v outputs as matrix and %v is // oneline, but for standard format, it's the opposite, so we xor if (matlabFmt || pythonFmt) != oneline { fmt.Printf("%#v\n", out) } else { fmt.Printf("%v\n", out) } } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { err := rootCmd.Execute() if err != nil { os.Exit(1) } } func init() { // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.gv2adj.yaml)") // Cobra also supports local flags, which will only run // when this action is called directly. rootCmd.Flags().StringVarP(&file, "file", "f", "", "dot file") rootCmd.MarkFlagRequired("file") rootCmd.Flags().BoolVar(&matlabFmt, "matlab", false, "format output as MATLAB array") rootCmd.Flags().BoolVar(&pythonFmt, "python", false, "format output as python array") rootCmd.MarkFlagsMutuallyExclusive("matlab", "python") rootCmd.Flags().BoolVar(&oneline, "oneline", false, "output on one line") rootCmd.Flags().StringVar(&weightAttr, "weight-attr", "len", "edge attribute to use as weight") rootCmd.Flags().StringSliceVarP(&nodeOrder, "order", "o", nil, "order of nodes in rows/columns of output") }