func (lm *landmark) isPriorLandmarkTo(otherSeqs []bool, otherPositions []int32) bool {
	for i, use := range lm.seqs {
		if use && otherSeqs[i] && otherPositions[i] < lm.positions[i] {
			return false
		}
	}
	return true
}
isPriorLandmarkTo is a strict ordering, assuming positions exactly match the landmark's kmer
package alignment
import (
	"fmt"
	"github.com/jteutenberg/downpore/sequence"
	"github.com/jteutenberg/downpore/util"
	"math"
	"sort"
)
var initialOffset = int32(8)
var debug = false
type Result struct {
	EndPositions []int32
}
type Aligner interface {
	GlobalConsensus() (<-chan uint16, <-chan *QualityMetrics, <-chan *Result)
	GlobalAlignment() (<-chan uint16, <-chan *QualityMetrics, <-chan []int)
	GlobalAlignmentTo([]uint16) (<-chan uint16, <-chan *QualityMetrics, <-chan []int)
	ConsensusCost([]uint16) uint
}
type Measure interface {
	SetSequences(seqs [][]uint16, rc []bool)
	GetSequences() ([][]uint16, []bool)
	GetSequenceLen(int) int
	Distances(a uint16, sequence, start int, ds []uint16)
}
type QualityMetrics struct {
	ExactFraction  float64
	CostDelta      uint
	StateSpaceSize int
}
type dtw struct {
	maxWarp        int  
	maxCost        uint16
	initialGapCost uint16
	costThreshold  uint16  
	measure        Measure
	full           bool  
	k                 int  
	prevKmers         *util.IntSet
	kMask             uint16
	ds                []uint16  
	landmarks         []*landmark
	expectedPositions []int32
	depth             int32
}
type landmark struct {
	k         uint16
	cost      uint
	seqs      []bool   
	positions []int32  
}
type state struct {
	k            uint16      
	positions    []int32     
	offsets      [][]uint16  
	prev         *state      
	minCost      uint        
	votes        float64     
	spaceSize    int         
	finished     bool        
	nextLandmark int         
	quality      []float64   
}
func (s *state) printOffsets() {
	for j, offsets := range s.offsets {
		for _, off := range offsets {
			if off > 30000 {
				fmt.Print("- ")
			} else {
				fmt.Print(off, " ")
			}
		}
		fmt.Println("\n", s.positions[j])
	}
}
func NewDTWAligner(maxWarp int, initialGapCost uint, measure Measure, full bool, costThreshold uint, k int) Aligner {
	for maxWarp%8 != 0 {
		maxWarp++
	}
	ks := k
	var kMask uint16
	for k > 0 {
		kMask = (kMask << 2) | 0x3
		k--
	}
	d := dtw{maxWarp * 2, uint16(math.MaxUint16 / 2), uint16(initialGapCost), uint16(costThreshold), measure, full, ks, util.NewIntSet(), kMask, make([]uint16, maxWarp*2, maxWarp*2), make([]*landmark, 0, 10), nil, 0}
	return &d
}
func (lm *landmark) matchesLandmark(positions []int32) bool {
	count := 0
	c2 := 0
	for i, use := range lm.seqs {
		if use {
			c2++
			if positions[i] == lm.positions[i] {
				count++
			}
		}
	}
	return count >= c2/2
}
func (lm *landmark) matches(positions []int32) bool {
	count := 0
	c2 := 0
	for i, use := range lm.seqs {
		if use {
			c2++
			if positions[i] >= lm.positions[i]-6 && positions[i] <= lm.positions[i]+6 {
				count++
			}
		}
	}
	return count >= c2/2
}
func (lm *landmark) isPriorTo(positions []int32) bool {
	for i, use := range lm.seqs {
		if use && positions[i]-4 < lm.positions[i] {
			return false
		}
	}
	return true
}