// Graph converts an HMM Net object to a graph where states are nodes. Like // an HMM net, the graph contains a single entry and exit non-emmiting state. func (m *Net) Graph() *graph.Graph { g := graph.New() // Create nodes. for i := 0; i < m.ns; i++ { var entry, exit bool if i == 0 { entry = true } if i == m.ns-1 { exit = true } key := m.Name + "-" + strconv.FormatInt(int64(i), 10) nv := nodeValue{scorer: m.B[i], entry: entry, exit: exit} g.Set(key, nv) } // Connect nodes. for i := 0; i < m.ns; i++ { fromKey := m.Name + "-" + strconv.FormatInt(int64(i), 10) for j := i; j < m.ns; j++ { if m.A.At(i, j) > math.Inf(-1) { toKey := m.Name + "-" + strconv.FormatInt(int64(j), 10) g.Connect(fromKey, toKey, m.A.At(i, j)) } } } return g }
// SearchGraph creates a graph based on a set of HMM networks. func (set *Set) SearchGraph() *graph.Graph { glog.Infof("building search graph using %d hmms", set.size()) g := graph.New() for _, m := range set.Nets { glog.Infof("adding model [%s]", m.Name) err := g.Add(m.Graph()) if err != nil { glog.Fatalf("failed to build search graph with error: ", err) } } // Log prob of model in search graph. logp := -math.Log(float64(set.size())) // Start node. Only node with no predescessors. start := g.Set("start", nodeValue{}) // End node. Only no with no successors. end := g.Set("end", nodeValue{}) // Backoff node connects all networks exit states to all entry states. backoff := g.Set("backoff", nodeValue{}) nodes := g.GetAll() for _, n := range nodes { val := n.Value().(nodeValue) if val.entry { // backoff to entry backoff.Connect(n, logp) } if val.exit { // exit to backoff n.Connect(backoff, 0) } } // backoff to end backoff.Connect(end, 0) // start to backoff start.Connect(backoff, 0) // Normalize all transition weights. // TODO glog.Infof("search graph created - num nodes: %d", g.Len()) glog.V(3).Info("search graph:\n", g) return g }