#  Copyright (c) 1997-2010
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
#  http://www.polymake.de
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------
#  $Project: polymake $$Id: algebraic_types 9558 2010-03-10 14:47:10Z sherrmann $


declare property_type Vector<Element> : c++ (operators => '@arith | |= @compare') {

   method construct(Int) : c++;

   user_method dim() : c++;

   user_method slice(*) : lvalue_opt : c++;

   user_method slice($$) : lvalue_opt : c++;

   user_method div_exact(*) : lvalue : c++;
}

property_type Vector<Float> {
   
   type()->equal=sub { (typeof Array<Float>)->equal->(@_) };
}

function permuted(Vector, *) : c++;

function permuted_inv(Vector, *) : c++;

function _convert_to<Element>(*) : c++ (name => 'convert_to');


# @category Arithmetic

user_function gcd(Vector) : c++;


# @category Data conversion
# Convert to different element type if needed.

user_function convert_to<Element>(Vector) {
   my $target_type=typeof Element;
   if ($_[0]->type->param==$target_type) {
      $_[0]
   } else {
      _convert_to<Element>($_[0]);
   }
}

##################################################################################

declare property_type Matrix<Element> : c++ (operators => '@arith | |= @compare') {

   method construct(Int,Int) : c++;

   method construct(Vector+) {
      my $proto=shift;
      my $M=$proto->construct->(scalar(@_), $_[0]->dim);
      my $i=0;
      $M->[$i++]=$_ for @_;
      $M;
   }

   user_method rows() : c++;

   user_method cols() : c++;

   user_method row($) : lvalue_opt : c++;

   user_method col($) : lvalue_opt : c++;

   user_method minor(*,*) : lvalue_opt : c++;

   method operator($,$) : lvalue_opt : c++;

   user_method diagonal() : lvalue_opt : c++;

   user_method anti_diagonal() : lvalue_opt : c++;

   user_method div_exact(*) : lvalue : c++;
}

property_type Matrix<Float> {

   type()->equal=sub { (typeof Array<Array<Float>>)->equal->(@_) };
}

declare property_type all_rows_or_cols : c++ (name => 'pm::all_selector', builtin => enum { All }, include => ["Matrix.h"]);


# @category Data conversion

user_function vector2row(Vector) : c++ (include => ["Matrix.h"]);


# @category Data conversion

user_function vector2col(Vector) : c++ (include => ["Matrix.h"]);


# @category Linear Algebra

user_function diag(Vector) : c++ (include => ["SparseMatrix.h"]);


# @category Linear Algebra

user_function diag(*,*) : c++ (include => ["SparseMatrix.h"]);


# @category Linear Algebra

user_function anti_diag(Vector) : c++ (include => ["SparseMatrix.h"]);


# @category Linear Algebra

user_function anti_diag(*,*) : c++ (include => ["SparseMatrix.h"]);

function permuted_rows(Matrix, *) : c++;

function permuted_inv_rows(Matrix, *) : c++;

function permuted_cols(Matrix, *) : c++;

function permuted_inv_cols(Matrix, *) : c++;


# @category Data conversion

user_function convert_to<Element>(Matrix) {
   my $target_type=typeof Element;
   if ($_[0]->type->param==$target_type) {
      $_[0]
   } else {
      _convert_to<Element>($_[0]);
   }
}


# @category Linear Algebra

user_function transpose(Matrix) : c++ (name => 'T');


# @category Linear Algebra

user_function det(Matrix) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function rank(Matrix) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function inv(Matrix) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function normalized(Matrix) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function basis(Matrix) : returns(@) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function basis_affine(Matrix) : returns(@) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function basis_rows(Matrix) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function basis_cols(Matrix) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function unit_matrix<Element=Rational>($) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function unit_vector<Element=Rational>($$) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function zero_vector<Element=Rational>(;$=0) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function ones_vector<Element=Rational>(;$=0) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function null_space(Matrix) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function null_space(Vector) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function lineality_space(Matrix) : c++ (include => ["linalg.h"]);


# @category Linear Algebra

user_function lin_solve(Matrix,Vector) : c++ (include => ["linalg.h"]);


# @category Linear Algebra
# Check whether both matrices are bases of the same linear subspace.

