module Groebner

  def self.basis_132A(g)
    gbasis = g.dup
    record = {}
    loop do
      flag = false
      gbasis.each_pair_with_index do |x, y, i, j|
	next if record[[i, j]]
	s = (x|y) % gbasis
	if s.zero?
	  record[[i, j]] = true
	else
	  gbasis.push s
	  flag = true
	  break
	end
      end
      break unless flag
    end 
    gbasis
  end

  def self.basis_132B(g)
    gbasis = g.dup
    record = {}
    loop do
      flag = false
      gbasis.each_pair_with_index do |x, y, i, j|
	if record[[i, j]]
	  next
	else
	  record[[i, j]] = true
	end
	s = (x|y) % gbasis
	unless s.zero?
	  gbasis.push s
	  flag = true
	  break
	end
      end
      break unless flag
    end 
    gbasis
  end

  def self.basis_132C(b)
    gbasis = []
    i, j = 1, 0
    b.each do |x|
      gbasis.push x
      while i < gbasis.size
	s = (gbasis[i]|gbasis[j]) % gbasis
	gbasis.push s if !s.zero?
	i, j = j < i-1 ? [i, j+1] : [i+1, 0]
      end
    end
    gbasis
  end

  def self.basis_coeff_132_A(g)
    gbasis = g.dup
    n0 = g.size
    coeff = (0...n0).collect{|k| [0]*k+[1]+[0]*(n0-k-1)}
    record = {}
    loop do
      flag = false
      gbasis.each_pair_with_index do |x, y, i, j|
	next if record[[i, j]]
	t, a, b = x.S_pair_coeff(y)
	q, s = t.divmod(*gbasis)
	if s.zero?
	  record[[i, j]] = true
	else
	  u = (0...n0).collect {|k| sum = 0
	    (0...gbasis.size).each do |m|
	      d = (m == i ? a-q[m] : (m == j ? b-q[m] : -q[m]))
	      sum += d * coeff[m][k]
	    end
	    sum
	  }
	  coeff.push u
	  gbasis.push s
	  flag = true
	  break
	end
      end
      break unless flag
    end
    [coeff, gbasis]
  end

  def self.minimal_basis_coeff_A(coeff, gbasis)
    indexes = (0...gbasis.size).to_a
    loop do
      flag = false
      indexes.each do |i|
	others = gbasis.indices(*(indexes-[i])).collect{|x| x.lt}
	if (gbasis[i].lt % others).zero?
	  indexes.delete(i)
	  coeff.delete(i)
	  flag = true
	  break
	end
      end
      break unless flag
    end
    b = gbasis.indices(*indexes)
    c = coeff.indices(*indexes)
    [c, b]
  end

  def self.reduced_basis_coeffA(coeff, gbasis)
    indexes = (0...gbasis.size).to_a
    indexes.each do |i|
      others = gbasis.indices(*(indexes-[i]))
      q, gbasis[i] = gbasis[i].divmod(*others)
      coeff[i] = (0...coeff[i].size).collect {|k| sum = 0
	(0...gbasis.size).each do |m|
	  d = (m < i ? -q[m] : m == i ? 1 : -q[m-1])
	  sum += d * coeff[m][k]
	end
	sum
      }
    end
    gbasis.each_with_index do |x, i|
      c = x.lc
      coeff[i].collect!{ |v| v / c}
      gbasis[i] = x / c
    end
    [coeff, gbasis]
  end


end
