diff --git a/CHANGELOG.md b/CHANGELOG.md index b1780e1..42ffdde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## v0.2.0 +* #12: Add cycle and matrix output to lsap command + * `lsap` provides `-cycles` and `-matrix` flags for assignment forms. + * `ap.Matrix` is now a `[][]int8` instead of `[][]bool`. * #10: Add reduced cost and dual price output to lsap command * `lsap` uses `-dual` and `-rc` flags for dual prices and reduced costs. * #6: Provide Cycle struct and method diff --git a/README.md b/README.md index d0abeb5..42f3ea9 100644 --- a/README.md +++ b/README.md @@ -126,8 +126,12 @@ Usage: ] EOF Flags: + -cycles + output cyclic assignment form -dual output dual prices + -matrix + output matrix assignment form -rc output reduced cost matrix ``` diff --git a/cmd/lsap/lsap.go b/cmd/lsap/lsap.go index bd5495e..98a31ed 100644 --- a/cmd/lsap/lsap.go +++ b/cmd/lsap/lsap.go @@ -27,7 +27,9 @@ func usage() { } func main() { + cycles := flag.Bool("cycles", false, "output cyclic assignment form") dual := flag.Bool("dual", false, "output dual prices") + matrix := flag.Bool("matrix", false, "output matrix assignment form") rc := flag.Bool("rc", false, "output reduced cost matrix") flag.Usage = usage flag.Parse() @@ -44,10 +46,18 @@ func main() { "cost": a.Cost(), } + if *cycles { + out["cycles"] = p.Cycles() + } + if *dual { out["dual"] = a.DualPrices() } + if *matrix { + out["matrix"] = p.Matrix() + } + if *rc { rcMatrix := make([][]int64, len(p)) for u := range p { diff --git a/cycles.go b/cycles.go index 93d5dec..ba2a68a 100644 --- a/cycles.go +++ b/cycles.go @@ -45,7 +45,7 @@ func (c Cycles) Inverse() Cycles { func (c Cycles) Matrix() Matrix { m := make(Matrix, c.len()) for u := range m { - m[u] = make([]bool, len(m)) + m[u] = make([]int8, len(m)) } for _, cycle := range c { @@ -54,7 +54,7 @@ func (c Cycles) Matrix() Matrix { if i < len(cycle)-1 { v = cycle[i+1] } - m[u][v] = true + m[u][v] = 1 } } diff --git a/cycles_test.go b/cycles_test.go index 3987056..149c245 100644 --- a/cycles_test.go +++ b/cycles_test.go @@ -16,12 +16,6 @@ func ExampleCycles() { // Output: // [[0 1] [2] [3 6 4 5]] // [[0 1] [2] [3 5 4 6]] - // - X - - - - - - // X - - - - - - - // - - X - - - - - // - - - - - - X - // - - - - - X - - // - - - X - - - - // - - - - X - - + // [[0 1 0 0 0 0 0] [1 0 0 0 0 0 0] [0 0 1 0 0 0 0] [0 0 0 0 0 0 1] [0 0 0 0 0 1 0] [0 0 0 1 0 0 0] [0 0 0 0 1 0 0]] // [1 0 2 6 5 3 4] } diff --git a/matrix.go b/matrix.go index 28cb207..89a9920 100644 --- a/matrix.go +++ b/matrix.go @@ -1,10 +1,8 @@ package ap -import "strings" - // Matrix representation of an assignment. If u is assigned to v, then M[u][v] // is true. Each row and each column has exactly one true element. -type Matrix [][]bool +type Matrix [][]int8 // Cycles converts a permutation matrix to a cyclic representation. func (m Matrix) Cycles() Cycles { @@ -21,7 +19,7 @@ func (m Matrix) Permutation() Permutation { p := make(Permutation, len(m)) for u, mu := range m { for v, assigned := range mu { - if assigned { + if assigned == 1 { p[u] = v break } @@ -29,22 +27,3 @@ func (m Matrix) Permutation() Permutation { } return p } - -func (m Matrix) String() string { - s := make([]string, len(m)) - for u, mu := range m { - s[u] = rowString(mu) - } - return strings.Join(s, "\n") -} - -func rowString(row []bool) string { - s := make([]string, len(row)) - for i, v := range row { - s[i] = "-" - if v { - s[i] = "X" - } - } - return strings.Join(s, " ") -} diff --git a/matrix_test.go b/matrix_test.go index d868592..d171129 100644 --- a/matrix_test.go +++ b/matrix_test.go @@ -8,13 +8,13 @@ import ( func ExampleMatrix() { m := ap.Matrix{ - {false, true, false, false, false, false, false}, - {true, false, false, false, false, false, false}, - {false, false, true, false, false, false, false}, - {false, false, false, false, false, false, true}, - {false, false, false, false, false, true, false}, - {false, false, false, true, false, false, false}, - {false, false, false, false, true, false, false}, + {0, 1, 0, 0, 0, 0, 0}, + {1, 0, 0, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 1, 0}, + {0, 0, 0, 1, 0, 0, 0}, + {0, 0, 0, 0, 1, 0, 0}, } fmt.Println(m) fmt.Println(m.Cycles()) @@ -22,20 +22,8 @@ func ExampleMatrix() { fmt.Println(m.Permutation()) // Output: - // - X - - - - - - // X - - - - - - - // - - X - - - - - // - - - - - - X - // - - - - - X - - // - - - X - - - - // - - - - X - - + // [[0 1 0 0 0 0 0] [1 0 0 0 0 0 0] [0 0 1 0 0 0 0] [0 0 0 0 0 0 1] [0 0 0 0 0 1 0] [0 0 0 1 0 0 0] [0 0 0 0 1 0 0]] // [[0 1] [2] [3 6 4 5]] - // - X - - - - - - // X - - - - - - - // - - X - - - - - // - - - - - X - - // - - - - - - X - // - - - - X - - - // - - - X - - - + // [[0 1 0 0 0 0 0] [1 0 0 0 0 0 0] [0 0 1 0 0 0 0] [0 0 0 0 0 1 0] [0 0 0 0 0 0 1] [0 0 0 0 1 0 0] [0 0 0 1 0 0 0]] // [1 0 2 6 5 3 4] } diff --git a/permutation.go b/permutation.go index 9436744..be7dadd 100644 --- a/permutation.go +++ b/permutation.go @@ -49,8 +49,8 @@ func (p Permutation) Inverse() Permutation { func (p Permutation) Matrix() Matrix { m := make(Matrix, len(p)) for u, v := range p { - m[u] = make([]bool, len(p)) - m[u][v] = true + m[u] = make([]int8, len(p)) + m[u][v] = 1 } return m } diff --git a/permutation_test.go b/permutation_test.go index 03dbff2..1a16914 100644 --- a/permutation_test.go +++ b/permutation_test.go @@ -17,11 +17,5 @@ func ExamplePermutation() { // [1 0 2 6 5 3 4] // [[0 1] [2] [3 6 4 5]] // [1 0 2 5 6 4 3] - // - X - - - - - - // X - - - - - - - // - - X - - - - - // - - - - - - X - // - - - - - X - - // - - - X - - - - // - - - - X - - + // [[0 1 0 0 0 0 0] [1 0 0 0 0 0 0] [0 0 1 0 0 0 0] [0 0 0 0 0 0 1] [0 0 0 0 0 1 0] [0 0 0 1 0 0 0] [0 0 0 0 1 0 0]] }