user_function equal_bases(Matrix, Matrix) {
   my ($M1, $M2)=@_;
   return $M1->rows==$M2->rows && !(null_space($M1) * transpose($M2));
}

user_function dense(Vector) { shift }

user_function dense(Matrix) { shift }


# @category Combinatorics

user_function permutation_matrix(*) : c++ (include => ["permutations.h"]);

##################################################################################

declare property_type SparseIterator<*> : Iterator : c++ {

   method index() : c++;
}

declare property_type SparseVector<Element> : Vector<Element> : c++ {

   user_method size() : c++;
}

declare property_type SparseMatrix<Element, Sym=NonSymmetric> : Matrix<Element> : c++ {

   user_method squeeze() : non_const : void : c++;

   user_method squeeze_rows() : non_const : void : c++;

   user_method squeeze_cols() : non_const : void : c++;
}

function entire(SparseVector) : c++ : returns(SparseIterator<*>);

# @category Data conversion
# Convert to an equivalent dense vector of the same element type
# @param SparseVector v
user_function dense<Element>(SparseVector<Element>) { new Vector<Element>(shift) }

# @category Data conversion
# Convert to an equivalent dense matrix of the same element type
# @param SparseMatrix m
user_function dense<Element>(SparseMatrix<Element>) { new Matrix<Element>(shift) }


# @category Data conversion

user_function toVector<Scalar>(Set $) : c++ (name => 'same_element_sparse_vector', include => ['SparseVector.h']);


# @category Data conversion

user_function toMatrix<Scalar>(IncidenceMatrix) : c++ (name => 'same_element_sparse_matrix', include => ['SparseMatrix.h']);

# @category Data conversion
# Convert to a dense 0/1 matrix
# @param IncidenceMatrix m
user_function dense(IncidenceMatrix) { dense(toMatrix<Int>(@_)); }

# @category Data conversion
# Convert to a dense 0/1 vector of a given dimension
# @param Set s
# @param Int dim
user_function dense(Set $) { dense(toVector<Int>(@_)); }

##################################################################################

##declare property_type MaxPlusRational : c++ (operators => ' bool @arith @compare') {

##   function ONE() : c++ (name => 'MaxPlusRational::ONE', include => ["MaxPlusRational.h"]);

##   function ZERO() : c++ (name => 'MaxPlusRational::ZERO', include => ["MaxPlusRational.h"]);
   
##   user_method get_value() : c++;
##}

##user_function isfinite(MaxPlusRational) : c++ (include => ["MaxPlusRational.h"]);

##user_function isinf(MaxPlusRational) : c++ (include => ["MaxPlusRational.h"]);

##################################################################################

declare property_type Ring<Coefficient=Rational, Exponent=Int> : c++ (operators => '== !=', default_constructor => 0) {

   # either a number of variables, a single name, or a list of names given per reference
   method construct(*) : c++;

   # number of variables and the name stem
   method construct(Int,$) : c++;

   # list of names
   method construct($$@) {
      (shift)->construct->(\@_);
   }

   user_method variables() : returns(@) : c++ (include => ["Polynomial.h"]);

   user_method variable() : c++ (include => ["Polynomial.h"]);

   user_method names() : c++;

   method id() : c++;
}

declare property_type Monomial<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv ^ ^= @compare', include => ["Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(Vector,Ring) : c++;
}

declare property_type UniMonomial<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv ^ ^= @compare', include => ["Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(*,Ring) : c++;
}

declare property_type Term<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv @compare', include => ["Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(Vector,*,Ring) : c++;
}

declare property_type UniTerm<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv @compare', include => ["Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(*,Ring) : c++;
}

declare property_type Polynomial<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv @compare') {

   method construct(Ring) : c++;

   method construct(*,Ring) : c++;

   method construct(Matrix,*,Ring) : c++;

   user_method lm_exp() : c++;

   user_method lc() : c++;
}

declare property_type UniPolynomial<Coefficient=Rational,Exponent=Int> : c++ \
   (operators => '@arith_nodiv @compare', include => ["Polynomial.h"]) {

   method construct(Ring) : c++;

   method construct(*,Ring) : c++;

   method construct(*,*,Ring) : c++;

   user_method lm_exp() : c++;

   user_method lc() : c++;
}

# Local Variables:
# mode: perl
# c-basic-offset:3
# End:
