#
# The main function in this file is the routine relpoly.
# It computes the reliability polynomial a(p) for the so called
# ``all-terminal reliability network''.  Such a network is
# modelled by a graph with multiple edges and with a
# probability p of failure on each edge.  The polynomial a(p)
# gives the probability that the network is spanned in the
# presence of edge failures, i.e. the probability that
# each node remains connected to each other node.
#
# EXAMPLE:
#
# The function relpoly_clique(N,p) shows how to construct a graph G
# for input to the relpoly(G,p) routine, in this case, a clique on
# N vertices.  Here are some examples
#
# > relpoly_clique(3,p);
#
#                                     2      3
#                                  3 p  - 2 p
#
# > relpoly_clique(4,p); # for a clique with 4 vertices
#
#                              3       4       5      6
#                          16 p  - 33 p  + 24 p  - 6 p
#
#
# SEE ALSO: ?networks,spanpoly  (in Maple V Release 2 note)
#
# Author: Michael Monagan, monagan@inf.ethz.ch
#

# Input a(p) reliability polynomial of degree d with probability p of failure
# Ouput a(p) = sum( N[k]*p^k*(1-p)^(d-k), k=0..d )
F := proc(a,p) local d,i,j,k,N;
	d := degree(a,p);
	for k from 0 to d do
	    N[k] := coeff(a,p,k);
	    for i to k do
		N[k] := N[k] - (-1)^i*binomial(d+i-k,i)*N[k-i]
	    od
	od;
	convert( [seq( N[j]*p^j*(1-p)^(d-j), j=0..d )], `+` );
end:

#
#--> relpoly(G,p)
#
# Compute the reliability polynomial a(p) from the Graph G on N vertices
# The input graph G should be input as a list of N polynomials in the vertices
# X[i], i=1..N, where the c = coeff(G[i],X[j]) gives the multiplicity
# of the edges from vertex i to j.
# The input p is the edge probability and N is the number of vertices.
#
relpoly := proc(G,p) local n;
    if not type(G,'list(polynom(nonnegint))') then
	ERROR(`The input graph must be a list of polynomials with \
non-negative integer coeffients`,G)
    fi;
    n := nops(G);
    reliability(G,p,n)
end:

reliability := proc(G,p,n) local c,d,k,u,v,w,t,H;

	# Choose first vertex of minimum degree
	d := n;
	for k to nops(G) while d > 0 do
	    if G[k] <> infinity then 
		c := nops(indets(G[k]));
	        if c < d then d := c; u := k fi
	    fi;
	od;

	if d = 0 then if n = 1 then RETURN(1) else RETURN(0) fi fi;
	v := op(1,op(1,indets(G[u]))); c := coeff(G[u],X[v],1);

	if d = 1 then		# Isolated node contraction
		H := subsop( u=infinity, v=G[v]-c*X[u], G );
		RETURN( expand( (1-(1-p)^c) * reliability(H,p,n-1) ) )
	fi;

	# First delete the edge of multiplicity c between vertices u and v
	# (All edges between u and v have failed with probability (1-p)^c)
	H := subsop( u=G[u]-c*X[v], v=G[v]-c*X[u], G );
	t := (1-p)^c * reliability(H,p,n);

	# Now contract vertices u and v (at least one edge has not failed)
	H := subsop( u=infinity, v=H[u]+H[v], subs(X[u]=X[v],H) );
	t := expand( (1-(1-p)^c) * reliability(H,p,n-1) + t );

	# Now remember this computation
	reliability(G,p,n) := t;

end:

# This is a utility routine to insert the edge u v into the graph G.
# G should be initialized to vector (array) of N zeroes.
# The third argument m specifies the multiplicity of the edge
insert := proc(G,u,v,m)
    if nargs = 3 then insert(G,u,v,1) else
	G[u] := G[u]+m*X[v];
	G[v] := G[v]+m*X[u];
	NULL
    fi
end:

# relpoly_clique(N,p); computes the reliability polynomial for
# a clique on N vertices with edge failure probability p
relpoly_clique := proc(N,p) local G,i,j;
    G := array([0$N]);
    for i to N-1 do for j from i+1 to N do insert(G,i,j) od od;
    G := convert(G,list):
    relpoly(G,p);
