func (self *Sax) build_letter_compare_dict() {
  number_rep := rangeIntArray(0, self.alphabetSize)
  letters := make([]string, len(number_rep))  
  for i, x := range number_rep {
    letters[i] = string(rune(x + int(self.aOffset)))
  }
  self.compareDict = make(map[string]float64)
  for i := 0; i < len(letters); i++ {
    for j := 0; j < len(letters); j++ {
      if math.Abs(float64(number_rep[i] - number_rep[j])) <= 1 {
        self.compareDict[letters[i] + letters[j]] = 0
      } else {
        high_num := int(math.Max(float64(number_rep[i]), float64(number_rep[j])) - 1)
        low_num := int(math.Min(float64(number_rep[i]), float64(number_rep[j])))
        self.compareDict[letters[i] + letters[j]] = self.beta[high_num] - self.beta[low_num]
      }
    }
  }
}
/*
Builds up the lookup table to determine numeric distance between two letters
given an alphabet size.  Entries for both 'ab' and 'ba' will be created
and will have identical values.
package gosax
import (
  "errors"
  "math"
  "strconv"
  "strings"
)
var ErrDictionarySizeIsNotSupported = errors.New("Dictionary size not supported")
var ErrStringsAreDifferentLength = errors.New("StringsAreDifferentLength")
var ErrOverlapSpecifiedIsNotSmallerThanWindowSize = errors.New("OverlapSpecifiedIsNotSmallerThanWindowSize")
type Sax struct {
  aOffset       rune
  wordSize      int
  alphabetSize  int
  eps           float64
  breakpoints   map[string][]float64
  beta          []float64
  scalingFactor float64
  compareDict   map[string]float64
  windowSize    int
}
func NewSax(wordSize int, alphabetSize int, epsilon float64) (*Sax, error) {
  if alphabetSize < 3 || alphabetSize > 20 {
    return nil, ErrDictionarySizeIsNotSupported
  }
  self := Sax{}
  self.aOffset = 'a'
  self.wordSize = wordSize
  self.alphabetSize = alphabetSize
  self.eps = epsilon
  self.breakpoints = make(map[string][]float64)
  self.breakpoints["3"] = []float64{-0.43, 0.43}
  self.breakpoints["4"] = []float64{-0.67, 0, 0.67}
  self.breakpoints["5"] = []float64{-0.84, -0.25, 0.25, 0.84}
  self.breakpoints["6"] = []float64{-0.97, -0.43, 0, 0.43, 0.97}
  self.breakpoints["7"] = []float64{-1.07, -0.57, -0.18, 0.18, 0.57, 1.07}
  self.breakpoints["8"] = []float64{-1.15, -0.67, -0.32, 0, 0.32, 0.67, 1.15}
  self.breakpoints["9"] = []float64{-1.22, -0.76, -0.43, -0.14, 0.14, 0.43, 0.76, 1.22}
  self.breakpoints["10"] = []float64{-1.28, -0.84, -0.52, -0.25, 0, 0.25, 0.52, 0.84, 1.28}
  self.breakpoints["11"] = []float64{-1.34, -0.91, -0.6, -0.35, -0.11, 0.11, 0.35, 0.6, 0.91, 1.34}
  self.breakpoints["12"] = []float64{-1.38, -0.97, -0.67, -0.43, -0.21, 0, 0.21, 0.43, 0.67, 0.97, 1.38}
  self.breakpoints["13"] = []float64{-1.43, -1.02, -0.74, -0.5, -0.29, -0.1, 0.1, 0.29, 0.5, 0.74, 1.02, 1.43}
  self.breakpoints["14"] = []float64{-1.47, -1.07, -0.79, -0.57, -0.37, -0.18, 0, 0.18, 0.37, 0.57, 0.79, 1.07, 1.47}
  self.breakpoints["15"] = []float64{-1.5, -1.11, -0.84, -0.62, -0.43, -0.25, -0.08, 0.08, 0.25, 0.43, 0.62, 0.84, 1.11, 1.5}
  self.breakpoints["16"] = []float64{-1.53, -1.15, -0.89, -0.67, -0.49, -0.32, -0.16, 0, 0.16, 0.32, 0.49, 0.67, 0.89, 1.15, 1.53}
  self.breakpoints["17"] = []float64{-1.56, -1.19, -0.93, -0.72, -0.54, -0.38, -0.22, -0.07, 0.07, 0.22, 0.38, 0.54, 0.72, 0.93, 1.19, 1.56}
  self.breakpoints["18"] = []float64{-1.59, -1.22, -0.97, -0.76, -0.59, -0.43, -0.28, -0.14, 0, 0.14, 0.28, 0.43, 0.59, 0.76, 0.97, 1.22, 1.59}
  self.breakpoints["19"] = []float64{-1.62, -1.25, -1, -0.8, -0.63, -0.48, -0.34, -0.2, -0.07, 0.07, 0.2, 0.34, 0.48, 0.63, 0.8, 1, 1.25, 1.62}
  self.breakpoints["20"] = []float64{-1.64, -1.28, -1.04, -0.84, -0.67, -0.52, -0.39, -0.25, -0.13, 0, 0.13, 0.25, 0.39, 0.52, 0.67, 0.84, 1.04, 1.28, 1.64}
  self.beta = self.breakpoints[strconv.Itoa(self.alphabetSize)]
  self.build_letter_compare_dict()
  self.scalingFactor = 1
  return &self, nil
}
func mean(xs[]float64) float64 {
  total := 0.0
  for _, v := range xs {
    total += v
  }
  return total / float64(len(xs))
}
func stdDev(numbers []float64, mean float64) float64 {
  total := 0.0
  for _, number := range numbers {
    total += math.Pow(number - mean, 2)
  }
  variance := total / float64(len(numbers) - 1)
  return math.Sqrt(variance)
}
func (self *Sax) normalize(measureList []float64) []float64 {
  var err error
  if len(measureList) < 1 {
    return measureList
  }
  s2 := float64(1)
  m2 := float64(0)
  m1 := mean(measureList)
  if err != nil {
    panic(err)
  }
  s1 := stdDev(measureList, m1)
  if err != nil {
    panic(err)
  }
  stdMultiplier := (s2 / s1)
  for i, m := range measureList {
    measureList[i] = float64(m2 + (m - m1)) * stdMultiplier
  }
  return measureList
}
func (self *Sax) ToLetterRepresentation(x []float64) (string, [][]int) {
  paaX, indices := self.toPaa(self.normalize(x))
  self.scalingFactor = math.Sqrt(float64((len(x) * 1.0) / (self.wordSize * 1.0)))
  return self.alphabetize(paaX), indices
}
func (self *Sax) toPaa(x []float64) (approximation []float64, indices [][]int) {
  n := len(x)
  stepFloat := float64(n) / float64(self.wordSize)
  step := int(math.Ceil(stepFloat))
  frameStart := 0
  approximation = []float64{}
  indices = [][]int{}
  i := 0
  for frameStart <= n - step {
    thisFrame := x[frameStart:int(frameStart + step)]
    m := mean(thisFrame)
    approximation = append(approximation, m)
    indices = append(indices, []int{frameStart, int(frameStart + step)})
    i += 1
    frameStart = int(float64(i) * stepFloat)
  }
  return
}
func (self *Sax) alphabetize(paaX []float64) string {
  alphabetizedX := ""
  for i := 0; i < len(paaX); i++ {
    letterFound := false
    for j := 0; j < len(self.beta); j++ {
      if paaX[i] < self.beta[j] {
        alphabetizedX += string(rune(int(self.aOffset) + j))
        letterFound = true
        break
      }
    }
    if !letterFound {
      alphabetizedX += string(rune(int(self.aOffset) + len(self.beta)))
    }
  }
  return alphabetizedX
}
func (self *Sax) CompareStrings(list_letters_a, list_letters_b []byte) (float64, error) {
  if len(list_letters_a) != len(list_letters_b) {
    return 0, ErrStringsAreDifferentLength
  }
  mindist := 0.0
  for i := 0; i < len(list_letters_a); i++ {
    mindist += math.Pow(self.compare_letters(rune(list_letters_a[i]), rune(list_letters_b[i])), 2)
  }
  mindist = self.scalingFactor * math.Sqrt(mindist)
  return mindist, nil
}
func (self *Sax) compare_letters(la, lb rune) float64 {
  return self.compareDict[string(la) + string(lb)]
}
func rangeIntArray(start, end int) []int {
  x := make([]int, end - start)
  for i := start; i < end; i++ {
    x[i] = i
  }
  return x
}