Spicing Up Your Research in Combinatorics with Sage
system:sage


<link type="text/css" rel="stylesheet" href="coast.css" /><div class="maketitle">
                                                                          

                                                                          
                                                                          

                                                                          

<h2 class="titleHead">Spicing Up Your Research in Combinatorics
with Sage</h2>
<div class="author"/><br/>
<div class="date"><span class="cmr-12x-x-120">February 12, 2011</span></div>
</div><div class="center">
<!--l. 16--><p class="noindent">
</p><!--l. 18--><p class="noindent"><span class="cmr-17">Rob Beezer</span><br/>
<span class="cmr-17">University of Puget Sound</span><br/>
<span class="cmr-17">&#160;</span><br class="newline"/><span class="cmr-17">14th Coast Combinatorics Conference</span><br/>
<span class="cmr-17">University of Victoria</span><br/>
</p>
</div>

{{{id=1|

///
}}}

<h3 class="sectionHead"><span class="titlemark">1   </span> <a id="x1-10001"/>Disclaimers</h3><p class="noindent">$&#8729;$ I may
be the wrong person to give this talk!<br class="newline"/>$&#8729;$ Open
source fanatic<br class="newline"/>$&#8729;$
Member, Sage developer community<br class="newline"/>$&#8729;$ Sage
development: linear algebra, graph theory, group theory<br class="newline"/>$&#8729;$ But I
will <span class="cmti-12">try </span>to be objective
</p><h3 class="sectionHead"><span class="titlemark">2   </span> <a id="x1-20002"/>Introduction</h3><ul class="itemize1">
      <li class="itemize">Sage: Open source software for mathematics
      </li>
      <li class="itemize">Mission: &#8220;Creating a viable free open source alternative to Magma,
      Maple, Mathematica and Matlab.&#8221;
      </li>
      <li class="itemize">Consolidates over 100 packages, such as:
           <ul class="itemize2">
           <li class="itemize">NetworkX &#8212; Graph Theory
           </li>
           <li class="itemize">GAP &#8212; Groups, Algorithms, Programming
           </li>
           <li class="itemize">ATLAS &#8212; Automatically Tuned Linear Algebra System
           </li>
           <li class="itemize">IML &#8212; Integer Matrix Library</li></ul>
      </li>
      <li class="itemize">Command Line, Batch, Notebook Interface
                                                                          

                                                                          
      </li>
      <li class="itemize">FREE!</li></ul><p class="noindent">
</p><h3 class="sectionHead"><span class="titlemark">3   </span> <a id="x1-30003"/>Graph Theory</h3><p class="noindent">Create  graphs  in  a  natural  way:
</p>

{{{id=3|
harary = Graph([(0,1), (1,2), (2,3), (3,0), (1,3)])
///
}}}

{{{id=4|
harary
///
}}}

{{{id=5|
harary.plot()
///
}}}

{{{id=6|
harary.num_verts(), harary.num_edges()
///
}}}

{{{id=7|
harary.is_planar()
///
}}}

{{{id=8|
H=harary.hamiltonian_cycle()
H.plot()
///
}}}

{{{id=9|
harary.degree_sequence()
///
}}}

{{{id=10|
sorted(harary.degree_sequence())
///
}}}

<p class="noindent">
</p><h4 class="subsectionHead"><span class="titlemark">3.1   </span> <a id="x1-40003.1"/>Graph Generators</h4><p class="noindent">Many pre-de&#64257;ned graphs (digraphs, too):
</p>

{{{id=12|
graphs.
///
}}}

{{{id=13|
trees_iterator = graphs.trees(8)
T8 = list(trees_iterator)
T8
///
}}}

<p class="noindent">From  a  path  to  a  star:
</p>

{{{id=15|
[tree.diameter() for tree in T8]
///
}}}

<p class="noindent">Visually:
</p>

{{{id=17|
graphs_list.show_graphs(T8)
///
}}}

