/*
  
  GRAPHS - graph theory package for Maxima
  Copyright (C) 2007 Andrej Vodopivec <andrej.vodopivec@gmail.com>

  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 of the License, or	 
  (at your option) any later version. 

  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.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/


/*********************
 *
 * Chromatic polynomial
 *
 *********************/

chromatic_polynomial(gr, x) :=
if graph_order(gr)=0 then x^graph_size(gr)
else  block(
  [comp],
  comp : connected_components(gr),
  if length(comp)>1 then (
    comp : map(lambda([u], chromatic_polynomial(induced_subgraph(u, gr), x)), comp),
    expand(apply("*", comp)))
  else if graph_order(gr)=graph_size(gr)-1 then x*(x-1)^graph_order(gr)
  else if graph_order(gr)=graph_size(gr)*(graph_size(gr)-1)/2 then c_poly_complete(graph_size(gr),x)
  else if min_degree(gr)[1]=2 and max_degree(gr)[1]=2 then c_poly_cycle[graph_size(gr)](x)
  else block(
    [g1, g2, u, v, p1, p2, e],
    u : max_degree(gr)[2],
    v : first(neighbors(u, gr)),
    e : [min(u,v), max(u,v)],
    g1 : copy_graph(gr),
    g2 : copy_graph(gr),
    remove_edge(e, g1),
    contract_edge(e, g2),
    p1 : chromatic_polynomial(g1, x),
    p2 : chromatic_polynomial(g2, x),
    p1-p2))$

c_poly_cycle[1](x) := x$
c_poly_cycle[3](x) := x*(x-1)*(x-2)$
c_poly_cycle[n](x) := x*(x-1)^(n-1)-c_poly_cycle[n-1](x)$
c_poly_complete(n,x) := apply("*", makelist(x-i, i, 0, n-1))$

/*******************
 *
 *  Matching polynomial
 *
 *******************/

matching_polynomial(gr, x) := (
  if max_degree(gr)[1]<3 then
    matching_polynomial_simple(gr, x)
  else block(
    [g1 : copy_graph(gr), g2 : copy_graph(gr), md, mv],
    md : max_degree(g1),
    mv : md[2],
    md : md[1],
    u : first(neighbors(mv, g1)),
    remove_vertex(mv, g1),
    remove_vertex(u, g1),
    remove_edge([u, mv], g2),
    matching_polynomial(g2, x) - matching_polynomial(g1, x)))$

matching_polynomial_simple(gr, x) := block(
  [conn, pol : 1, c, deg, u],
  conn : connected_components(gr),
  for c in conn do (
    deg : apply(min,
      args(map(lambda([u], vertex_degree(u, gr)), c))),
    if deg=2 then pol : pol * cycle_poly(length(c), x)
    else pol : pol * path_poly[length(c)](x)),
  expand(pol))$

cycle_poly(n, x) := path_poly[n](x) - path_poly[n-2](x)$
path_poly[1](x) := x$
path_poly[2](x) := x^2-1$
path_poly[n](x) := x*path_poly[n-1](x) - path_poly[n-2](x)$