end:

# relpoly_loop(N,p); computes the reliability polynomial for
# a simply cycle on N vertices with edge failure probability p
relpoly_loop := proc(N,p) local G,i;
    G := array([0$N]);
    for i to N-1 do insert(G,i,i+1) od;
    insert(G,N,1);
    G := convert(G,list):
    relpoly(G,p);
end:

# The reliability polynomial for the Red Arpanet
relpoly_RedArpanet := proc(p) local N,G;
    N := 20;
    G := array([0$N]):
    insert(G,1,2):
    insert(G,1,3):
    insert(G,2,3):
    insert(G,2,4):
    insert(G,3,5):
    insert(G,4,5):
    insert(G,4,6):
    insert(G,6,7):
    insert(G,5,7):
    insert(G,1,8):
    insert(G,8,9):
    insert(G,9,10):
    insert(G,9,11):
    insert(G,10,11):
    insert(G,7,10):
    insert(G,6,11):
    insert(G,8,12):
    insert(G,10,15):
    insert(G,11,20):
    insert(G,12,13):
    insert(G,13,14):
    insert(G,14,15):
    insert(G,13,15):
    insert(G,14,18):
    insert(G,12,16):
    insert(G,15,17):
    insert(G,16,17):
    insert(G,16,18):
    insert(G,17,19):
    insert(G,18,19):
    insert(G,18,20):
    insert(G,19,20):
    G := convert(G,list);
    relpoly(G,p)
end:

`help/text/relpoly` := TEXT(
`FUNCTION: relpoly - reliability (spanning) polynomial of an undirected graph`,
`   `,`CALLING SEQUENCE: relpoly(G,p)`,`   `,`PARMETERS:   `,
`   G - an undirected graph`,
`   p - expression (usually a variable) for the edge probability`,`   `,
`SYNOPSIS:   `,`   `,
`- relpoly(G,p) computes the reliability polynomial a(p) for the so called`,` \
 ````all-terminal reliability network''.  Such a network is modelled by a grap\
h`,`  G with multiple edges and with a probability p of failure on each edge.`,
`  The polynomial a(p) gives the probability that the network is spanned in`,
`  the presence of edge failures, i.e. the probability that each node remains`,
`  connected to each other node.`,`   `,
`- The graph G is an undirected graph on N vertices.  It is input as a`,
`  list of N polynomials in the vertices X[i], i=1..N, where`,`   `,
`  c = coeff(G[i],X[j])`,`   `,
`  gives the multiplicity of the edges from vertex i to j.`,
`  The input p is the edge probability and N is the number of vertices.`,`   `,
`- This function has the same functionality as the routine spanpoly in the`,
`  networks package (in the Maple library).  It is simply much must faster.`,
`  Note relpoly assumes that the probability of failure on each edge is the`,
`  same accross the network.`,`   `,`EXAMPLES:   `,`   `,
`# A clique with with vertices`,
`> G := [ X[2]+X[3]+X[4], X[1]+X[3]+X[4], X[1]+X[2]+X[4], X[1]+X[2]+X[3] ]:`,
`> ac4 := relpoly(G,p);`,`   `,
`                                 3       4       5      6`,
`                      ac4 := 16 p  - 33 p  + 24 p  - 6 p`,`   `,
`# A loop with four vertices`,
`> G := [ X[4]+X[2], X[1]+X[3], X[2]+X[4], X[3]+X[1] ]:`,
`> al4 := relpoly(G,p);`,`   `,
`                                         3      4`,
`                               al4 := 4 p  - 3 p`,`   `,
`# A tree with four vertices`,`> G := [ X[2]+X[3], X[1]+X[4], X[1], X[2] ]:`,
`> at4 := relpoly(G,p);`,`   `,`                                           3`,
`                                   at4 := p`,`   `,
`# Where obviously the clique should be more reliable than the loop which in`,
`# turn should be more reliable than the tree.`):

#save `relpoly.m`;
#quit
