# code to compute correction terms of lens spaces
# our convention is opposite to Ozsvath-Szabo's, in the sense that $L(p,q)$ is $-p/q$ surgery on the unknot.
# the labelling of spin^c structures on $L(p,q)$ follows O-Sz.

class Fraction

  public
  attr_reader :p, :q

  def initialize(p,q) # q is always going to be positive.
    if q<0
      initialize(-p,-q)
    else
      d = p.gcd(q)
      @p = p/d
      @q = q/d
    end
  end

  def to_s
    if self.q == 1 then self.p.to_s else self.p.to_s + "/" + self.q.to_s end
  end

  def + other
    Fraction.new(self.p*other.q + self.q*other.p, self.q*other.q)
  end

  def - other
    Fraction.new(self.p*other.q - self.q*other.p, self.q*other.q)
  end

end

class DInvariant

  attr_reader :d
  
  def initialize(p,q,i)
    if p==1
      @d = Fraction.new(0,1)
    else
      t = 2*i+1-p-q
#      print q.to_s + " " + (p%q).to_s + " " + (i%q).to_s + " " + DInvariant.new(q,p%q,i%q).to_s + "\n"
      @d = Fraction.new(p*q-t*t,4*p*q) - DInvariant.new(q,p%q,i%q).d
    end
  end

  def to_s
    self.d.to_s
  end

end

class DInvariants

  attr_reader :p, :q

  def initialize(p,q)
    @p = p
    @q = q
  end

  def to_s
    string = "i   d(L(" + p.to_s + "," + q.to_s + "),i)\n"
    for i in 0..p-1
      string = string + i.to_s + "    " + DInvariant.new(p,q,i).to_s + "\n"
    end
    string
  end

end

continue = true;

print "This program computes the correction terms of lens spaces.\nBy convention, L(p,q) is the oriented 3-manifold obtained as -p/q surgery on the unknot.\nATTENTION: this convention is opposite to Ozsvath and Szabo's convention, but is consistent with most of the literature on 3-manifolds.\nFor us, L(p,q) will always have 0<q<p, and p and q will be coprime.\nSpin^c structures on L(p,q) will be indexed according to Ozsvath and Szabo \"Absolutely graded Floer homologies intersection forms for four-manifolds with boundary\" (the indexing takes into account the orientation-reversal issue, so that structures are labelled by reversing the orientation first).\n\n"

while(continue == true) do

  print "Choose one of the following options:\n"
  print "(1) Compute a single correction term d(L(p,q),i);\n"
  print "(2) Compute all correction terms for L(p,q) with p,q fixed;\n"
  print "(3) Compute all correction terms of all L(p,q) with p fixed;\n"
  print "(4) Compute all correction terms of all L(p,q) with p <= N;\n"
  print "(5) Compute all correction terms d(L(p,q),0) with p fixed;\n"
  print "(6) Quit.\n"

  option = gets.to_i

  case option
  when 1
    puts "You've chosen to compute d(L(p,q),i) (p,q,i fixed).\nInsert p>0:\n"
    p = gets.to_i
    if p==1
      puts "d(L(1,0),0) = 0\n"
    else
      puts "Insert 0<q<p (relatively prime to p):\n"
      q = gets.to_i
      puts "Insert the label of the Spin^c structure, 0 <= i < p:\n"
      i = gets.to_i
      puts "\nd(L(" + p.to_s + "," + q.to_s + ")," + i.to_s + ") = " + DInvariant.new(p,q,i).to_s + "\n"
    end
  when 2
    puts "You've chosen to compute d(L(p,q),i) as i varies (p,q fixed).\nInsert p>0:\n"
    p = gets.to_i
    puts "Insert 0<q<p (relatively prime to p):\n"
    q = gets.to_i
    puts DInvariants.new(p,q).to_s
  when 3
    puts "You've chosen to compute d(L(p,q),i) as i and q vary (p fixed).\nInsert p>1:\n"
    p = gets.to_i
    for q in 1..p-1
      if q.gcd(p) == 1 then puts DInvariants.new(p,q).to_s + "\n" end
    end
  when 4
    puts "You've chosen to compute d(L(p,q),i) as p, q and i vary (2 <= p <= N).\nInsert N>1:\n"
    N = gets.to_i
    for p in 1..N
      for q in 1..p-1
        if q.gcd(p) == 1 then puts DInvariants.new(p,q).to_s + "\n" end
      end
    end
  when 5
    puts "You've chosen to compute d(L(p,q),0) as q varies (p fixed).\nInsert p>1:\n"
    p = gets.to_i
    for q in 1..p-1
      if q.gcd(p) == 1 then puts "d(L(" + p.to_s + "," + q.to_s + "),0) = " + DInvariant.new(p,q,0).to_s + "\n" end
    end
  when 6
    continue = false
  else
    puts "Choice not valid."
  end
end