<p class="noindent">
</p><h4 class="subsectionHead"><span class="titlemark">3.2   </span> <a id="x1-50003.2"/>Tower of Hanoi Graph</h4><div class="center">
<!--l. 118--><p class="noindent">
</p><!--l. 119--><p class="noindent"><img alt="pict" src="4peghanoi.jpg"/>
</p>
</div><p class="noindent">$&#8729;$
<span class="obeylines-h"><span class="verb"><span class="cmtt-12">graphs.HanoiTowerGraph(n,</span><span class="cmtt-12">&#160;d)</span></span></span><br class="newline"/>$&#8729;$ Generalize
to $n$ pegs
and $d$
disks<br class="newline"/>$&#8729;$ State
graph: intermediate con&#64257;gurations, edges are &#8220;one move&#8221;<br class="newline"/>$&#8729;$ Labels:
$d$-tuple,
large disk to small disk; entries are peg numbers<br class="newline"/>$&#8729;$ Example:
$n = 3$,
$d = 4$:
$(2, 0, 2, 1)$<br class="newline"/>
</p>

{{{id=19|
T = graphs.HanoiTowerGraph(3, 4, positions=True)
T.show(figsize=12)
///
}}}

<p class="noindent">A solution is path between states &#8220;all the disks on one peg&#8221; and &#8220;all the disks on another peg.&#8221;
</p>

{{{id=21|
solution=T.shortest_path((0,0,0,0), (1,1,1,1))
solution
///
}}}

<p class="noindent">Minimum  number  of  moves:
</p>

{{{id=23|
len(solution) - 1
///
}}}

{{{id=24|
T.diameter()
///
}}}

<p class="noindent">More  general:
</p>

{{{id=26|
T = graphs.HanoiTowerGraph(4, 3, positions=True)
T.show(figsize=12)
///
}}}

{{{id=27|
T = graphs.HanoiTowerGraph(4, 4, labels=False, positions=True)
T.show(figsize=12)
///
}}}

<p class="noindent">Forget about graphics, work with graph itself.
</p>

{{{id=29|
T = graphs.HanoiTowerGraph(4, 8, labels=False, positions=False)
T.num_verts()
///
}}}

<p class="noindent">Code vertices to integers: $d$-tuples,
base $n$.
All disks on peg 0, move to all disks on peg 3.
</p>

{{{id=31|
solution = T.shortest_path(0, 4^8-1)
solution
///
}}}

{{{id=32|
len(solution)-1
///
}}}

<p class="noindent">Theorem: automorphisms of the state graph are just the obvious ones (renumber pegs)
</p>

{{{id=34|
T = graphs.HanoiTowerGraph(4, 6, labels=False, positions=False)
A = T.automorphism_group()
A.order()
///
}}}

{{{id=35|
S4 = SymmetricGroup(4)
S4.is_isomorphic(A)
///
}}}

<p class="noindent">Automorphisms are computed via Brendan McKay&#8217;s <span class="obeylines-h"><span class="verb"><span class="cmtt-12">nauty</span></span></span> algorithm,
re-implemented as <span class="obeylines-h"><span class="verb"><span class="cmtt-12">NICE</span></span></span>.
</p><h4 class="subsectionHead"><span class="titlemark">3.3   </span> <a id="x1-60003.3"/>Online Help</h4><p class="noindent">Tab-completion, online syntax and tested examples (?), source code (??).
</p>

{{{id=37|
G = graphs.GrotzschGraph()
///
}}}

{{{id=38|
G.degree_seq
///
}}}

<p class="noindent">
</p><h4 class="subsectionHead"><span class="titlemark">3.4   </span> <a id="x1-70003.4"/>Algebraic Graph Theory</h4><p class="noindent">Comprehensive support for groups via GAP. If need be,
can ship <span class="cmti-12">any </span>GAP command directly from Sage to GAP.
</p>

{{{id=40|
P = graphs.PetersenGraph()
A = P.automorphism_group()
A
///
}}}

{{{id=41|
A.order()
///
}}}

{{{id=42|
A.is_transitive()
///
}}}

{{{id=43|
S = A.stabilizer(9); S
///
}}}

{{{id=44|
sg = S.subgroups(); sg
///
}}}

{{{id=45|
[H.order() for H in sg]
///
}}}

{{{id=46|
H.is_isomorphic(DihedralGroup(6))
///
}}}

{{{id=47|
ds = A.derived_series()
///
}}}

{{{id=48|
[K.order() for K in ds]
///
}}}

{{{id=49|
B = ds[1]
B.is_isomorphic(AlternatingGroup(5))
///
}}}

<p class="noindent">Comprehensive support for linear algebra.
</p>

{{{id=51|
A = random_matrix(ZZ, 1000, 1000)
time A.determinant()
///
}}}

{{{id=52|
K = graphs.KneserGraph(8,3)
///
}}}

{{{id=53|
adj = K.adjacency_matrix()
adj
///
}}}

{{{id=54|
K.spectrum()
///
}}}

<p class="noindent">A small &#8220;singular graph.&#8221; (I.&#160;Sciriha, 2007)
</p>

{{{id=56|
S = graphs.CycleGraph(4)
S.add_vertices([4, 5, 6])
S.add_edges([(2,4), (2,5), (2,6)])
S.add_edges([(3,4), (3,5), (3,6)])
S.plot()
///
}}}

{{{id=57|
graph_editor(S)
///
}}}

{{{id=58|
adj = S.adjacency_matrix()
ker = adj.kernel()
ker
///
}}}

<p class="noindent">Notice this is the kernel over the integers, and is computed
as a module. It is easy to upgrade to the rationals.
</p>

{{{id=60|
adjQ = adj.change_ring(QQ)
kerQ = adjQ.kernel()
kerQ
///
}}}

<p class="noindent">A vector space in Sage behaves like a vector space, it has dimension, you can interect two of them, &#8230;
</p>

{{{id=62|
kerQ.
///
}}}

<p class="noindent">
</p><h3 class="sectionHead"><span class="titlemark">4   </span> <a id="x1-80004"/>Combinatorics</h3><p class="noindent">MuPAD-Combinat was sold to MathWorks (i.e.&#160;Matlab) in September 2008.
With foresight, MuPAD contributors had switched to Sage in June 2008. So there
is an active and experienced group contributing combinatorics to Sage as
&#8220;sage-combinat.&#8221;
</p><p class="noindent">The  usual  functions:
</p>

{{{id=64|
stirling_number2(500,30)
///
}}}

{{{id=65|
number_of_derangements(["a", 'b', 'c', 'd', 'e'])
///
}}}

<p class="noindent">The  usual  objects  (note  multisets):
</p>

{{{id=67|
permutations([0,1,1,2,2,2])
///
}}}

{{{id=68|
combinations([0,1,1,2,2,2], 3)
///
}}}

{{{id=69|
derangements(["a", 'b', 'c', 'd', 'e'])
///
}}}

<p class="noindent">Ranking and Unranking (uses classes):<br class="newline"/>(preserve  order  for  <span class="obeylines-h"><span class="verb"><span class="cmtt-12">.rank()</span></span></span>)
</p>

{{{id=71|
C = Combinations(["cat", "dog", "pig", "fox", "bug", "rat"], 3)
///
}}}

{{{id=72|
C.unrank(15)
///
}}}

{{{id=73|
C.rank(['cat', 'dog', 'bug'])
///
}}}

<p class="noindent">Polynomials:<br class="newline"/>A  symbolic  object:
</p>

{{{id=75|
var('t')
p = bernoulli_polynomial(t, 5); p
///
}}}

{{{id=76|
diff(p, t)
///
}}}

{{{id=77|
p.parent()
///
}}}

<p class="noindent">A  function:
</p>

{{{id=79|
var('t')
q(t) = bernoulli_polynomial(t, 5); q
///
}}}

{{{id=80|
q(10)
///
}}}

{{{id=81|
q.parent()
///
}}}

<p class="noindent">A polynomial over the rationals, i.e.&#160;in
$\mathbf{Q}[t]$:
</p>

{{{id=83|
t = polygen(QQ, 't')
r = bernoulli_polynomial(t, 5); r
///
}}}

{{{id=84|
r.is_irreducible()
///
}}}

{{{id=85|
r.factor()
///
}}}

{{{id=86|
r.parent()
///
}}}

<p class="noindent">Lots  of  esoterica:
</p>

{{{id=88|
S = SkewPartitions(4)
s = S[25]; s
///
}}}

{{{id=89|
print s.diagram()
///
}}}

<p class="noindent">Much, much more: crystals, posets, root systems, symmetric functions,
words.
</p><h3 class="sectionHead"><span class="titlemark">5   </span> <a id="x1-90005"/>Goodies</h3><p class="noindent">Excellent  <span class="LATEX">L<span class="A">A</span><span class="TEX">T<span class="E">E</span>X</span></span>support.
</p>

{{{id=91|
latex(integrate(sec(x), x))
///
}}}

{{{id=92|
A = random_matrix(QQ, 4, num_bound=9, den_bound=9)
latex(A)
///
}}}

<p class="noindent"><span class="LATEX">L<span class="A">A</span><span class="TEX">T<span class="E">E</span>X</span></span>&#160;versions  of  graphs:
</p>

{{{id=94|
P = graphs.PetersenGraph()
P.set_latex_options(vertex_shape='diamond', vertex_color='red', vertex_label_color='gold', edge_color='blue')
///
}}}

{{{id=95|
latex(P)
///
}}}

{{{id=96|
from sage.graphs.graph_latex import setup_latex_preamble
setup_latex_preamble()
latex.jsmath_avoid_list('tikzpicture')
///
}}}

<div class="center">
<!--l. 449--><p class="noindent">
</p><!--l. 450--><p class="noindent"><img alt="pict" src="petersen-uvic.png"/></p></div><p class="noindent">Embedded Word Processor (Shift-Click) is <span class="TEX">T<span class="E">E</span>X</span>-aware.
</p>

{{{id=98|
<!--l. 457--><p class="noindent" ></p>
///
}}}

<p class="noindent">Sage<span class="TEX">T<span class="E">E</span>X</span>&#160;&#160;allows you to call Sage to compute values, expressions or plots for
automatic inclusion in your <span class="LATEX">L<span class="A">A</span><span class="TEX">T<span class="E">E</span>X</span></span>&#160;document.
</p><p class="noindent">$&#8729;$ Input:
<span class="obeylines-h"><span class="verb"><span class="cmtt-12">Today&#8217;s</span><span class="cmtt-12">&#160;date</span><span class="cmtt-12">&#160;\$2011-02-12=20110212\$</span><span class="cmtt-12">&#160;factors</span><span class="cmtt-12">&#160;as</span><span class="cmtt-12">&#160;\sage{factor(20110212)}.</span></span></span><br class="newline"/>$&#8729;$ Output:
Today&#8217;s date $2011 &#8722; 02 &#8722; 12 = 20110212$
factors as ${2}^{2} &#8901; {3}^{2} &#8901; 173 &#8901; 3229$.
</p><p class="noindent">Can author in <span class="LATEX">L<span class="A">A</span><span class="TEX">T<span class="E">E</span>X</span></span>&#160;and produce worksheets (this is an example).<br class="newline"/>
</p><h3 class="sectionHead"><span class="titlemark">6   </span> <a id="x1-100006"/>Interacts and Python Extensions</h3><p class="noindent">$&#8729;$ Full
support for any Python package.<br class="newline"/>$&#8729;$
Easy-to-construct interactive demonstrations.
                                                                          

                                                                          
</p><p class="noindent">Code adapted from a demonstration by William Stein
</p>

{{{id=100|
import pylab
A_image = pylab.mean(pylab.imread(DATA + 'mystery.png'), 2)
@interact
def svd_image(i=(1,(1..50)), display_axes=True):
     u,s,v = pylab.linalg.svd(A_image)
     A     = sum(s[j]*pylab.outer(u[0:,j], v[j,0:]) for j in range(i))
     show(matrix_plot(A), axes=display_axes, figsize=(11,5))
     html('<h2>Compressed using %s singular values</h2>'%i)
///
}}}

<p class="noindent">Code from Sage Wiki (Interacts) by Pablo Angulo.
</p>

{{{id=102|
%hide
def animate_contraction(g, e, frames = 12, **kwds):
     v1, v2 = e
     if not g.has_edge(v1,v2):
         raise ValueError, "Given edge not found on Graph"
     ls = []
     posd = g.get_pos()
     for j in range(frames):
         gp = Graph(g)
         posdp = dict(posd)
         p1 = posdp[v1]
         p2 = posdp[v2]
         posdp[v2] = [a*(frames-j)/frames + b*j/frames
                        for a,b in zip(p2,p1)]

         gp.set_pos(posdp)
         ls.append(plot(gp, **kwds))
     return ls

def animate_vertex_deletion(g, v, frames = 12, **kwds):
     kwds2 = dict(kwds)
     if 'vertex_colors' in kwds:
         cs = dict(kwds['vertex_colors'])
         for c, vs in kwds['vertex_colors'].items():
              if v in vs:
                   vs2 = list(vs)
                   vs2.remove(v)
                   cs[c] = vs2
         kwds2['vertex_colors'] = cs
     else:
         kwds2 = dict(kwds)
     g2 = Graph(g)
     posd = dict(g.get_pos())
     del posd[v]
     g2.delete_vertex(v)
     g2.set_pos(posd)
     return [plot(g, **kwds),plot(g2, **kwds2)]*int(frames/2)

def animate_edge_deletion(g, e, frames = 12, **kwds):
     v1, v2 = e
     g2 = Graph(g)
     g2.delete_edge(e)
     return [plot(g, **kwds),plot(g2, **kwds)]*int(frames/2)

def animate_glide(g, pos1, pos2, frames = 12, **kwds):
     ls = []
     for j in range(frames):
         gp = Graph(g)
         pos = {}
         for v in gp.vertices():
              p1 = pos1[v]
              p2 = pos2[v]
              pos[v] = [b*j/frames + a*(frames-j)/frames
                            for a,b in zip(p1,p2)]
         gp.set_pos(pos)
         ls.append(plot(gp, **kwds))
     return ls

def medio(p1, p2):
     return tuple((a+b)/2 for a,b in zip(p1, p2))

def new_color():
     return (0.1+0.8*random(), 0.1+0.8*random(), 0.1+0.8*random())

def animate_minor(g, m, frames = 12, pause = 50, step_time = 100):
     '''Crea una animacin que muestra cmo un grafo tiene un menor m
     '''
     posd = dict(g.get_pos())
     posg = posd.values()
     posm = m.get_pos().values()
     xmax = max(max(x for x,y in posg), max(x for x,y in posm))
     ymax = max(max(y for x,y in posg), max(y for x,y in posm))
     xmin = min(min(x for x,y in posg), min(x for x,y in posm))
     ymin = min(min(y for x,y in posg), min(y for x,y in posm))
     dd = g.minor(m)

     #Set colors
     m_colors = dict((v,new_color()) for v in m.vertices())
     g_colors = dict((m_colors[k],vs)
                            for k,vs in dd.items())

     extra_vs = (set(g.vertices()) -
                   set(v for vs in dd.values()
                          for v in vs))
     g_colors[(0,0,0)] = list(extra_vs)

     #pics contains the frames of the animation
     #no colors at the beggining
     gg = Graph(g)
     pics = [plot(gg)]*frames

     #First: eliminate extra vertices
     for v in extra_vs:
         pics.extend(animate_vertex_deletion(gg, v, frames,
                                 vertex_colors = g_colors))
         gg.delete_vertex(v)
         del posd[v]
         g_colors[(0,0,0)].remove(v)
     del g_colors[(0,0,0)]

     #Second: contract edges
     for color, vs in g_colors.items():
         while len(vs)>1:
              for j in xrange(1,len(vs)):
                   if gg.has_edge(vs[0], vs[j]):
                        break
              pics.extend(animate_contraction(gg, (vs[0], vs[j]), frames,
                                      vertex_colors = g_colors))
              for v in gg.neighbors(vs[j]):
                   gg.add_edge(vs[0],v)
              gg.delete_vertex(vs[j])
              del posd[vs[j]]
              gg.set_pos(posd)
              posd = dict(gg.get_pos())
              del vs[j]

     #Relabel vertices of m so that they match with those of gg
     m = Graph(m)
     dd0 = dict((k, vs[0])
                     for k,vs in dd.items() )
     m.relabel(dd0)


     #Third: glide to position in m
     pos_m = m.get_pos()
     pos_g = gg.get_pos()
     pics.extend(animate_glide(gg, pos_g, pos_m, frames,
                                      vertex_colors = g_colors))
     gg.set_pos(pos_m)

     #Fourth: delete redundant edges
     for e in gg.edges(labels = False):
         if not m.has_edge(e):
              pics.extend(animate_edge_deletion(gg, e, frames,
                                      vertex_colors = g_colors))
              gg.delete_edge(*e)

     #And wait for a moment
     pics.extend([plot(gg, vertex_colors = g_colors)]*frames)

     return animate(pics, xmin = xmin - 0.1, xmax = xmax + 0.1,
                             ymin = ymin - 0.1, ymax = ymax + 0.1)
///
}}}

{{{id=103|
graph_list = {'CompleteGraph4':graphs.CompleteGraph(4),
                'CompleteGraph5':graphs.CompleteGraph(5),
                'CompleteGraph6':graphs.CompleteGraph(6),
                'BipartiteGraph3,3':graphs.CompleteBipartiteGraph(3,3),
                'BipartiteGraph4,3':graphs.CompleteBipartiteGraph(4,3),
                'PetersenGraph':graphs.PetersenGraph(),
                'CycleGraph4':graphs.CycleGraph(4),
                'CycleGraph5':graphs.CycleGraph(5),
                'BarbellGraph(3,2)':graphs.BarbellGraph(3,2)
                }
@interact
def _(u1 = text_control(value='Does this graph'),
       g  = selector(graph_list.keys(), buttons = True),
       u2 = text_control(value='have a minor isomorphic to this other graph:'),
       m  = selector(graph_list.keys(), buttons = True),
       u3 = text_control(value='''? It is has, show it to me,
       with an animation with the following parameters'''),
       frames = slider(1,15,1,4, label = 'Frames per second'),
       step_time = slider(1/10,2,1/10,1, label = 'Seconds per step')):
     g = graph_list[g]
     m = graph_list[m]
     if g == m:
         html('<h3>Please select two different graphs</h3>')
         return
     try:
         a = animate_minor(g, m, frames = frames)
         a.show(delay=100*step_time/frames)
     except ValueError:
         html('''<h3>The first graph have <strong>NO</strong> minor isomorphic to the second</h3>''')
///
}}}

<p class="noindent">
</p><h3 class="sectionHead"><span class="titlemark">7   </span> <a id="x1-110007"/>Miscellaneous</h3><ul class="itemize1">
      <li class="itemize">Cython: a Python-to-C translator, creates core routines in Sage
      </li>
      <li class="itemize">Optimization: CVXOPT, Exact cover with DLX, etc.
      </li>
      <li class="itemize">Active community: $ &#8764;$200
      developers, mathematicians and programmers.
      </li>
      <li class="itemize">Online servers
      </li>
      <li class="itemize">Interfaces to GAP, PARI, Maxima, R, Singular (Python, LaTeX) &#8212; all
      included packages
      </li>
      <li class="itemize">Interfaces  to  Mathematica,  Maple,  Matlab,  Magma,  Axiom,  Kash,
      Macaulay2, MuPad, Octave (not included)
      </li>
      <li class="itemize">More packages: SymPy, NumPy, Linbox, MPFR, MPFI, NTL, eclib,
      ATLAS, FLINT, lcalc, PolyBori PyCrypto, matplotlib</li></ul><p class="noindent">
</p><h3 class="sectionHead"><span class="titlemark">8   </span> <a id="x1-120008"/>Philosophy</h3><p class="noindent">Mathematica: &#8220;Why You Do Not Usually Need to Know about Internals&#8221;<br class="newline"/>In the online Mathematica Documentation Center.
      </p><div class="quote">
      <!--l. 687--><p class="noindent">You should realize at the outset that while knowing about the
      internals  of  Mathematica  may  be  of  intellectual  interest,  it  is
      usually much less important in practice than you might at &#64257;rst
      suppose.
                                                                          

                                                                          
      </p><!--l. 689--><p class="noindent">&#8230;
      </p><!--l. 691--><p class="noindent">Indeed, in almost all practical uses of Mathematica, issues about
      how Mathematica works inside turn out to be largely irrelevant.
      </p><!--l. 693--><p class="noindent">&#8230;
      </p><!--l. 695--><p class="noindent">Particularly  in  more  advanced  applications  of  Mathematica,
      it  may  sometimes  seem  worthwhile  to  try  to  analyze  internal
      algorithms  in  order  to  predict  which  way  of  doing  a  given
      computation  will  be  the  most  e&#64259;cient.  And  there  are  indeed
      occasionally major improvements that you will be able to make
      in speci&#64257;c computations as a result of such analyses.
      </p><!--l. 697--><p class="noindent">But  most  often  the  analyses  will  not  be  worthwhile.  For  the
      internals of Mathematica are quite complicated, and even given a
      basic description of the algorithm used for a particular purpose, it
      is usually extremely di&#64259;cult to reach a reliable conclusion about
      how the detailed implementation of this algorithm will actually
      behave in particular circumstances.</p></div><p class="noindent">J. Neub&#252;ser (Founder of GAP): &#8220;An invitation to computational group
theory.&#8221;<br class="newline"/>In C. M. Campbell, T. C. Hurley, E. F. Robertson, S. J. Tobin, and J. J. Ward,
editors, Groups 93 Galway/St. Andrews, Volume 2, volume 212 of London
Mathematical Society Lecture Note Series, pages 457-475. Cambridge University
Press, 1995.
      </p><div class="quote">
      <!--l. 705--><p class="noindent">You can read Sylow&#8217;s Theorem and its proof in Huppert&#8217;s book
      in the library without even buying the book and then you can use
      Sylow&#8217;s Theorem for the rest of your life free of charge, but&#8230;&#160;for
      many  computer  algebra  systems  license  fees  have  to  be  paid
      regularly for the total time of their use. In order to protect what
      you pay for, you do not get the source, but only an executable,
      i.e.&#160;a black box. You can press buttons and you get answers in
      the same way as you get the bright pictures from your television
      set but you cannot control how they were made in either case.
      </p><!--l. 716--><p class="noindent">With this situation two of the most basic rules of conduct in
                                                                          

                                                                          
      mathematics are violated: In mathematics information is passed
      on free of charge and everything is laid open for checking. Not
      applying these rules to computer algebra systems that are made
      for mathematical research&#8230;&#160;means moving in a most undesirable
      direction. Most important: Can we expect somebody to believe a
      result of a program that he is not allowed to see? Moreover: Do
      we really want to charge colleagues in Moldava several years of
      their salary for a computer algebra system?</p></div>

{{{id=105|

///
}}}