gonum.org/v1/gonum@v0.14.0/graph/path/dynamic/dumper_test.go (about)

     1  // Copyright ©2015 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package dynamic
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"sort"
    12  	"text/tabwriter"
    13  
    14  	"gonum.org/v1/gonum/graph/path/internal/testgraphs"
    15  	"gonum.org/v1/gonum/graph/simple"
    16  )
    17  
    18  // dumper implements a grid D* Lite statistics dump.
    19  type dumper struct {
    20  	step int
    21  
    22  	dStarLite *DStarLite
    23  	grid      *testgraphs.LimitedVisionGrid
    24  
    25  	w io.Writer
    26  }
    27  
    28  // dump writes a single step of a D* Lite path search to the dumper's io.Writer.
    29  func (d *dumper) dump(withpath bool) {
    30  	if d == nil {
    31  		return
    32  	}
    33  	var pathStep map[int64]int
    34  	if withpath {
    35  		pathStep = make(map[int64]int)
    36  		path, _ := d.dStarLite.Path()
    37  		for i, n := range path {
    38  			pathStep[n.ID()] = i
    39  		}
    40  	}
    41  	fmt.Fprintf(d.w, "Step:%d kₘ=%v\n", d.step, d.dStarLite.keyModifier)
    42  	d.step++
    43  	w := tabwriter.NewWriter(d.w, 0, 0, 0, ' ', tabwriter.Debug)
    44  	rows, cols := d.grid.Grid.Dims()
    45  	for r := 0; r < rows; r++ {
    46  		if r == 0 {
    47  			for c := 0; c < cols; c++ {
    48  				if c != 0 {
    49  					fmt.Fprint(w, "\t")
    50  				}
    51  				fmt.Fprint(w, "-------------------")
    52  			}
    53  			fmt.Fprintln(w)
    54  		}
    55  		for ln := 0; ln < 6; ln++ {
    56  			for c := 0; c < cols; c++ {
    57  				if c != 0 {
    58  					fmt.Fprint(w, "\t")
    59  				}
    60  				n := d.dStarLite.model.Node(d.grid.NodeAt(r, c).ID()).(*dStarLiteNode)
    61  				switch ln {
    62  				case 0:
    63  					if n.ID() == d.grid.Location.ID() {
    64  						if d.grid.Grid.HasOpen(n.ID()) {
    65  							fmt.Fprintf(w, "id:%2d  >@<", n.ID())
    66  						} else {
    67  							// Mark location as illegal.
    68  							fmt.Fprintf(w, "id:%2d  >!<", n.ID())
    69  						}
    70  					} else if n.ID() == d.dStarLite.t.ID() {
    71  						fmt.Fprintf(w, "id:%2d   G", n.ID())
    72  						// Mark goal cell as illegal.
    73  						if !d.grid.Grid.HasOpen(n.ID()) {
    74  							fmt.Fprint(w, "!")
    75  						}
    76  					} else if pathStep[n.ID()] > 0 {
    77  						fmt.Fprintf(w, "id:%2d  %2d", n.ID(), pathStep[n.ID()])
    78  						// Mark path cells with an obstruction.
    79  						if !d.grid.Grid.HasOpen(n.ID()) {
    80  							fmt.Fprint(w, "!")
    81  						}
    82  					} else {
    83  						fmt.Fprintf(w, "id:%2d", n.ID())
    84  						// Mark cells with an obstruction.
    85  						if !d.grid.Grid.HasOpen(n.ID()) {
    86  							fmt.Fprint(w, "   *")
    87  						}
    88  					}
    89  				case 1:
    90  					fmt.Fprintf(w, "h:  %.4v", d.dStarLite.heuristic(n, d.dStarLite.Here()))
    91  				case 2:
    92  					fmt.Fprintf(w, "g:  %.4v", n.g)
    93  				case 3:
    94  					fmt.Fprintf(w, "rhs:%.4v", n.rhs)
    95  				case 4:
    96  					if n.g != n.rhs {
    97  						fmt.Fprintf(w, "key:%.3f", n.key)
    98  					}
    99  					if !n.key.isBadKey() {
   100  						// Mark keys for nodes in the priority queue.
   101  						// We use NaN inequality for this check since all
   102  						// keys not in the queue must have their key set
   103  						// to badKey.
   104  						//
   105  						// This should always mark cells where key is
   106  						// printed.
   107  						fmt.Fprint(w, "*")
   108  					}
   109  					if n.g > n.rhs {
   110  						fmt.Fprint(w, "^")
   111  					}
   112  					if n.g < n.rhs {
   113  						fmt.Fprint(w, "v")
   114  					}
   115  				default:
   116  					fmt.Fprint(w, "-------------------")
   117  				}
   118  			}
   119  			fmt.Fprintln(w)
   120  		}
   121  	}
   122  	w.Flush()
   123  	fmt.Fprintln(d.w)
   124  }
   125  
   126  // printEdges pretty prints the given edges to the dumper's io.Writer using the provided
   127  // format string. The edges are first formatted to a string, so the format string must use
   128  // the %s verb to indicate where the edges are to be printed.
   129  func (d *dumper) printEdges(format string, edges []simple.WeightedEdge) {
   130  	if d == nil {
   131  		return
   132  	}
   133  	var buf bytes.Buffer
   134  	sort.Sort(lexically(edges))
   135  	for i, e := range edges {
   136  		if i != 0 {
   137  			fmt.Fprint(&buf, ", ")
   138  		}
   139  		fmt.Fprintf(&buf, "%d->%d:%.4v", e.From().ID(), e.To().ID(), e.Weight())
   140  	}
   141  	if len(edges) == 0 {
   142  		fmt.Fprint(&buf, "none")
   143  	}
   144  	fmt.Fprintf(d.w, format, buf.Bytes())
   145  }
   146  
   147  type lexically []simple.WeightedEdge
   148  
   149  func (l lexically) Len() int { return len(l) }
   150  func (l lexically) Less(i, j int) bool {
   151  	return l[i].From().ID() < l[j].From().ID() || (l[i].From().ID() == l[j].From().ID() && l[i].To().ID() < l[j].To().ID())
   152  }
   153  func (l lexically) Swap(i, j int) { l[i], l[j] = l[j], l[i] }