#ifndef i2_H
#define i2_H

/* Operations on points and vectors of Z^2 */
/* Last edited on 2011-12-24 01:57:16 by stolfilocal */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>

#include <vec.h>

/* OVERFLOW

  Many of the operations below may overflow if the scalar arguments
  (including scale factors and vector coordinates) are too large in
  absolute value.
  
  The "Input MMax:" information in the comments below is the maximum {M} such
  that the ouput is guaranteed correct as long as all input scalars
  are in the symmetric range {[-M..+M]}.
  
  The "Output range:" information is the smallest symmetric range that contains
  the output scalars when the input scalars and
  coordinates span the symmetric range {[-M..+M]}.
  
  Note that signed {int2_t} variables naturally have an *asymmetric* range
  {[-N..N-1]} where {N = 2^31}. */

typedef struct { int32_t c[2]; } i2_t;

void i2_zero (i2_t *r);
  /* Sets {r} to the zero vector. */
  
void i2_all (int32_t x, i2_t *r);
  /* Sets all coordinates of {r} to the value {x}. */
  
void i2_axis (int i, i2_t *r);
  /* Sets {r} to the {i}th vector of the canonical basis. */

void i2_add (i2_t *a, i2_t *b, i2_t *r);
  /* Sets {r = a + b}. Input MMax: {2^30-1}. Output range: {-2*M..+2*M}. */

void i2_sub (i2_t *a, i2_t *b, i2_t *r);
  /* Sets {r = a - b}. Input MMax: {2^30-1}. Output range: {-2*M..+2*M}. */

void i2_neg (i2_t *a, i2_t *r);
  /* Sets {r} to {-a}. Input MMax: {2^31-1}. Output range: {-M..+M}. */

int32_t i2_L_inf_norm (i2_t *a);
  /* Returns the L-infinity norm of {a} (max absolute coordinate).
    Input MMax: {2^31-1}. Output range: {0..+M}. */

int32_t i2_L_inf_dist (i2_t *a, i2_t *b);
  /* Returns the L-infinity distance between {a} and {b} (max absolute diff).
    Input MMax: {2^30-1}. Output range: {0..+2*M}. */

int64_t i2_norm_sqr (i2_t *a);
  /* Returns the square of the Euclidean norm of {a}. 
    Input MMax: {2^31-1}. Output range: {0..+2*M^2}.
    !!! Perhaps should be {uint64_t}? !!! */

int64_t i2_dist_sqr (i2_t *a, i2_t *b);
  /* Returns the square of the Euclidean distance between {a} and {b}.
    Input MMax: {2^30-1}. Output range: {0..+8*M^2}.
    !!! Perhaps should be {uint64_t}? !!! */

int64_t i2_dot (i2_t *a, i2_t *b);
  /* Dot product of vectors {a} and {b}. 
    Input MMax: {2^30-1}. Output range: {-2*M^2 .. +2*M^2}. */

void i2_cross (i2_t *a, i2_t *r);
  /* Returns in {r} the vector {a} rotated 90 degrees counterclockwise. 
    Input MMax: {2^31-1}. Output range: {-M .. +M}. */

int64_t i2_det (i2_t *a, i2_t *b);
  /* Returns the determinant of the 2x2 matrix whose rows are {a,b}.  
    Input MMax: {2^30-1}. Output range: {-2*M^2 .. +2*M^2}. */

int i2_eq(i2_t *p, i2_t *q);
  /* True iff points {p} and {q} are identical. */

void i2_print (FILE *f, i2_t *a);
  /* Prints {a} on file {f}, with some default format. */

void i2_gen_print (FILE *f, i2_t *a, char *fmt, char *lp, char *sep, char *rp);
  /* Prints {a} on file {f}, formatting each coordinate with {fmt}. 
    The strings {lp}, {sep}, and {rp} are printed respectively before,
    between, and after all the coordinates of {a}.  When NULL, they default 
    to "%d", "(", " ", and ")", respectively. */

vec_typedef(i2_vec_t,i2_vec,i2_t);
  /* An {i2_vec_t} is a vector of {i2_t}s. */

#endif
