pax_global_header00006660000000000000000000000064132157231110014506gustar00rootroot0000000000000052 comment=f54f468d5575abae3662ebd4f5a10e0746350140 libhomfly-1.02r5/000077500000000000000000000000001321572311100136645ustar00rootroot00000000000000libhomfly-1.02r5/.gitignore000066400000000000000000000005201321572311100156510ustar00rootroot00000000000000# git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): *.[oa] *.lo *.la Makefile Makefile.in aclocal.m4 config.log config.status configure libtool test/test_example libhomfly-1.02r5/.travis.yml000066400000000000000000000007561321572311100160050ustar00rootroot00000000000000language: c matrix: include: - os: osx compiler: clang - os: linux compiler: gcc addons: apt: packages: - libgc-dev before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install bdw-gc ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libgc-dev ; fi script: autoreconf --install && automake --add-missing --copy && ./configure && make check libhomfly-1.02r5/LICENSE000066400000000000000000000022731321572311100146750ustar00rootroot00000000000000This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to libhomfly-1.02r5/Makefile.am000066400000000000000000000001211321572311100157120ustar00rootroot00000000000000SUBDIRS = lib test ACLOCAL_AMFLAGS = -I m4 dist-hook: cp .travis.yml $(distdir) libhomfly-1.02r5/README.md000066400000000000000000000050071321572311100151450ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/miguelmarco/libhomfly.svg?branch=master)](https://travis-ci.org/miguelmarco/libhomfly) # libhomfly ## Library to compute the homfly polynomial of a link This is basically a conversion of the [program][1] written by Robert J Jenkins Jr into a shared library. It accepts as entry a character string, formatted in the same way as the input files that the original code used (see below). The returned value is the string that the original program would print on screen. The modifications done to the original program are: * modified input/output to allow being called as a shared library * the library now does not write any output to stdout * memory allocation moved to boehmgc to prevent memory leaks ### Authors * Robert J Jenkins Jr wrote the original program in 1990. The last version, used as a basis for this library was written in 2010. * Miguel Marco made the modifications to make it a library in 2015. ### Dependencies * standard c library * boehmgc ### Installation Run ```` autoreconf --install ```` to generate the config script. Then run ```` ./configure make ```` to build the library. Finally, as superuser run ```` make install ```` to install it. The autoreconf command should be in the autotools package. ### Example of usage This simple program can be used as an example of how to use the library. In particular, it computes the homfly polynomial of the trefoil knot. `````````````````````````````````````````````````````````````````````````````````````````` #include #include #include "homfly.h" #include int main() { char *out; char input[] = " 1 6 0 1 1 -1 2 1 0 -1 1 1 2 -1 0 1 1 1 2 1 "; out = homfly(input); printf("%s", out); return 0; } `````````````````````````````````````````````````````````````````````````````````````````` ### Input format Links are represented by a string with numbers separated by spaces as follows * how many strings, * for each string, how many crossings, then * for each crossing, the cross name, then 1 if over, -1 if under * for each crossing, the name of the crossing and 1 if right, -1 if left. The spacing and placement of returns don't matter. Integers only. If there are n crossings, they must be named 0 .. n-1. ### License The original program by Robert J Jenkins Jr is in the public domain, so I choose to keep it. This means in particular that you are free to distribute it or any derivative work under whichever license you choose. [1]: http://burtleburtle.net/bob/knot/homfly.html libhomfly-1.02r5/configure.ac000066400000000000000000000010031321572311100161440ustar00rootroot00000000000000AC_INIT([libhomfly], [1.02r5], [mmarco@unizar.es]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([foreign -Wall]) AM_PROG_AR AC_PROG_CC LT_INIT([win32-dll]) AC_CANONICAL_HOST dnl libtool requires "-no-undefined" for win32 dll AC_SUBST(HOMFLY_LDFLAGS) case $host_os in *cygwin* | *mingw*) if test x"$enable_shared" = xyes; then HOMFLY_LDFLAGS="$HOMFLY_LDFLAGS -no-undefined" fi ;; esac AC_CONFIG_FILES([Makefile lib/Makefile test/Makefile]) AC_OUTPUT libhomfly-1.02r5/lib/000077500000000000000000000000001321572311100144325ustar00rootroot00000000000000libhomfly-1.02r5/lib/Makefile.am000066400000000000000000000005061321572311100164670ustar00rootroot00000000000000lib_LTLIBRARIES = libhomfly.la libhomfly_la_SOURCES = bound.c control.c dllink.c homfly.c knot.c model.c order.c poly.c standard.h order.h bound.h control.h dllink.h homfly.h knot.h model.h order.h poly.h standard.h libhomfly_la_LDFLAGS = $(HOMFLY_LDFLAGS) -lgc -export-symbols-regex '(c_)?homfly' include_HEADERS = homfly.h libhomfly-1.02r5/lib/bound.c000066400000000000000000000220271321572311100157100ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ BOUND.C By Bob Jenkins, in association with his Masters Thesis Routines dealing with boundary manipulations of weaves Public Domain ------------------------------------------------------------------------------ */ #include #include #include "standard.h" #include "order.h" #include "control.h" #include "bound.h" /* ------------------------------------------------------------------------------ B_MANIP computes values of the global boundary variables. A step is either adding a crossing, adding a crossing and removing a pair of boundary crossings, or just removing a pair of boundary crossings. ------------------------------------------------------------------------------ */ word list[BIGWEAVE]; /* description of first new weave */ word list2[BIGWEAVE]; /* description of second, if needed */ word old_going_in[BIGWEAVE];/* Was *i* an input? *old_going_in[i]*. */ word going_in[BIGWEAVE]; /* Will *i* be an input? *going_in[i]*. */ word map[BIGWEAVE]; /* i of old weave becomes map[i] of new weave */ word first; /* first boundary crossing to remove */ word second; /* second boundary crossing to remove */ word right; /* Is the crossing being added be righthanded? */ word oldcross; /* number of boundary crossings in the old weave */ word newcross; /* number of boundary crossings in each new weave */ word oldin; /* number of inputs to the old weave */ word newin; /* number of inputs to the new weave */ void b_manip(weave *oldweaves) { word i, j, k; ub4 boundary[2]; oldcross = plan.oldn; /* number of original boundary crossings */ oldin = oldcross/2; /* number of original inputs */ newcross = plan.newn; /* number of boundary crossings in resulting weaves */ newin = newcross/2; /* " inputs " */ /*--------------------------------------------------- Compute old_going_in */ for (i = 0; !oldweaves[i].tag.len; i++) ; /* find a defined weave */ boundary[0] = oldweaves[i].boundary[0]; boundary[1] = oldweaves[i].boundary[1]; for (i = 0; i < oldcross; i++) old_going_in[i] = 1; /* pretend all crossings are inputs */ for (i = 0; i < oldin; i++) { k = (i < 6) ? 0 : 1; if (old_going_in[(boundary[k] & 0x1f)] == 0) { printf("cannot have both ends of a string be an output\n"); } old_going_in[(boundary[k] & 0x1f)] = 0; /* unmark the outputs */ boundary[k] >>= 5; } right = plan.right; if (plan.which != -1) { for (i = 0; i < oldcross; ++i) { if (old_going_in[i] != plan.going_in[i]) { printf("going_in is messed up\n"); break; } } } /*--------------------------- Set first and second, if they need to be set */ first = plan.r0[0]; second = plan.r1[0]; if (plan.reductions && plan.which != -1) /* crossing added, pair removed */ { if (first > plan.which+1) --first; if (second > plan.which+1) --second; if (first > plan.which) --first; if (second > plan.which) --second; } else ; /* crossing added, no pair removed */ /*---------------------------------------------------------------- Set map */ if (plan.reductions == 0) { for (i = 0, j = 0; i < oldcross+2; ++i) if ((i != plan.which) && (i != plan.which+2)) map[j++] = i; } else if (plan.which == (-1)) { for (i = 0, j = 0; j < oldcross; ++j) if ((j != plan.r0[0]) && (j != plan.r1[0])) map[j] = i++; } else if (plan.r0[0] > plan.r1[0]) { for (i = 0; i < oldcross; i++) map[i] = i; map[first] = (second); map[second] = (first); } else if (plan.which == 0) { for (i = 0; i < oldcross; i++) map[i] = i+1; map[0] = 0; map[oldcross-1] = 1; } else { for (i = 0; i < oldcross; i++) map[i] = i-1; map[0] = oldcross-2; map[oldcross-1] = oldcross-1; } /*----------------------------------------------------------- Set going_in */ if (plan.which != (-1)) { for (i = 0; i < oldcross; i++) { going_in[map[i]] = old_going_in[i]; } } else { for (i = 0; i < oldcross; i++) { if ((i != first) && (i != second)) { going_in[map[i]] = old_going_in[i]; } } } if (plan.reductions == 0) { going_in[plan.which] = plan.prev; going_in[plan.which+2] = !plan.prev; } } /* ------------------------------------------------------------------------------ B_NO_PAIRS adds a single crossing to a single weave. Either the crossing is correct, in which case *one* will be set, or it is wrong. In this case no more than two weaves are needed, so *two* will be set. ------------------------------------------------------------------------------ */ void b_no_pairs(word *list, /* list of original inputs/outputs, modified by this routine */ word *list2, /* inputs/outputs of the second new weave */ word *one, /* will one new weave suffice? */ word *two) /* will two new weaves suffice? */ { word i, a, b, c; /*-------------------------------------------------- Make the new boundary */ for (i = oldcross; --i >= 0;) list[map[i]] = map[list[i]]; a = plan.which+1; list[a-1] = a+1; list[a+1] = a-1; /*------------------------- Decide if the crossing needs to be operated on */ c = a-1; b_right(list, going_in, c, a, i); *one = (i == right); *two = !*one; if (*two) { for (i = newcross; --i >= 0;) list2[i] = list[i]; b = (plan.prev == going_in[a]) ? a-1 : a+1; c = (plan.prev == going_in[a]) ? a+1 : a-1; list2[list2[a]] = b; list2[b] = list2[a]; list2[a] = c; list2[c] = a; } } /* ------------------------------------------------------------------------------ B_ONE_PAIR handles adding one crossing and removing one pair of boundary crossings. This may require replacing the original weave with one, two, or more new weaves. If more than two are needed, do not set *one* or *two*. ------------------------------------------------------------------------------ */ void b_one_pair(list, list2, one, two) word *list; /* list of original inputs/outputs, modified by this routine */ word *list2; /* inputs/outputs of the second new weave */ word *one; /* will one new weave suffice? */ word *two; /* will two new weaves suffice? */ { word a; word i; word crossed; word shouldBeRight; word temp[BIGWEAVE]; /*---------------------------------- Check for a couple easy to spot cases */ a = plan.which; if ((plan.r0[0] == a+1) || (plan.r1[0] == a+1)) { /* A Type I Reidemeister move */ *one = 1; return; } /*---------------- Handle the cases where the reduction is the 0..n-1 jump */ if (plan.r0[0] < plan.r1[0]) { if (old_going_in[0] && old_going_in[oldcross-1]) return; crossed = b_cross(first, second, list[first], list[second]); b_right(list, old_going_in, first, second, shouldBeRight); /* werecrossed */ if (list[first] == second) { /* A Type I Reidemeister move */ for (i = oldcross; --i >= 0; ) temp[map[i]] = list[i]; for (i = oldcross; --i >= 0; ) list[i] = map[temp[i]]; *one = 1; return; } if (old_going_in[first] != old_going_in[second]) { /* this may be complicated */ return; } for (i = oldcross; --i >= 0; ) temp[map[i]] = list[i]; for (i = oldcross; --i >= 0; ) list[i] = map[temp[i]]; if (!old_going_in[first] && !old_going_in[second] && (crossed ^ shouldBeRight ^ right)) { *two = 1; for (i = 0; i < newcross; i++) list2[i] = list[i]; if (plan.which == 0) b_switch(list2, 1, 0, i); else b_switch(list2, newcross-1, newcross-2, i); } else *one = 1; return; } /*-------- Handle the cases where the numbers on the boundary are adjacent */ if (list[first] == second) /* A Type I Reidemeister move */ { *one = 1; return; } crossed = b_cross(first, second, list[first], list[second]);/* werecrossed */ b_right(list, old_going_in, first, second, a); /* old crossing righthanded */ b_switch(list, first, second, i); /* switch the boundary crossings */ b_right(list, going_in, first, second, i); /* new should be righthanded */ *one = (((crossed) && (a != right)) || ((!crossed) && (i == right))); if (*two = !*one) { if (old_going_in[first] != old_going_in[second]) { *two = 0; b_switch(list, first, second, i); } else { for (i = newcross; --i >= 0; ) list2[i] = list[i]; b_switch(list2, first, second, i); } } } libhomfly-1.02r5/lib/bound.h000066400000000000000000000140121321572311100157100ustar00rootroot00000000000000/* --------------------------------------------------------------------------- BOUND.H Declarations of public routines found in bound.c Macros dealing with weave boundaries Public Domain --------------------------------------------------------------------------- */ #ifndef BOUND #define BOUND #include "standard.h" #include "poly.h" #define MAXSTRING 12 #define BIGWEAVE (2*MAXSTRING+2) /* --------------------------------------------------------------------------- This algorithm models the solved region of a link by a set of simple weaves and their associated polynomials, which are called tags. Due to a nice result, any simple weave is uniquely defined by how its inputs are matched to its outputs. A list of the outputs the inputs are matched to, in the order of the inputs, is enough to define a simple weave. Unfortunatly, there is no similar result about the associated tags. Since I've never seen a workstation capable of storing 9! polynomials, it is reasonable to assume no weave of more than 8 inputs ever needs to be dealt with. Weaves of 8 inputs have 16 boundary crossings, so any reduced weave with 8 inputs or less can be stored in (8 copies of 4 bits =32 bits). The size of an integer nowadays is, you guessed it, 32 bits. Something of type WEAVE is just a simple weave and its tag. BODY is a compressed representation of the simple weave itself. TAG is the polynomial associated with that simple weave. --------------------------------------------------------------------------- */ struct weave { ub4 boundary[2]; /* Representation of the weave, heavily encoded. */ Poly tag; /* Polynomial associated with link represented by weave */ }; typedef struct weave weave; /* --------------------------------------------------------------------------- Global Variables -- located in bound.c --------------------------------------------------------------------------- */ extern word list[]; /* description of first new weave */ extern word list2[]; /* description of second, if needed */ extern word old_going_in[]; /* Was *i* an input? *old_going_in[i]*. */ extern word going_in[]; /* Will *i* be an input? *going_in[i]*. */ extern word map[]; /* i of old weave becomes map[i] of new weave */ extern word first; /* first boundary crossing to remove */ extern word second; /* second boundary crossing to remove */ extern word right; /* Is the crossing being added righthanded? */ extern word oldcross; /* number of boundary crossings in the old weave */ extern word newcross; /* number of boundary crossings in each new weave */ extern word oldin; /* number of inputs to the old weave */ extern word newin; /* number of inputs to the new weave */ /* --------------------------------------------------------------------------- Procedures defined in bound.c --------------------------------------------------------------------------- */ /* Manipulate those variables whose values are universal to all weaves at a given step. (These are the global variables declared above). */ void b_manip(weave *oldweaves); /* Add a crossing to a single weave without removing any pair of boundary crossings. Compute list, and perhaps list2, describing the new simple weaves. */ void b_no_pairs(word *list, word *list2, word *one, word *two); /* Add a crossing to a simple weave and remove one pair of boundary crossings. If the result is one or two simple weaves, well and good. If the result is more complicated than that, b_one_pair is essentially a no-op. */ void b_one_pair(word *list, word *list2, word *one, word *two); /* --------------------------------------------------------------------------- There are three representations of weave boundaries. 1) *list* is an array of words of size oldcross saying which crossing is attached to which other crossing. If list[i]==j, list[j]==i. 2) The medium-size representation (two ub4's) stores the values of *list* for only the inputs (the output can be deduced). Further, each value is stored in 5 bits, with 6 values per ub4. 3) The tiny representation recognizes that the medium-size representation is a permutation of the outputs, and permutations can be enumerated. The tiny representation is the number for that permutation. --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- The macro b_cross determines if two strings cross in a simple weave in standard form. This formula has been proven to be correct (via a large truth table). --------------------------------------------------------------------------- */ #define b_cross( inp1, inp2, outp1, outp2) \ (((inp1)<(inp2))==((inp2)<(outp1))==((outp1)<(outp2))==((inp1)<(outp2))) /* --------------------------------------------------------------------------- Switch the positions of *first* and *second* in the boundary *list*. --------------------------------------------------------------------------- */ #define b_switch( list, first, second, temp ) \ if (1) \ { \ list[list[first]] = second; \ list[list[second]] = first; \ temp = list[first]; \ list[first] = list[second]; \ list[second] = temp; \ } else /* --------------------------------------------------------------------------- Should the crossing of *first* and *second* in *list* be righthanded? *i*. Boundary crossings are numbered counterclockwise. Inside a simple weave, the string with the lowest input should be an overpass. --------------------------------------------------------------------------- */ #define b_right( list, going_in, first, second, i ) \ if (1) \ { \ word x = first < list[first] ? first : list[first]; \ word y = second < list[second] ? second : list[second]; \ if (x > y) {i = x; x = y; y = i;} \ i = !(going_in[x] && !going_in[y]); \ } else #endif /* BOUND */ libhomfly-1.02r5/lib/control.c000066400000000000000000000177061321572311100162710ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ By Bob Jenkins, revamped August 1990, in relation to my masters thesis Public Domain ------------------------------------------------------------------------------ */ #include #include #include "standard.h" #include "poly.h" #include "knot.h" #include "order.h" #include "bound.h" #include "model.h" #include "control.h" Instruct plan; Poly llplus; Poly lplusm; Poly lminusm; Poly llminus; Poly mll; ub4 total_weaves_handled; /* these variables are global, and may be because nobody ever changes them */ void c_init() { Poly blank[1]; p_init(blank); p_term((-1), 0, 2, blank, &llplus); p_term((-1), 1, 1, blank, &lplusm); p_term((-1), 1, (-1), blank, &lminusm); p_term((-1), 0, (-2), blank, &llminus); p_init(&mll); p_term((-1), (-1), 1, &mll, blank); p_kill(&mll); p_term((-1), (-1), (-1), blank, &mll); p_kill(blank); total_weaves_handled = 0; } void c_handle(word *list, /* matching of inputs/outputs in thisweave */ weave *thisweave, /* the weave to be handled */ weave *newweaves) /* all the new weaves */ /* Given a simple weave WEAVE, this figures out what BODY should be, and adds the weave to the list NEWWEAVES */ /* Rather than keeping a heap or tree of new weaves, I have assumed that every permutation will probably be used. I use a total ordering on the set of permutations as an index to my array of all possible new weaves. */ /* This is one of the most used procedures in this program */ { Poly temp[1]; word i, j, k; word sum; word prod; word count; ub4 boundary[2]; word inputs[BIGWEAVE]; ++total_weaves_handled; boundary[0] = 0; boundary[1] = 0; /* Make a list of which inputs go to which outputs; compute *boundary* */ for (i = newin, j = newcross; i--;) { while (!going_in[--j]); inputs[i] = list[j]; k = (i < 6) ? 0 : 1; boundary[k] = inputs[i] + (boundary[k] << 5); } /* Determine this weave's index in the array of newweaves */ sum = 0; prod = 1; for (i = 1; i < newin; ++i) { prod *= i; count = 0; for (j = i, k = inputs[i]; --j >= 0;) if (k > inputs[j]) ++count; sum += count * prod; } newweaves[sum].boundary[0] = boundary[0]; newweaves[sum].boundary[1] = boundary[1]; p_add(&newweaves[sum].tag, &thisweave->tag, temp); p_kill(&thisweave->tag); p_kill(&newweaves[sum].tag); newweaves[sum].tag = *temp; } /* This does all the weave manipulation associated with adding a single crossing to a single weave. */ static void c_do_one_weave( weave *oldweave, /* the single weave to apply the instructions to */ weave *newweaves) /* the array of all new weaves */ { word one = 0; word two = 0; word i, j, k; ub4 boundary[2]; weave other[1]; Poly temp[1]; /*-------------------------------------------------- undecode the boundary */ boundary[0] = oldweave->boundary[0]; boundary[1] = oldweave->boundary[1]; for (j = 0, i = 0; i < oldin; ++i, ++j) { while (!old_going_in[j]) j++; /* find the next input */ k = (i < 6) ? 0 : 1; list[j] = boundary[k] & 0x1f; /* set boundary input */ boundary[k] >>= 5; list[list[j]] = j; /* set boundary output */ } /*----------------------------------------------- Try to handle it quickly */ if (plan.reductions == 0) b_no_pairs(list, list2, &one, &two); else if (plan.which >= 0) b_one_pair(list, list2, &one, &two); /*----------------------- Is the old weave replaced by only one new weave? */ if (one) { c_handle(list, oldweave, newweaves); return; } /*--------------------------- Is the old weave replaced by two new weaves? */ if (two) { if (right) { p_mult(&lminusm, &oldweave->tag, &other->tag); p_mult(&llminus, &oldweave->tag, temp); p_kill(&oldweave->tag); oldweave->tag = *temp; } else { p_mult(&lplusm, &oldweave->tag, &other->tag); p_mult(&llplus, &oldweave->tag, temp); p_kill(&oldweave->tag); oldweave->tag = *temp; } c_handle(list, oldweave, newweaves); c_handle(list2, other, newweaves); return; } /*------------------- The old weave is replace by up to 2^(n-1) new weaves */ m_model_weave(list, oldweave, newweaves); } /* ------------------------------------------------------------------------------ NAME: C_FOLLOW() FUNCTION: Given a list of *crossings* instructions *l*, follow them and produce the polynomial *answer* which is the HOMFLY polynomial for the original link. METHOD: For each instruction, Break the instruction into (add crossing/remove pair), (remove pair), ... (Each operation changes the size of the weave boundary from n inputs to either n+2 (add), n (add/remove), or n-2 (remove) crossings) For each of the (oldn/2)! old weaves, apply the instruction and merge the result into the list of (newn/2)! new weaves. At the end (n/2)=1, so there are (n/2)! = 1 final weaves, and the tag associated with that weave is *answer* . NOTES: The tags for the weaves are being freed immediately after they are last used by whichever procedure last uses them. They are not being freed in the procedures which MALLOC them. Before you change where things are freed, think. ------------------------------------------------------------------------------ */ Poly *c_follow(Instruct *l, int num_crossings) { word i, j, k; ub4 oldfact; ub4 newfact; weave *oldweaves, *newweaves; extern Instruct plan; /*---------------------------------------------- Set up the starting weave */ oldweaves = (weave *)GC_MALLOC(sizeof(weave)); oldweaves[0].boundary[0] = 1; oldweaves[0].boundary[1] = 0; oldweaves->tag.len = 0; p_term(1, 0, 0, &oldweaves->tag, &oldweaves->tag); /* tag of original link is 1 */ /*-------------- For each crossing, follow the instructions on every weave */ for (i = 0; i < num_crossings; ++i) { /*----- Handle adding the crossing, plus the first boundary pair removal */ plan = l[i]; plan.reductions = (plan.reductions > 0); plan.newn = plan.oldn + 2 - 2*plan.reductions; b_manip(oldweaves); for (j = 2, newfact = 1; j <= newin; newfact *= (j++)) ; newweaves = (weave *)GC_MALLOC(sizeof(weave) * newfact); for (j = 0; j < newfact;) newweaves[j++].tag.len = 0; for (j = 2, oldfact = 1; j <= oldin; oldfact *= (j++)) ; for (j = 0; j < oldfact; ++j) { if (oldweaves[j].tag.len) { c_do_one_weave(oldweaves + j, newweaves); } } //free((char *)oldweaves); oldweaves = newweaves; // printf("firstbatch\n"); /*for (j = 0; j < newfact; ++j) { if (newweaves[j].tag.len != 0) { p_show(&newweaves[j].tag); } }*/ /*----------- Remove any other pairs of boundary crossings one at a time */ for (k = 1; k < l[i].reductions; ++k) { oldfact = newfact; plan.which = -1; plan.r0[0] = l[i].r0[k]; plan.r1[0] = l[i].r1[k]; plan.oldn = plan.newn; plan.newn -= 2; b_manip(oldweaves); newfact = oldfact / oldin; newweaves = (weave *)GC_MALLOC(sizeof(weave) * newfact); for (j = 0; j < newfact;) newweaves[j++].tag.len = 0; for (j = 0; j < oldfact; j++) { if (oldweaves[j].tag.len) { c_do_one_weave((oldweaves+j), newweaves); } } //free((char *)oldweaves); oldweaves = newweaves; // printf("reduction %d\n", k); } /*------------------------ Gloat about how little work needed to be done */ } /*-------------------------------------------- Return the final polynomial */ return &oldweaves->tag; } libhomfly-1.02r5/lib/control.h000066400000000000000000000030651321572311100162670ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ By Bob Jenkins, Spring 1989, Public Domain These are the data structures used in my knot programs ------------------------------------------------------------------------------ */ #ifndef CONTROL #define CONTROL #include "poly.h" #include "order.h" /* Global variables -- located in control.c */ extern Instruct plan; /* plan of what to do to each old weave for this step */ extern Poly llplus; /* -L^2 */ extern Poly lplusm; /* -LM */ extern Poly lminusm; /* -(L^-1)M */ extern Poly llminus; /* -L^-2 */ extern Poly mll; /* (M^-1)(-(L^-1) - L) */ extern ub4 total_weaves_handled; /* how much work has been done? */ /* ------------------------------------------------------------------------------ Procedures defined in control.c ------------------------------------------------------------------------------ */ void c_init(void); /* Initialize global polynomials */ /* c_handle: Merge the tag of a new weave with the list of all new weaves */ void c_handle(word *list, struct weave *thisweave, struct weave *newweaves); /* c_follow: Follow all instructions, return the poly for the original link */ Poly *c_follow(Instruct *l, int num_crossings); #endif /* ifndef CONTROL */ libhomfly-1.02r5/lib/dllink.c000066400000000000000000000037151321572311100160610ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ dllink.c - routines for dealing with doubly linked, circular lists Bob Jenkins, 1990. Public Domain. ------------------------------------------------------------------------------ */ #include #include #include "standard.h" #include "dllink.h" /* ------------------------------------------------------------------------------ This displays all the nodes in a single string ------------------------------------------------------------------------------ */ void l_show(dllink *l) { dllink *count; if ((count = l) != 0) { //printf("%d ", count->c); count = count->z; while (count != l) { //printf("%d ", count->c); count = count->z; } } //printf("\n"); } /* ------------------------------------------------------------------------------ This takes a dllink inp, adds a dllink before it, and places a pointer to the added dllink in outp ------------------------------------------------------------------------------ */ void l_add(dllink *inp, /* the next crossing in this string */ word crossings, /* the new crossing number */ dllink **outp) /* out: pointer to the new crossing */ { dllink *newlink; newlink = (dllink *)GC_MALLOC(sizeof(dllink)); newlink->c = crossings; if (inp == 0) { newlink->a = newlink; newlink->z = newlink; inp = newlink; } else { newlink->a = inp->a; newlink->z = inp; inp->a->z = newlink; inp->a = newlink; } *outp = inp->a; } /* ------------------------------------------------------------------------------ This deletes a given dllink from a loop ------------------------------------------------------------------------------ */ void l_del(l) dllink **l; { dllink *ll = *l; if (!ll) return; if (ll->a != ll) { ll->z->a = ll->a; ll->a->z = ll->z; } //free((char *)ll); *l = (dllink *)0; } libhomfly-1.02r5/lib/dllink.h000066400000000000000000000021011321572311100160520ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ DLLINK.H Declares structures and procedures for the abstract data type DLLINK which is implemented in dllink.c . Bob Jenkins, 1990. Public Domain. ------------------------------------------------------------------------------ */ #ifndef DLLINK #define DLLINK #include "standard.h" /* Something of type DLLINK is a node in a doubly-linked cyclic list. C is the data stored in this node. A is a pointer to the previous node. Z is a pointer to the next node. */ struct dllink { word c; /* the crossing number */ struct dllink *a; /* the previous crossing */ struct dllink *z; /* the next crossing */ }; typedef struct dllink dllink; /* Procedures defined in dllink.c */ # define l_init( l) (l = ((dllink *)(0))) void l_show(dllink *l); /* Display all nodes */ void l_add(dllink *inp, word c, dllink **outp); /* Add a node */ void l_del(dllink **l); /* Delete a node */ #endif /* ifndef DLLINK */ libhomfly-1.02r5/lib/homfly.c000066400000000000000000000026771321572311100161100ustar00rootroot00000000000000/** ------------------------------------------------------------------------------ HOMFLY.C Main functions for the library ------------------------------------------------------------------------------ */ #include #include #include "standard.h" #include "poly.h" #include "knot.h" #include "homfly.h" #include "order.h" #include "control.h" char *homfly_str(char *argv) { Poly *answer; /* HOMFLY polynomial for the original link */ char *out; answer = homfly(argv); out = p_show(answer); /* display the answer */ //free((char *)*knot); //free((char *)*plan); //p_kill(answer); /* If you want to be thorough, free the polynomials defined in c_init */ //free (llplus.term); //free (lplusm.term); //free (lminusm.term); //free (llminus.term); //free (mll.term); return out; } Poly *homfly(char *argv) { Link *link; GC_INIT(); k_read(&link, argv); /* read link */ return c_homfly(link); } /** * Compute the homfly polynomial and return the result as the polynomial answer. */ Poly *c_homfly(Link *link) { Instruct *plan; /* list of instructions */ c_init(); /* initialize variables */ o_make(link, &plan); /* make plan for attacking the link */ return c_follow(plan, link->num_crossings); /* follow the plan */ } libhomfly-1.02r5/lib/homfly.h000066400000000000000000000043411321572311100161030ustar00rootroot00000000000000/** * Main functions to be called from the library * * ---------------------------------------------------------------------------- * Here's a sketch of the algorithm: * The Homfly polynomial is calculated using a recursive formula that * replaces a given link with two intermediate links, and associates a * polynomial with each intermediate link. The two new links differ at * the single crossing at which the recursive formula was applied. * The base case is always links with no crossings. * The obvious will produce a binary tree with about 2^n nodes, where each * node is an intermediate link and all the leaf links have no crossings. * This approach applies the recursion formula to the crossings in all * intermediate links in the same order, which encourages duplicates among the * intermediate links. Duplicate links are collected, their polynomials are * summed, then only one copy of each type of intermediate link needs to be * dealt with. * The number of intermediate links at any point is n! or less, where n is * the ceiling(sqrt(#crossings)) or less. Usually n never needs to exceed * sqrt(#crossings)/2, where #crossing is the number of crossings in the * original link. * ---------------------------------------------------------------------------- */ #ifndef HOMFLY_H #define HOMFLY_H #ifndef UB4MAXVAL typedef int word; typedef signed long int sb4; typedef unsigned short int ub2; typedef signed short int sb2; #endif #ifndef KNOT struct crossing { struct dllink *o; /* overpass */ struct dllink *u; /* underpass */ int hand; /* 1 if right handed, -1 if left, 0 if no longer a crossing */ }; typedef struct crossing crossing; struct Link { crossing *data; int num_crossings; }; typedef struct Link Link; #endif #ifndef POLY struct Term { sb4 coef; sb2 m; sb2 l; }; typedef struct Term Term; struct Poly { Term *term; sb4 len; }; typedef struct Poly Poly; #endif char *homfly_str(char *argv); Poly *homfly(char *argv); /* c_homfly: Compute the homfly polynomial for the link */ Poly *c_homfly(Link *link); #endif // HOMFLY_H libhomfly-1.02r5/lib/knot.c000066400000000000000000000075671321572311100155700ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ By Bob Jenkins, 1989, in relation to my Master's Thesis. Public Domain. This module handles entire knots. ------------------------------------------------------------------------------ */ #include #include #include #include "standard.h" #include "dllink.h" #include "knot.h" /* ------------------------------------------------------------------------------ Assumes the dllinks all form cycles This displays each string once by listing its crossings in order. After that, it displays the HANDedness of each crossing. ------------------------------------------------------------------------------ */ void k_show(Link *link) { word i, j; word tab[MAXCROSS]; dllink *count, *start; for (i=0; inum_crossings; ++i) tab[i] = 0; for (j=0; j<2; ++j) { for (i=0; inum_crossings; ++i) { if (link->data[i].hand && ((tab[i] == 0) || (tab[i] == 1) || (tab[i] == 10))) { if (tab[i] != 10) count = link->data[i].o; else count = link->data[i].u; start = count; if (link->data[count->c].o == count) { tab[count->c] += 10; } else { tab[count->c] += 1; } if (count != 0) count = count->z; while (count != start) { if (link->data[count->c].o == count) tab[count->c] += 10; else tab[count->c] += 1; count = count->z; } } } } } /* ------------------------------------------------------------------------------ Assumes the file given by the user exists and contains a legal knot. ------------------------------------------------------------------------------ */ boolean k_read(Link **link, char *f) { char name[20]; word links, startwhere, where, startover, over, i, j; int num_crossings, pos; crossing *kk; crossing k[MAXCROSS]; for (i = 0; i < MAXCROSS; i++) k[i].hand = 0; if (f == 0) { return FALSE; } sscanf(f, "%d%n", &links, &pos); f += pos; for (i=0; i num_crossings) num_crossings = where; } ++num_crossings; kk = (crossing *)GC_MALLOC(sizeof(crossing) * num_crossings); for (i=0; i < num_crossings; ++i) kk[i] = k[i]; /* check that every crossing has an overpass and underpass */ for (i=0; inum_crossings = num_crossings; (*link)->data = kk; return TRUE; } libhomfly-1.02r5/lib/knot.h000066400000000000000000000036061321572311100155630ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ KNOT.H By Bob Jenkins, 1988. Public Domain. A file describing a legal knot consists of 1: how many strings, 2: for each string, how many crossings, then 3: for each crossing, the cross name, then 1 if over, -1 if under 4: for each crossing, the name of the crossing and 1 if right, -1 if left. The spacing and placement of returns don't matter. Integers only. If there are n crossings, they must be named 0..n-1. Example: Two rubber bands, one on top of the other, would be: 2 4 0 1 1 1 2 1 3 1 4 0 -1 1 -1 2 -1 3 -1 0 -1 1 1 2 -1 3 1 ------------------------------------------------------------------------------ */ #ifndef KNOT #define KNOT #include "standard.h" #include "dllink.h" /* ------------------------------------------------------------------------------ The set of crossings for a dllink is represented by an array of type CROSSING. hand is -1 if this is crossing is lefthanded, 1 if it is righthanded. hand is 0 if the crossing no longer exists. o is a pointer to the overpass node. u is a pointer to the underpass node. ------------------------------------------------------------------------------ */ struct crossing { dllink *o; /* overpass */ dllink *u; /* underpass */ word hand; /* 1 if right handed, -1 if left, 0 if no longer a crossing */ }; typedef struct crossing crossing; struct Link { crossing *data; int num_crossings; }; typedef struct Link Link; /* maximum number of crossings in a knot */ #define MAXCROSS 1000 /* Procedures defined in knot.c */ /* Display a whole knot */ void k_show(Link *k); /* Read a knot file */ boolean k_read(Link **k, char *filename); #endif /* ifndef KNOT */ libhomfly-1.02r5/lib/model.c000066400000000000000000000364321321572311100157060ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ MODEL.C - Bob Jenkins, 1989. Public Domain. When weaves do not fit in to one of the special cases handled in BOUND.C, it becomes necessary to actually model the weave (that is, build strings that cross over each other) and manipulate the model. The model is copied and manipulated until the original weave has been replaced by a set of simple weaves. c_handle() is called directly whenever a simple weave is produced. A single weave may need a set of as many as 2^oldin simple weaves to replace it. Refer to my masters thesis for a description and justification of the algorithm used to replace weaves with simple weaves. ------------------------------------------------------------------------------ */ /* A program by Bob Jenkins, Spring 1989 */ #include #include #include "standard.h" #include "poly.h" #include "order.h" #include "bound.h" #include "control.h" #include "model.h" /* Since models are used only underneath the routines that create them, the memory they use actually comes from local variables. This cuts down the time and space for memory allocation/deallocation incredibly. */ /* Create a copy of the weave modeled in model1 in model2. */ static void m_copy(node **model1, node **model2, char *mem) { word i; word offset = 0; node *nodemem = (node *)mem; node *cur, *t; node *tab[BIGWEAVE][BIGWEAVE]; for (i = 0; i < newcross; i++) { for (cur = model1[i]; cur != 0; cur = cur->z) { tab[cur->o1][cur->o2] = 0; } } for (i = 0; i < newcross; i++) { if (model1[i] != 0) { model2[i] = (node *)(&nodemem[offset++]); cur = model1[i]; t = model2[i]; while (cur != 0) { *t = *cur; if (tab[t->o1][t->o2] != 0) { t->m = tab[t->o1][t->o2]; t->m->m = t; } else tab[t->o1][t->o2] = t; if (cur->z != 0) { t->z = (node *)(&nodemem[offset++]); } else t->z = 0; cur = cur->z; t = t->z; } } else model2[i] = 0; } } /* Display the structure of the model *model* */ void m_show(node **model) { } /* Often it can be proven that no bad crossings are or ever will be in a string. In this case, eliminate all crossings the string is involved in, eliminate the memory associated with the string, and eliminate the string. This reduces the complexity of the model. */ static void m_string_kill(node **model, word where) { word i, done; node *t; for (i = newcross; --i >= 0;) { if ((model[i]) && (i != where)) { for (done = 0; !done;) { done = !model[i]->z; if (model[i]->m->self == where) model[i] = model[i]->z; else done = 1; } if (model[i]) { for (t = model[i]; t->z;) { if (t->z->m->self == where) t->z = t->z->z; else t = t->z; } } } } model[where] = 0; } /* Should string *a* cross string *x* before string *b*? */ /* Positions of crossings are determined by the lowest numbered boundary crossing of a string. Overpass/underpass is determined by the crossing of the string which is the input. m_before() is concerned with the former order, while the rest of this project cares mostly about the latter order. Thus all the (list[a] < a), *backwards*, and so on in this routine. */ static word m_before(word x, word a, word b, word *list) { word backwards; if (backwards = (list[x] < x)) x = list[x]; if (list[a] < a) a = list[a]; if (list[b] < b) b = list[b]; if (a == b) return 0; if (b_cross(a, b, list[a], list[b])) return((a < b) != backwards); a = ((x < a) && (a < list[x])) ? a : list[a]; b = ((x < b) && (b < list[x])) ? b : list[b]; return((a < b) != backwards); } /* Put the crossings in the simple weave being modeled in the correct places. This is called "a simple weave in standard form" in my thesis. */ static void m_sort(word i, node **model, word *list) /* This assumes that the weave is simple */ { word done = 0; node **t, *temp, *temp2; while (!done) { for (done = 1, t = (&(model[i])); (*t)->z; t = (&((*t)->z))) { if (m_before(i, (*t)->z->m->self, (*t)->m->self, list)) { temp = (*t)->z->z; (*t)->z->z = (*t); temp2 = (*t)->z; (*t)->z = temp; (*t) = temp2; done = 0; } } } } /* Are the correct strings overpasses in all the crossings of this string? */ static void m_correct(node **model, word string) { node *t; for (t = model[string]; t != 0; t = t->z) { word self = t->self; word other = t->m->self; t->correct = (t->over == (self < other)); if (self == other) t->correct = 1; t->m->correct = t->correct; } } /* Break, as in the HOMFLY recursion formula */ static void m_k_break(node **at, node **bt) { word a, b; node *c; a = (*at)->self; b = (*bt)->self; c = (*at); *at = (*bt)->z; *bt = c->z; for (c = (*at); c != 0; c = c->z) c->self = a; for (c = (*bt); c != 0; c = c->z) c->self = b; } /* Switch, as in the HOMFLY recursion formula */ static void m_k_switch(node *at, node *bt) { at->right = !at->right; at->over = !at->over; at->correct = !at->correct; bt->right = !bt->right; bt->over = !bt->over; bt->correct = !bt->correct; } /* Given a model *model* with boundary crossings *list*, either confirm that *model* models a simple weave, or find a crossing to apply the HOMFLY recursion formula to. A simple weave is a circle with strings going in and out of it. Its internal structure is determined by the order of the strings going in and out of it. Arrange its border in a right triangle, with the diagonal going from bottom left to upper right, and number the crossings 0..n-1 along that diagonal. Have all the strings form right angles, going straight up then to the right. I suppose it's really straight left then down if the input comes after the output. That layout determines where the crossings should be. If two strings cross, the string with the lower input should be the overpass. */ static void m_recurse(node **model, word *list, weave *oldweave, weave *newweaves) { word i, j, wasright, mfirst, msecond, mtop, mbot, list2[BIGWEAVE]; char mem2[BIGMODEL]; node *t, **t2, *model2[BIGWEAVE]; weave other[1]; Poly temp[1]; /* remove strings lying below everything interesting */ for (mbot = newcross; --mbot >= 0;) { for (t = model[mbot]; t && t->correct; t = t->z) ; if (t) break; if (model[mbot]) m_string_kill(model, mbot); } /* remove strings lying above everything interesting */ for (mtop = 0; mtop < newcross; mtop++) { for (t = model[mtop]; t && t->correct; t = t->z) ; if (t) break; if (model[mtop]) m_string_kill(model, mtop); } if (mtop < mbot) { for (t = model[mbot], i = 0; t; t = t->z) i += !t->correct; for (t = model[mtop], j = 0; t; t = t->z) j += !t->correct; for (t = model[i>j ? mbot : mtop]; t->correct; t = t->z); wasright = t->right; mfirst = t->self; msecond = t->m->self; for (j = 0; j < newcross; j++) list2[j] = list[j]; m_copy(model, model2, mem2); *other = *oldweave; p_copy(&oldweave->tag, &other->tag); m_k_switch(t, t->m); b_switch(list2, mfirst, msecond, j); for (t2 = (&(model2[mfirst])); (*t2)->correct; t2 = (&((*t2)->z))) ; if (model2[msecond]->m != (*t2)) { for (t = model2[msecond]; t->z->m != (*t2); t = t->z) ; m_k_break(&(t->z), t2); } else m_k_break(&model2[msecond], t2); m_correct(model2, mfirst); m_correct(model2, msecond); other->boundary[0] = oldweave->boundary[0]; other->boundary[1] = oldweave->boundary[1]; if (wasright) { p_mult(&lminusm, &oldweave->tag, &other->tag); p_mult(&llminus, &oldweave->tag, temp); p_kill(&oldweave->tag); oldweave->tag = *temp; } else { p_mult(&lplusm, &oldweave->tag, &other->tag); p_mult(&llplus, &oldweave->tag, temp); p_kill(&oldweave->tag); oldweave->tag = *temp; } m_recurse(model, list, oldweave, newweaves); m_recurse(model2, list2, other, newweaves); return; } else { c_handle(list, oldweave, newweaves); } } static void m_add(node **model, /* original weave */ node *t, /* crossing to add to the weave */ word *list, /* mapping of inputs to outputs */ word where) /* where to add the crossing */ { node *temp; if (going_in[where]) { /* add this node to the start of the string */ t->z = model[where]; model[where] = t; } else { /* add this node to the end of the string */ t->z = 0; if (model[list[where]]) { for (temp = model[list[where]]; temp->z; temp = temp->z) ; temp->z = t; } else model[list[where]] = t; } } static void m_shrink(word *list, node **model, weave *oldweave) { Poly blank; word this, that, i, j; node *t; this = (old_going_in[first]) ? list[second] : list[first]; that = (old_going_in[first]) ? first : second; for (t = model[that]; t != 0; t = t->z) t->self = this; if (model[this] != 0) { for (t = model[this]; t->z != 0; t = t->z) ; t->z = model[that]; } else model[this] = model[that]; model[that] = 0; list[this] = list[that]; list[list[this]] = this; for (i = 0; i < oldcross; i++) { if ((i != first) && (i != second)) { j = map[i]; model[j] = model[i]; for (t = model[j]; t != 0; t = t->z) t->self = j; list[j] = list[i]-((list[i] > first)+(list[i] > second)); } } if (this == first || this == second) { /* A loop is being eliminated, multiply oldweave->tag by mll */ p_mult(&mll, &oldweave->tag, &blank); p_kill(&oldweave->tag); oldweave->tag = blank; } else { /* some of the crossings might now be wrong */ this = map[this]; m_correct(model, this); } } static void m_switch(word *list, node **model, char *mem) { word i, temp[BIGWEAVE], mfirst, msecond; node *t, /* first string's half of new crossing */ *t2, /* second string's half of new crossing */ *temp2[BIGWEAVE]; mfirst = first; msecond = second; if (mfirst != msecond + 1) { /* * Augh, we need some massive rearrangement here. * I think this also causes lots of bad crossings, due to the highest * string suddenly becoming the lowest string or vice versa, when the * one swapping from high to low or low to high is an input. * Could we finagle the plan so that this never happens? */ for (i = 0; i < oldcross; i++) temp[map[i]] = list[i]; for (i = 0; i < oldcross; i++) list[i] = map[temp[i]]; for (i = 0; i < oldcross; i++) temp2[map[i]] = model[i]; for (i = 0; i < oldcross; i++) model[i] = temp2[i]; for (i = 0; i < oldcross; i++) for (t = model[i]; t != 0; t = t->z) t->self = i; mfirst = map[mfirst]; msecond = map[msecond]; } else { /* swap the two neighboring strings */ b_switch(list, mfirst, msecond, i); t2 = model[mfirst]; model[mfirst] = model[msecond]; model[msecond] = t2; /* note, model[mfirst] is empty if mfirst happens to be an output */ for (t2 = model[mfirst]; t2 != 0; t2 = t2->z) t2->self = mfirst; for (t2 = model[msecond]; t2 != 0; t2 = t2->z) t2->self = msecond; } if (mfirst > msecond) { i = mfirst; mfirst = msecond; msecond = i; } t = (node *)mem; t->right = plan.right; t->self = (going_in[mfirst]) ? mfirst : list[mfirst]; t->over = (t->right ^ going_in[mfirst] ^ going_in[msecond]); t->o1 = 0; t->o2 = 0; t2 = (node *)(&mem[sizeof(node)]); t2->self = (going_in[msecond]) ? msecond : list[msecond]; t2->right = t->right; t2->over = !t->over; t2->o1 = 0; t2->o2 = 0; t->m = t2; t2->m = t; m_add(model, t, list, mfirst); m_add(model, t2, list, msecond); m_correct(model, mfirst); m_correct(model, msecond); } /* ------------------------------------------------------------------------------ Given the boundary description of a simple weave, construct the weave. ------------------------------------------------------------------------------ */ void m_make(word *list, node **model, char *mem) { word i, j, temp; word offset = 0; node *a, *b; node *nodemem = (node *)mem; for (i = 0; i < oldcross; ++i) model[i] = 0;/* null terminate every string */ for (i = 1; i < oldcross; ++i) { if (old_going_in[i]) { for (j = 0; j < i; ++j) { if ((old_going_in[j]) && (b_cross(i, j, list[i], list[j]))) { a = (node *)(&nodemem[offset++]); /* overpass */ b = (node *)(&nodemem[offset++]); /* underpass */ a->self = j; /* a is in string j */ b_right(list, old_going_in, j, i, temp); /* Is this right handed? *temp*. */ a->right = temp; /* righthanded? */ a->over = 1; /* a is an overpass */ a->correct = 1; /* yes, this crossing should be the hand that it is. */ a->m = b; /* the other node in this internal crossing */ a->z = model[j]; /* the internal crossing one closer to the output */ a->o1 = j; /* a was originally in crossing i,j */ a->o2 = i; /* a was originally in crossing i,j */ *b = *a; /* copy everything that is the same */ b->self = i; b->over = 0; b->m = a; b->z = model[i]; model[j] = a; /* tack a onto the front of the string */ model[i] = b; /* tack b onto the front of the string */ } } } } for (i = 0; i < oldcross; ++i) { if (model[i]) m_sort(i, model, list); } } /* ------------------------------------------------------------------------------ The change to the weave is too severe to be handled by special cases. Construct a model of the weave and systematically apply the recursion formula to it. Whenever you get new simple weaves, c_handle them. ------------------------------------------------------------------------------ */ void m_model_weave(word *list, weave *oldweave, weave *newweaves) { node *model[BIGWEAVE]; char mem[BIGMODEL]; char extra[2*sizeof(node)]; m_make(list, model, mem); if (plan.which == (-1)) { m_shrink(list, model, oldweave); } else { m_switch(list, model, extra); } m_recurse(model, list, oldweave, newweaves); } libhomfly-1.02r5/lib/model.h000066400000000000000000000027521321572311100157110ustar00rootroot00000000000000/* --------------------------------------------------------------------------- MODEL.H By Bob Jenkins, August 1990, in association with my Masters Thesis Structures and procedures used for modelling complicated weaves Public Domain --------------------------------------------------------------------------- */ #ifndef MODEL #define MODEL # include "standard.h" # include "bound.h" /* When weaves are complicated enough to need modeling, a model of them is made using singly linked lists of type node. Something of type node is a single node in a string in a weave. */ struct node { word self; /* number of string m belongs to */ word right; /* the crossing this node is in is righthanded */ word over; /* this node is an overpass */ word correct; /* is this node where it ought to be? */ struct node *m; /* other node in this crossing */ struct node *z; /* next node in this string */ word o1; /* number of original string 1 */ word o2; /* number of original string 2 */ }; typedef struct node node; #define BIGMODEL (((MAXSTRING)*(MAXSTRING-1)+2)*sizeof(node)) /* Public procedures defined in model.c */ /* Handle weaves that need to be modeled */ void m_model_weave(word *list, weave *oldweave, weave *newweaves); #endif /* MODEL */ libhomfly-1.02r5/lib/order.c000066400000000000000000000172711321572311100157210ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ By Bob Jenkins, 1989, in association with his thesis project Public Domain ------------------------------------------------------------------------------ */ #include #include #include "standard.h" #include "dllink.h" #include "knot.h" #include "order.h" /* o_tabs: mark the neighbors and the neighbors of the neighbors */ #define o_tabs( k, t, big) \ if (1) \ { \ (t)[(k)->o->c] += (big); \ (t)[(k)->o->a->c] += 2; \ (t)[(k)->o->z->c] -= 1; \ (t)[(k)->u->a->c] += 2; \ (t)[(k)->u->z->c] -= 1; \ } else /* This assumes that every crossing is used. This lists the crossings in an order my algorithm will hopefully like. */ static void o_order2( crossing *k, word *oldorder, word *order, word crossings) { word tab[MAXCROSS]; word j, *ip, *endp, tmp1, tmp2; crossing *kp, *kp2; for (ip = tab, endp = tab+crossings; ip != endp;) *(ip++) = 0; *order = oldorder[crossings-1]; for (ip = order+1, endp = order+crossings; ip < endp; ip++) { j = *(ip-1); *ip = j; tab[j] -= 100; kp2 = k+j; kp = k+kp2->o->a->c; o_tabs(kp, tab, 16); kp = k+kp2->o->z->c; o_tabs(kp, tab, 20); kp = k+kp2->u->a->c; o_tabs(kp, tab, 16); kp = k+kp2->u->z->c; o_tabs(kp, tab, 20); tmp1 = *ip; for (j = 0; j < crossings; ++j) { tmp2 = oldorder[crossings-1-j]; if (tab[tmp2] > tab[tmp1]) tmp1 = tmp2; } *ip = tmp1; } } /* This assumes that every crossing is used. This lists the crossings in an order my algorithm will hopefully like. */ static void o_order1(crossing *k, word *oldorder, word *order, word crossings) { word tab[MAXCROSS]; word j, *ip, *endp, tmp1, tmp2; crossing *kp2; for (ip = tab, endp = tab+crossings; ip != endp;) *(ip++) = 0; *order = oldorder[crossings-1]; for (ip = order+1, endp = order+crossings; ip != endp; ip++) { j = *(ip-1); *ip = j; tab[j] -= 100; kp2 = k+j; tab[kp2->o->a->c] += 20; tab[kp2->o->z->c] += 20; tab[kp2->u->a->c] += 20; tab[kp2->u->z->c] += 20; tmp1 = *ip; for (j = 0; j < crossings; ++j) { tmp2 = oldorder[crossings-1-j]; if (tab[tmp2] > tab[tmp1]) tmp1 = tmp2; } *ip = tmp1; } } /** * Make instructions for just adding a crossing to the solved region */ static void o_add(word *n, /* in/out: the number of strings in the weave */ dllink **boundary, word *going_in, /* in/out: which strings are inputs */ crossing *k, word newcross, Instruct *answer) { word i; word old; word go_in; word righthanded; dllink *link; /* link in crossing perpendicular to boundary */ word after; /* is the new input after the original string? */ answer->crossing = newcross; answer->oldn = *n; for (i = 0; i<*n; ++i) { answer->going_in[i] = going_in[i]; } /*-------------- Find *old*, try to make it an input rather than an output */ /* Imagine crossing c, input 0 and output n attached to c. If you add the crossing at n, n becomes n+1 and you have input n and output n+2. Then the pair of boundary crossings n+2 and 0 are removed, and string 0 becomes string n (really n-1 since things shift to fill in the missing 0). Changing a string from 0 to n-1 is likely to produce lots of bad crossings. If you added the crossing at the input to begin with, the problem would have been avoided. So try to add crossings at inputs. */ for (i = *n; boundary[--i]->c != newcross;) ; old = i; if (!going_in[i]) { while (i && (boundary[--i]->c != newcross || !going_in[i])); if (boundary[i]->c == newcross && going_in[i]) old = i; } answer->which = old; answer->over = (k[newcross].o == boundary[old]); answer->right = (k[newcross].hand == 1); *n += 2; for (i = *n; --i > old+2;) { boundary[i] = boundary[i-2]; going_in[i] = going_in[i-2]; } go_in = going_in[old]; righthanded = answer->right; link = answer->over ? k[newcross].u : k[newcross].o; going_in[old+1] = go_in; boundary[old+1] = (go_in ? boundary[old]->a : boundary[old]->z); /* crossing are labeled counterclockwise */ after = (go_in ^ righthanded ^ answer->over); if (after) { boundary[old] = link->z; going_in[old] = 0; boundary[old+2] = link->a; going_in[old+2] = 1; } else { boundary[old] = link->a; going_in[old] = 1; boundary[old+2] = link->z; going_in[old+2] = 0; } answer->prev = going_in[old]; answer->newn = *n; answer->reductions = 0; } /** * Make instructions for removing one pair of boundary crossings */ static void o_delete(word *n, dllink **boundary, word *going_in, Instruct *answer, word *done, word i) { word j; dllink *l, *m; j = (i == 0) ? *n-1 : i-1; l = (going_in[i]) ? boundary[i]->z : boundary[i]->a; m = (going_in[j]) ? boundary[j]->z : boundary[j]->a; if ((l == boundary[j]) && (m == boundary[i])) { *done = 0; answer->r0[answer->reductions] = i; answer->r1[answer->reductions] = j; if (i == 0) { for (j = 0; j < (*n)-2; j++) { boundary[j] = boundary[j+1]; going_in[j] = going_in[j+1]; } } else { for (j = i-1; j < (*n)-2; j++) { boundary[j] = boundary[j+2]; going_in[j] = going_in[j+2]; } } answer->reductions++; *n -= 2; } } /* make instructions for handling a single crossing */ static void o_one_make(word *n, dllink **boundary, word *going_in, crossing *k, word which, Instruct *answer) { word i, done; /* Move one crossing into the solved region */ o_add(n, boundary, going_in, k, which, answer); /* Join as many adjacent boundary pairs as possible */ for (done = 0; !done;) { for (i = *n, done = 1; done && (--i >= 0);) { if (*n == 2) break; /* do not shrink to nothing */ o_delete(n, boundary, going_in, answer, &done, i); } } answer->newn = *n; } /* Make complete instructions for handling all the crossings */ void o_make(Link *link, Instruct **list) { word order1[MAXCROSS]; /* order of crossings */ word order2[MAXCROSS]; /* another order of crossings */ dllink *boundary[BIGWEAVE]; word going_in[BIGWEAVE]; word i, j, n; int num_crossings = link->num_crossings; const crossing *k = link->data; Instruct *l; l = (Instruct *)GC_MALLOC(sizeof(Instruct) * num_crossings); for (i = 0; i < num_crossings; order1[i] = i, i++) ; for (i = 0; i < num_crossings; order2[i] = i, i++) ; o_order2(k, order2, order1, num_crossings); o_order1(k, order1, order2, num_crossings); o_order1(k, order2, order1, num_crossings); boundary[0] = k[order1[0]].o; boundary[1] = k[order1[0]].o->z; going_in[0] = 1; going_in[1] = 0; n = 2; for (i = 0; i < num_crossings; ++i) o_one_make(&n, boundary, going_in, k, order1[i], (l+i)); *list = l; } /*void o_show(Instruct *l, word num_crossings) { word i; word j; }*/ libhomfly-1.02r5/lib/order.h000066400000000000000000000041471321572311100157240ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ ORDER.H - Bob Jenkins, 1989, Public Domain Structures and routines used for choosing an order in which to add crossings to the solved region, plus code to make the instructions for how weaves have to change as those crossings are added. ------------------------------------------------------------------------------ */ #ifndef ORDER #define ORDER #include "standard.h" #include "bound.h" #include "knot.h" /* Something of type INSTRUCT can describes manipulations of a weave boundary. There are two types of manipulations: adding a crossing connected by one arc, which uses WHICH, PREV, and OVER; and removing a pair of adjacent boundary crossings, which requires REDUCTIONS and R. Something of type struct INSTRUCT can store one added crossing and 9 boundary removals. */ struct Instruct { word crossing; /* which crossing is added */ word which; /* which arc to add the crossing at (-1 for just removal) */ word prev; /* is new previous boundary crossing an input? */ word over; /* is the old string the overpass? */ word oldn; /* number of boundary crossings in the original weave */ word newn; /* number of boundary crossings in the final weave */ word reductions; /* number of boundary crossing pairs to connect */ word right; /* is this crossing righthanded */ word going_in[BIGWEAVE]; /* which strings are going in */ word r0[MAXSTRING+1]; /* first boundary crossing to connect */ word r1[MAXSTRING+1]; /* second boundary crossing to connect */ }; typedef struct Instruct Instruct; /* Procedures defined in order.c */ void o_make(Link *link, Instruct **list); /* make instructions */ /*void o_show(Instruct *l, word num_crossings);*/ /* display all instructions */ #endif /* ifndef ORDER */ libhomfly-1.02r5/lib/poly.c000066400000000000000000000114651321572311100155700ustar00rootroot00000000000000/* Yet another program by Bob Jenkins. 3/16/88, for 15-451 */ /* Public Domain */ #include #include #include "standard.h" #include "poly.h" /* These macros are machine dependent */ #define p_sign(m) ((sb4)(m)) #define p_cast(m) ((sb2)(m)) #define p_add_pow(m1, m2) ((m1)+(m2)) /* check that the coefficients add up to a power of -2 */ boolean p_check(Poly *p) { ub4 i; sb4 sum; sb4 compare; if (!p || !p->len) return FALSE; for (sum=0, i=0; ilen; ++i) { sum += p->term[i].coef; } for (compare=1; compare && compare != sum; compare *= (sb4)(-2)) { ; } if (!compare) return FALSE; return TRUE; } void p_copy(Poly *inp, Poly *outp) /* This returns a MALLOCed copy of inp. It eliminates all terms with coefficients of 0. */ { Term *interm; Term *outerm; Term *endterm; if (inp->len) { outp->term = (Term *)GC_MALLOC((size_t)(inp->len*sizeof(Term))); for (interm = inp->term, outerm = outp->term, endterm = interm + inp->len; interm != endterm; ++interm) { if (interm->coef) *(outerm++) = *interm; } outp->len = outerm-outp->term; } else { outp->term = (Term *)0; outp->len = 0; } } /* This displays the polynomial p */ char *p_show(Poly *p) { Term *pt; Term *pend; sb4 first; sb4 m; sb4 l; char *bp; size_t size; int pos, offs, maxlen; #define bp_chunksize 10000 #define bp_chunkreserve 500 #define bp_sprintf(...) {\ sprintf(bp+offs, __VA_ARGS__, &pos);\ offs += pos;\ if (offs > maxlen - bp_chunkreserve) {\ maxlen += bp_chunksize + bp_chunkreserve;\ bp = (char *)GC_REALLOC(bp, sizeof(char) * maxlen);\ }\ } maxlen = bp_chunksize + bp_chunkreserve; offs = 0; bp = (char *)GC_MALLOC(sizeof(char) * maxlen); if (!p->len) { bp_sprintf("0%n") return bp; } for (first = 1, pt = p->term, pend = pt+p->len; pt != pend; ++pt) { if (!pt->coef) continue; m = p_sign(pt->m); l = p_sign(pt->l); if (pt->coef < ((sb4)0)) bp_sprintf(" - %n") else if (!first) bp_sprintf(" + %n") if (pt->coef > ((sb4)1) ) bp_sprintf("%ld%n", pt->coef) else if (pt->coef < (sb4)(-1)) bp_sprintf("%ld%n", -pt->coef) else if ((!l) && (!m)) bp_sprintf("%d%n", 1) if (pt->m) { bp_sprintf("M%n") if (m != 1) bp_sprintf("^%ld%n", m) } if (pt->l) { bp_sprintf("L%n") if (l != 1) bp_sprintf("^%ld%n", l) } if (first) first = 0; } return bp; } /* outp = inp + {t.c=c; t.l=l; t.m=m;} */ void p_term(sb4 coef, sb4 m, sb4 l, Poly *inp, Poly *outp) { Poly p[1]; Term t[1]; t->coef = coef; t->m = p_cast(m); t->l = p_cast(l); p->len = 1; p->term = t; p_add(p, inp, outp); } /* This is like a merge sort */ void p_add(Poly *inp1, Poly *inp2, Poly *outp) { Term *t1; Term *t2; Term *tout; Term *end1; Term *end2; sb4 eq1; outp->term = (Term *)GC_MALLOC((size_t)((inp1->len+inp2->len)*sizeof(Term))); t1 = inp1->term; end1 = t1+inp1->len; t2 = inp2->term; end2 = t2+inp2->len; tout = outp->term; if (inp1->len && inp2->len) { while(TRUE) { eq1 = (t1->m == t2->m); if ((t1->m < t2->m) || (eq1 && (t1->l < t2->l))) { *(tout++) = *(t1++); if (t1 == end1) break; } else if ((!eq1) || (eq1 && (t1->l > t2->l))) { *(tout++) = *(t2++); if (t2 == end2) break; } else /* the powers of m and l are equal */ { *(tout) = *(t1); tout->coef = (t1++)->coef + (t2++)->coef; if (!(tout++)->coef) --tout; /* I don't know if this does anything - TCS */ if (t1 == end1) break; if (t2 == end2) break; } } } if (t2 == end2) { while (t1 != end1) *(tout++) = *(t1++); } else /* t1 == end1 */ { while (t2 != end2) *(tout++) = *(t2++); } outp->len = tout-outp->term; } /* *outp = (*inp1)*(*inp2) */ void p_mult(Poly *inp1, Poly *inp2, Poly *outp) /* It is assumed that inp1, inp2, and outp point to existing Poly structs */ { Poly xinp2[1]; Poly temp[1]; Poly *blank; Term *t1; Term *t2; Term *end1; Term *end2; Term *tx; if (inp1->len > inp2->len) { blank = inp1; inp1 = inp2; inp2 = blank; } p_init(outp); xinp2->term = (Term *)GC_MALLOC((size_t)(inp2->len*sizeof(Term))); xinp2->len = inp2->len; for (t1 = inp1->term, end1 = t1 + inp1->len, end2 = inp2->term+inp2->len; t1 < end1; ++t1) { for (t2 = inp2->term, tx = xinp2->term; t2 < end2;) { tx->m = p_add_pow(t1->m, t2->m); tx->l = p_add_pow(t1->l, t2->l); (tx++)->coef = t1->coef * (t2++)->coef; } p_add(outp, xinp2, temp); p_kill(outp); *outp = *temp; } p_kill(xinp2); } libhomfly-1.02r5/lib/poly.h000066400000000000000000000041001321572311100155610ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ POLY.H - Bob Jenkins, 1988, Public Domain Structures and procedures dealing with Laurent polynomials on M and L Laurent polynomials can have integer exponents; not just natural numbers. -(M^-1)(L^-1) - (M^-1)(L^1) is a typical polynomial of this type. ------------------------------------------------------------------------------ */ #ifndef POLY #define POLY #include "standard.h" /* ------------------------------------------------------------------------------ Something of type TERM is a single term in a polynomial. coef is the coefficient of the term. L is the power of L in the term. M is the power of M in the term. ------------------------------------------------------------------------------ */ struct Term { sb4 coef; sb2 m; sb2 l; }; typedef struct Term Term; /* ------------------------------------------------------------------------------ Something of type POLY is a polynomial of M and L. TERM is the array of terms. len is the number of terms. ------------------------------------------------------------------------------ */ struct Poly { Term *term; sb4 len; }; typedef struct Poly Poly; /* ------------------------------------------------------------------------------ Procedures defined in poly.c ------------------------------------------------------------------------------ */ #define p_init( p) ((p)->len = (sb4)0) #define p_kill( p) \ if (1) \ { \ (p)->len = (sb4)0; \ } else //if ((p)->len) free((char *)(p)->term); \ boolean p_check(Poly *p); /* check if a poly is a power of -2 */ void p_copy(Poly *inp, Poly *outp); /* copies a Poly */ char *p_show(Poly *l); /* displays the Poly */ void p_add(Poly *inp1, Poly *inp2, Poly *outp); /* adds two Polys */ void p_mult(Poly *inp1, Poly *inp2, Poly *outp); /* multiply two Polys */ /* returns a poly with term added */ void p_term(sb4 coef, sb4 m, sb4 l, Poly *inp, Poly *outp); #endif /* POLY */ libhomfly-1.02r5/lib/standard.h000066400000000000000000000032271321572311100164070ustar00rootroot00000000000000/* ------------------------------------------------------------------------------ Standard definitions and types, Bob Jenkins ------------------------------------------------------------------------------ */ #ifndef STANDARD # define STANDARD # ifndef STDIO # include # define STDIO # endif /* STDIO */ # ifndef STDDEF # include # define STDDEF # endif /* STDDEF */ typedef unsigned long long ub8; #define UB8MAXVAL 0xffffffffffffffffLL #define UB8BITS 64 typedef signed long long sb8; #define SB8MAXVAL 0x7fffffffffffffffLL typedef unsigned long int ub4; /* unsigned 4-byte quantities */ #define UB4MAXVAL 0xffffffff typedef signed long int sb4; #define UB4BITS 32 #define SB4MAXVAL 0x7fffffff typedef unsigned short int ub2; #define UB2MAXVAL 0xffff #define UB2BITS 16 typedef signed short int sb2; #define SB2MAXVAL 0x7fff typedef unsigned char ub1; #define UB1MAXVAL 0xff #define UB1BITS 8 typedef signed char sb1; /* signed 1-byte quantities */ #define SB1MAXVAL 0x7f typedef int word; /* fastest type available */ typedef int boolean; #define bis(target,mask) ((target) |= (mask)) #define bic(target,mask) ((target) &= ~(mask)) #define bit(target,mask) ((target) & (mask)) #ifndef min # define min(a,b) (((a)<(b)) ? (a) : (b)) #endif /* min */ #ifndef max # define max(a,b) (((a)<(b)) ? (b) : (a)) #endif /* max */ #ifndef align # define align(a) (((ub4)a+(sizeof(void *)-1))&(~(sizeof(void *)-1))) #endif /* align */ #ifndef abs # define abs(a) (((a)>0) ? (a) : -(a)) #endif #define TRUE 1 #define FALSE 0 #define SUCCESS 0 /* 1 on VAX */ #endif /* STANDARD */ libhomfly-1.02r5/test/000077500000000000000000000000001321572311100146435ustar00rootroot00000000000000libhomfly-1.02r5/test/Makefile.am000066400000000000000000000003601321572311100166760ustar00rootroot00000000000000check_PROGRAMS = test_example test_example_SOURCES = test_example.c homfly.h test_example_LDADD = @top_builddir@/lib/libhomfly.la test_example_DEPENDENCIES = @top_builddir@/lib/libhomfly.la TESTS = run_tests EXTRA_DIST = run_tests data.txt libhomfly-1.02r5/test/data.txt000066400000000000000000000054031321572311100163170ustar00rootroot00000000000000Trefoil 1 6 0 1 1 -1 2 1 0 -1 1 1 2 -1 0 1 1 1 2 1 - L^-4 - 2L^-2 + M^2L^-2 four 1 8 0 1 1 -1 2 1 3 -1 1 1 0 -1 3 1 2 -1 0 -1 1 -1 2 1 3 1 - L^-2 - 1 - L^2 + M^2 Boromean 3 4 0 1 2 -1 3 1 5 -1 4 0 -1 1 1 3 -1 4 1 4 1 -1 2 1 4 -1 5 1 0 -1 1 1 2 -1 3 1 4 -1 5 1 M^-2L^-2 + 2M^-2 + M^-2L^2 - M^2L^-2 - 2M^2 - M^2L^2 + M^4 knotseven 7 12 0 1 7 -1 14 1 21 -1 28 1 35 -1 36 1 30 -1 24 1 18 -1 12 1 6 -1 12 1 1 8 -1 15 1 22 -1 29 1 36 -1 37 1 31 -1 25 1 19 -1 13 1 0 -1 12 2 1 9 -1 16 1 23 -1 30 1 37 -1 38 1 32 -1 26 1 20 -1 7 1 1 -1 12 3 1 10 -1 17 1 24 -1 31 1 38 -1 39 1 33 -1 27 1 14 -1 8 1 2 -1 12 4 1 11 -1 18 1 25 -1 32 1 39 -1 40 1 34 -1 21 1 15 -1 9 1 3 -1 12 5 1 12 -1 19 1 26 -1 33 1 40 -1 41 1 28 -1 22 1 16 -1 10 1 4 -1 12 6 1 13 -1 20 1 27 -1 34 1 41 -1 35 1 29 -1 23 1 17 -1 11 1 5 -1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 -1 8 -1 9 -1 10 -1 11 -1 12 -1 13 -1 14 1 15 1 16 1 17 1 18 1 19 1 20 1 21 -1 22 -1 23 -1 24 -1 25 -1 26 -1 27 -1 28 1 29 1 30 1 31 1 32 1 33 1 34 1 35 -1 36 -1 37 -1 38 -1 39 -1 40 -1 41 -1 M^-6L^-6 + 6M^-6L^-4 + 15M^-6L^-2 + 20M^-6 + 15M^-6L^2 + 6M^-6L^4 + M^-6L^6 - 14M^-2L^-6 - 84M^-2L^-4 - 210M^-2L^-2 - 280M^-2 - 210M^-2L^2 - 84M^-2L^4 - 14M^-2L^6 + 28L^-6 + 182L^-4 + 476L^-2 + 644 + 476L^2 + 182L^4 + 28L^6 + 35M^2L^-6 + 182M^2L^-4 + 413M^2L^-2 + 532M^2 + 413M^2L^2 + 182M^2L^4 + 35M^2L^6 - 154M^4L^-6 - 1120M^4L^-4 - 3094M^4L^-2 - 4256M^4 - 3094M^4L^2 - 1120M^4L^4 - 154M^4L^6 + 119M^6L^-6 + 1190M^6L^-4 + 3850M^6L^-2 + 5558M^6 + 3850M^6L^2 + 1190M^6L^4 + 119M^6L^6 - 205M^8L^-6 - 264M^8L^-4 + 467M^8L^-2 + 1052M^8 + 467M^8L^2 - 264M^8L^4 - 205M^8L^6 + 189M^10L^-6 + 399M^10L^-4 - 3591M^10L^-2 - 7602M^10 - 3591M^10L^2 + 399M^10L^4 + 189M^10L^6 - 14M^12L^-6 - 67M^12L^-4 + 798M^12L^-2 + 4103M^12 + 798M^12L^2 - 67M^12L^4 - 14M^12L^6 + 43M^14L^-6 - 1264M^14L^-4 - 847M^14L^-2 + 920M^14 - 847M^14L^2 - 1264M^14L^4 + 43M^14L^6 + 210M^16L^-6 + 1597M^16L^-4 + 6034M^16L^-2 + 4492M^16 + 6034M^16L^2 + 1597M^16L^4 + 210M^16L^6 - 612M^18L^-6 - 2255M^18L^-4 - 7665M^18L^-2 - 12044M^18 - 7665M^18L^2 - 2255M^18L^4 - 612M^18L^6 + 575M^20L^-6 + 3146M^20L^-4 + 5782M^20L^-2 + 10195M^20 + 5782M^20L^2 + 3146M^20L^4 + 575M^20L^6 - 320M^22L^-6 - 2396M^22L^-4 - 4318M^22L^-2 - 4484M^22 - 4318M^22L^2 - 2396M^22L^4 - 320M^22L^6 + 150M^24L^-6 + 1023M^24L^-4 + 2643M^24L^-2 + 2070M^24 + 2643M^24L^2 + 1023M^24L^4 + 150M^24L^6 - 56M^26L^-6 - 340M^26L^-4 - 953M^26L^-2 - 1338M^26 - 953M^26L^2 - 340M^26L^4 - 56M^26L^6 + 12M^28L^-6 + 120M^28L^-4 + 226M^28L^-2 + 530M^28 + 226M^28L^2 + 120M^28L^4 + 12M^28L^6 - M^30L^-6 - 30M^30L^-4 - 75M^30L^-2 - 92M^30 - 75M^30L^2 - 30M^30L^4 - M^30L^6 + 3M^32L^-4 + 24M^32L^-2 + 14M^32 + 24M^32L^2 + 3M^32L^4 - 3M^34L^-2 - 6M^34 - 3M^34L^2 + M^36 libhomfly-1.02r5/test/homfly.h000066400000000000000000000000361321572311100163110ustar00rootroot00000000000000char *homfly_str(char *argv); libhomfly-1.02r5/test/run_tests000077500000000000000000000000421321572311100166130ustar00rootroot00000000000000#!/bin/sh ./test_example data.txt libhomfly-1.02r5/test/test_example.c000066400000000000000000000031331321572311100175010ustar00rootroot00000000000000/** * Run tests */ #include #include #include #include "homfly.h" #define BUFFER_SIZE 2048 /** * Test the library against given data * * usage: $TEST/test_example data.txt * * the data.txt must be formatted with 3 lines per test: * 1 - name * 2 - link info * 3 - expected output * * Each line can be at most 2048 characters. */ int main(int argc, char *argv[]) { char name[BUFFER_SIZE]; char input[BUFFER_SIZE]; char test[BUFFER_SIZE]; char *out; int i; FILE *f; if (argc != 2) { printf("must give exactly one file to test\n"); return 2; } f = fopen(argv[1], "r"); if (f == NULL) { fclose(f); return 1; } while(fgets(name, sizeof(name), f) != NULL) { if(fgets(input, sizeof(input), f) == NULL) { fclose(f); printf("missing link data"); return 3; } if(fgets(test, sizeof(test), f) == NULL) { fclose(f); printf("missing output data"); return 3; } // File ends with \n, but we need to ignore it name[strlen(name)-1] = '\0'; input[strlen(input)-1] = '\0'; test[strlen(test)-1] = '\0'; out = homfly_str(input); if(strcmp(test, out) != 0) { printf("error in computation: %s\n", name); printf("expected: %s\n", test); printf("got : %s\n", out); fclose(f); return 1; } } printf("correct result\n"); fclose(f); return 0; }