CableLink.m: Difference between revisions

From Knot Atlas
Jump to navigationJump to search
No edit summary
Tag: Manual revert
No edit summary
Tag: Manual revert
Line 1: Line 1:
(*


The program <code>CableLink</code> is documented on the page [[Threading a link by a polynomial]]. It is not part of the package <code>KnotTheory`</code> but is designed to work with it. Copy-paste the text below ignoring the <code>*&#41;</code> on the first line and the <code>&#40;*</code> on the last.
The program <code>CableLink</code> is documented on the page [[Threading a link by a polynomial]]. It is not part of the package <code>KnotTheory`</code> but is designed to work with it. Copy-paste the text below ignoring the <code>*&#41;</code> on the first line and the <code>&#40;*</code> on the last.
<pre>
<pre>
*)
*)

*)
(*Kauffman bracket*)
(*Kauffman bracket*)
KB1[pd_PD] := KB1[pd, {}, 1];
KB1[pd_PD] := KB1[pd, {}, 1];

Revision as of 18:34, 5 August 2025

The program CableLink is documented on the page Threading a link by a polynomial. It is not part of the package KnotTheory` but is designed to work with it. Copy-paste the text below ignoring the *) on the first line and the (* on the last.

*)

(*Kauffman bracket*)
KB1[pd_PD] := KB1[pd, {}, 1];
KB1[pd_PD, inside_, web_] := 
  Module[{pos = 
     First[Ordering[Length[Complement[List @@ #, inside]] & /@ pd]]}, 
   pdpos /.  
    X[a_, b_, c_, d_] :> 
     KB1[Delete[pd, pos], Union[inside, {a, b, c, d}], 
      Expand[web*(A P[a, d] P[b, c] + 1/A P[a, b] P[c, d])] //. {P[e_,
            f_] P[f_, g_] :> P[e, g], P[e_, _]^2 :> P[e, e], 
        P[e_, e_] -> -A^2 - 1/A^2}]];
KB1[PD[], _, web_] := Expand[web]
(*determine position of a strand label at a crossing*)
strandAtCrossing[crossing_, s_] := Module[{pos},
   pos = Position[crossing, s];
   If[Length[pos] > 0, pos1, 1, False]
   ];
(*determine orientation of overstrand. Complicated by components with only 2 labels*)
orientationOfOverStrand[crossing_, link_] := Module[{otherCrossings},
   (*find the other crossings containing the strand labels of the overstrand crossing*)
   otherCrossings = 
    DeleteElements[
     Select[link, 
      ContainsAny[
        List[Delete[#, 0]], {crossing2, 
         crossing4}] &], {crossing}];
   (*if the length of othercrossings is 1, 
   then the overstrand labels are part of a component with only two \
strand labels*)
   If[Length[otherCrossings] == 1,
    (*first check if a strand label is in the first position of the \
other crossing.*)
    Which[otherCrossings1, 1 == crossing2,
     True,
     otherCrossings1, 1 == crossing4,
     False,
     (*Otherwise, the strands are always overcrossings, 
     in which case we just choose to orient from small to large*)
     True,
     crossing2 > crossing4
     ],
    (*otherwise, 
    the overcrossing is oriented from 4 to 2 if pos 2 is 1 more than \
pos 4, or if pos 4 is more than 1 greater than pos 2.*)
     crossing2 - crossing4 == 1 || 
     crossing4 - crossing2 > 1
    ]
   ];
(*find crossing where a strand label enters*)
findEnteringVertex[link_, s_] := 
  Module[{crossingsContainingS, firstCrossing, pos},
   (*find crossings containing s*)
   crossingsContainingS = 
    Select[link, IntegerQ[strandAtCrossing[#, s]] &];
   firstCrossing = crossingsContainingS1;
   pos = strandAtCrossing[firstCrossing, s];
   Which[
    (*if pos is 1, then it is definitely an incoming strand*)
    pos == 1,
    firstCrossing,
    (pos == 2 && ! 
        orientationOfOverStrand[firstCrossing, link]) || (pos == 4 && 
       orientationOfOverStrand[firstCrossing, link]),
    firstCrossing,
    (*otherwise it must be the entering strand at the other vertex \
containing that label*)
    True,
    crossingsContainingS2
    ]
   ];
increaseStrandLabels[link_, s_] := 
  Replace[link, n_?(# > s &) -> n + 1, {2}];
decreaseStrandLabels[link_, s_] := 
  Replace[link, n_?(# > s &) -> n - 1, {2}];
(*duplicate a crossing*)
duplicateVertex[link_, crossing_, strands_] := 
  Module[{pos = strandAtCrossing[crossing, strands1], 
    newLabel = Length[link]*2 + 2, 
    newLink = DeleteElements[link, {crossing}], p1 = crossing1, 
    p2 = crossing2, p3 = crossing3, p4 = crossing4},
   Which[
    (*pos is 1 and the upper strand is oriented from 4 to 2*)
    pos == 1  && orientationOfOverStrand[crossing, link],
    {Union[
      increaseStrandLabels[newLink, p4],
      PD[
       X[If[p1 < p2, p1, p1 + 1], p4 + 1, If[p3 < p2, p3, p3 + 1], 
        p4]],
      PD[X[newLabel, If[p2 > p4, p2 + 1, p2], newLabel + 1, p4 + 1]]
      ],
     Map[If[# <= p2, #, # + 1] &, Prepend[strands2 ;;, p3]]
     },
    (*pos is 1 and the upper strand is oriented from 2 to 4*)
    pos == 1,
    {Union[
      increaseStrandLabels[newLink, p2],
      PD[
       X[If[p1 < p2, p1, p1 + 1], p2 + 1, If[p3 < p2, p3, p3 + 1], 
        If[p4 < p2, p4, p4 + 1]]],
      PD[X[newLabel, p2, newLabel + 1, p2 + 1]]
      ],
     Map[If[# <= p2, #, # + 1] &, Prepend[strands2 ;;, p3]]
     },
    (*pos is 2*)
    pos == 2,
    {Union[
      increaseStrandLabels[newLink, p1],
      PD[
       X[p1, If[p2 < p1, p2, p2 + 1], p1 + 1, 
        If[p4 < p1, p4, p4 + 1]]],
      PD[X[p1 + 1, newLabel, If[p3 < p1, p3, p3 + 1], newLabel + 1]]
      ],
     Map[If[# <= p1, #, # + 1] &, Prepend[strands2 ;;, p4]]
     },
    (*pos is 4*)
    True,
    {Union[
      increaseStrandLabels[newLink, p1],
      PD[
       X[p1 + 1, If[p2 < p1, p2, p2 + 1], If[p3 < p1, p3, p3 + 1], 
        If[p4 < p1, p4, p4 + 1]]],
      PD[X[p1, newLabel + 1, p1 + 1, newLabel]]
      ],
     Map[If[# <= p1, #, # + 1] &, Prepend[strands2 ;;, p2]]
     }
    ]
   ];
(*delete a crossing*)
deleteVertex[link_, crossing_, s_, strandList_] := 
 Module[{newCrossing = crossing, 
   newLink = DeleteElements[link, {crossing}], min, max, 
   pos = strandAtCrossing[crossing, s], outgoingStrandPos, 
   newStrandList = strandList},
  (*we create an unknot if the two labels of the other strand at the \
crossing are equal*)
  Which[(pos == 1 && crossing2 == crossing4) , 
   newStrandList = 
    Replace[newStrandList, 
     crossing2 -> 0, {1}], (pos == 2 || pos == 4 ) && 
    crossing1 == crossing3, 
   newStrandList = Replace[newStrandList, crossing1 -> 0, {1}]];
  (*"
	we need to keep track of the outgoing strand label. There's actually \
two ways to know we're done:
	either the outgoing strand is the same as the incoming strand, or \
the whole vertex only involves 2 different labels.
"*)
  outgoingStrandPos = Which[pos == 1, 3, pos == 2, 4, True, 2];
  If[crossingoutgoingStrandPos == s || 
    CountDistinct[{Delete[crossing, 0]}] < 3, 
   outgoingStrandPos = -1];
  (*adjust link after combining pos 1 and pos 3*)
  If[crossing1 > crossing3,
   newLink = 
    decreaseStrandLabels[
     Replace[newLink, crossing1 -> crossing3, {2}], 
     newCrossing1];
   newCrossing = 
    decreaseStrandLabels[{Replace[newCrossing, 
        crossing1 -> crossing3, {1}]}, 
      newCrossing1]1;
   newStrandList = 
    Map[If[# > newCrossing1, # - 1, #] &, 
     Replace[newStrandList, crossing1 -> crossing3, {1}]]
   ,
   newLink = decreaseStrandLabels[newLink, newCrossing1];
   newCrossing = 
    decreaseStrandLabels[{newCrossing}, newCrossing1]1;
   newStrandList = 
    Map[If[# > newCrossing1, # - 1, #] &, newStrandList]
   ];
  (*adjust link after combining pos 2 and pos 4*)
  min = Min[newCrossing2, newCrossing4];
  max = Max[newCrossing2, newCrossing4];
  If[max - min > 1,
   newLink = 
    decreaseStrandLabels[Replace[newLink, max -> min, {2}], max];
   newCrossing = 
    decreaseStrandLabels[{Replace[newCrossing, max -> min, {1}]}, 
      max]1;
   newStrandList = 
    Map[If[# > max, # - 1, #] &, 
     Replace[newStrandList, max -> min, {1}]],
   newLink = decreaseStrandLabels[newLink, min];
   newCrossing = decreaseStrandLabels[{newCrossing}, min]1;
   newStrandList = Map[If[# > max, # - 1, #] &, newStrandList]
   ];
  {newLink, 
   If[outgoingStrandPos > 0, newCrossingoutgoingStrandPos, -1], 
   newStrandList}
  ]
cableComponent[link_, s_, strandList_] := 
  Module[{initialStrands, newComponentLabel = 2 Length[link] + 1},
   initialStrands = Join[{s, s, newComponentLabel}, strandList];
   recurse[newLink_, strands_] := 
    Module[{currentStrand = strands1, firstStrand = strands2, 
      currentCrossing, updatedLink, 
      updatedStrands},(*copy the current crossing*)
     currentCrossing = findEnteringVertex[newLink, currentStrand];
     {updatedLink, updatedStrands} = 
      duplicateVertex[newLink, currentCrossing, strands];
     (*check if we've returned to the first strand*)
     If[updatedStrands1 == updatedStrands2,
      (*replace the largest strand label with the first strand label \
of the new component*)
      {Replace[updatedLink, 
        n_?(# == 2 Length[updatedLink] + 1 &) -> 
         updatedStrands3, {2}], 
       updatedStrands4 ;;},(*keep adding crossings*)
      recurse[updatedLink, updatedStrands]]
     ];
   recurse[link, initialStrands]
   ];
deleteComponent[link_, s_, strandList_] := 
  Module[{newLink, currentStrand, newStrandList, currentCrossing},
   If[s <= 0,
    (*we're done deleting stuff*)
    {link, strandList},
    (*keep deleting*)
    currentCrossing = findEnteringVertex[link, s];
    {newLink, currentStrand, newStrandList} = 
     deleteVertex[link, currentCrossing, s, strandList];
    deleteComponent[newLink, currentStrand, newStrandList]
    ]
   ];
cableLinkMonomial[link_, strandList_, degreeList_] := 
  Module[{newLink = link, newStrandList, newDegreeList, coeff = 1},
   (*reorder so that we're deleting components first*)
   {newDegreeList, newStrandList} = {degreeList, strandList}[[All, 
     Ordering@degreeList]];
   (*start cabling*)
   Do[
    Which[
     newStrandListi == 0,
     (*it's an unknot*)
     coeff = coeff*(-A^2 - A^(-2))^newDegreeListi,
     newDegreeListi == 0,
     (*we need to delete it*)
     {newLink, newStrandList} = 
      deleteComponent[newLink, newStrandListi, newStrandList],
     True,
     (*cable the component*)
     Do[
      {newLink, newStrandList} = 
       cableComponent[newLink, newStrandListi, newStrandList]
      , {j, 1, newDegreeListi - 1}]
     ]
    , {i, 1, Length[newStrandList]}
    ];
   coeff*KB1[newLink]
   ];
CableLink[link_, poly_, strandList_, vars_] := 
 Module[{monomials = CoefficientRules[poly, vars], temp},
  Total[
   Map[
    #2*cableLinkMonomial[link, strandList, #1] &
    , monomials]]
  ]