A Knotty situation
Brain-Flak, 1316 bytes
(({})<({()<(({}<>))><>}){(({})[()()]<{([{}]({})<>({}<>))}{}(([({}<>)]<<>({}<>)<>((({})<<>{({}<>)<>}<>>))>)){({}<>)<>}<>{}(({}<{}(({}<{({}<>)<>}>))>))<>{({}<>)<>}>)}<>>){(({}){}()<({}<>)>)<>{}(({}){}<>)<>}<>{}{}(()){(<({}<({}<>)>)>)<>((){[()](<(({})<>){({}[({})]<>({}<>))}{}({}<>({}<{}<>{({}<>)<>}>)[()])<>({}({})[()])(([()]{()(<({}[({})]())>)}{})<{(<{}{}>)}{}><>{()((<({}()[({}<>)])<>>))}{}<{}{}>)((){[()]<({}()<({}<({}<<>({()<({}<>)<>>}<>){({}[()]<(({})<({()<({}<>)<>>})<>>)<>{({}[()]<<>({}<>)>)}{}>)}<>>)<>>)>)((){[()](<{}(({})<<>(({})<(<<>({}<<>({}<(()()){({}[()]<([{}]()<>)<>({}<<>{({}({})<>[({}<>)])}{}{}>){({}<>)<>}<>>)}{}>{})>)>)<>{}{({}<>)<>}<>([({}<>)]<((()))>)(())<>({}<>)<>{}({}[()]){<>({}<<>(()()){({}[()]<({}<<>{({}<>)<>}>){({}[({})]<>({}<>))}{}(({})<<>({}<>)<>([{}])>)>)}{}{}>)<>({}<(({})())>[()]<>)}{}({}<<>{}([{}]()<{({}<>)<>}>){({}({})<>[({}<>)])}{}{}>){({}<>)<>}<>{}{}{}>{})>)>)}{}){(<{}(({})<<>(({}{})<<>(<({}<>)>)<>{}{({}<>)<>}<>>(({}){}){})>)>)}>}{}){(<{}([{}]<({}<<>([{}]()<>)<>({}<<>{({}({})<>[({}<>)])}{}{}>){({}<>)<>}<>>({})({}){})>)>)}{}>)}{}){{}(([{}]){}<>{}{}<<>({}<>{}){([{}]({}()()<{}({}<>)(())<>>))}{}{}{}>{})(())<>{{}({}<>)(())<>}(<>)<>}{}}{}{}<>{}{}({}<{{}({}<>)(())<>}<>{{}{((<(())>))}{}}{}{{}({}<>)(())<>}>)<>{{}({}<(<()>)<>([]){{}({}<>)(())<>([])}{}>)<>{{}({}<>)<>}{}{}({}<>)<>}<>
Try it online!
I regret nothing. Input is a flattened list of pairs.
# Part 1: extract edges
(({})<
({()<(({}<>))><>}){
(({})[()()]<
{([{}]({})<>({}<>))}{}(([({}<>)]<<>({}<>)<>((({})<<>{({}<>)<>}<>>))>)){({}<>)<>}
<>{}(({}<{}(({}<{({}<>)<>}>))>))<>{({}<>)<>}
>)}
<>>){(({}){}()<({}<>)>)<>{}(({}){}<>)<>}<>
{}{}(())
# Part 2: Compute bracket polynomial
{
# Move degree/sign to other stack
(<({}<({}<>)>)>)<>
# If current shape has crossings:
((){[()](<
# Consider first currently listed edge in set
# Find the other edge leaving same crossing
(({})<>){({}[({})]<>({}<>))}{}
# Move to top of other stack
# Also check for twist
({}<>({}<{}<>{({}<>)<>}>)[()])
# Check for twist in current edge
<>({}({})[()])
(
# Remove current edge if twist
([()]{()(<({}[({})]())>)}{})<{(<{}{}>)}{}>
# Remove matching edge if twist
<>{()((<({}()[({}<>)])<>>))}{}<{}{}>
# Push 1 minus number of twists from current vertex.
)
# If number of twists is not 1:
((){[()]<
# While testing whether number of twists is 2:
({}()<
# Keep sign/degree on third stack:
({}<({}<
# Duplicate current configuration
<>({()<({}<>)<>>}<>){({}[()]<(({})<({()<({}<>)<>>})<>>)<>{({}[()]<<>({}<>)>)}{}>)}
# Push sign and degree on separate stacks
<>>)<>>)
# If number of twists is not 2: (i.e., no twists)
>)((){[()](<{}
# Make first copy of sign/degree
(({})<<>(({})<
# Make second copy of sign/degree
(<<>({}<<>({}<
# Do twice:
(()()){({}[()]<
# Prepare search for vertex leading into crossing on other side
([{}]()<>)
# While keeping destination on third stack:
<>({}<
# Search for matching edge
<>{({}({})<>[({}<>)])}{}
# Replace old destination
{}>)
# Move back to original stack
{({}<>)<>}<>
>)}{}
# Add orientation to degree
>{})>)>)
# Move duplicate to left stack
<>{}{({}<>)<>}<>
# Create "fake" edges from current crossing as termination conditions
([({}<>)]<((()))>)(())<>
# Create representation of "top" new edge
({}<>)<>{}({}[()])
# While didn't reach initial crossing again:
{
# Keep destination of new edge on third stack
<>({}<<>
# Do twice:
(()()){({}[()]<
# Search for crossing
({}<<>{({}<>)<>}>){({}[({})]<>({}<>))}{}
# Reverse orientation of crossing
(({})<<>({}<>)<>([{}])>)
>)}{}
# Remove extraneous search term
{}
# Push new destination for edge
>)
# Set up next edge
<>({}<(({})())>[()]<>)
}
# Get destination of last edge to link up
{}({}<
# Find edge headed toward original crossing
<>{}([{}]()<{({}<>)<>}>){({}({})<>[({}<>)])}
# Replace destination
{}{}>)
# Move everything to left stack
{({}<>)<>}
# Clean up temporary data
<>{}{}{}
# Push new sign/degree of negatively smoothed knot
>{})>)
# Else (two twists)
# i.e., crossing is the twist in unknot with one half-twist
>)}{}){(<{}
# Copy sign and degree+orientation
(({})<<>(({}{})<
# Move sign to left stack
<>(<({}<>)>)
# Move copy of configuration to left stack
<>{}{({}<>)<>}
# Add an additional 4*orientation to degree
<>>(({}){}){})>)
>)}
# Else (one twist)
>}{}){(<
# Invert sign and get degree
{}([{}]<({}<
# Search term for other edge leading to this crossing
<>([{}]()<>)
# With destination on third stack:
<>({}<
# Find matching edge
<>{({}({})<>[({}<>)])}{}
# Replace destination
{}>)
# Move stuff back to left stack
{({}<>)<>}<>
# Add 3*orientation to degree
>({})({}){})>)
>)}{}
# Else (no crossings)
>)}{}){{}
# If this came from the 2-twist case, undo splitting.
# If this came from an initial empty input, use implicit zeros to not join anything
# New sign = sign - 2 * next entry sign
(([{}]){}<>{}{}<
# New degree = average of both degrees
<>({}<>{})
# Find coefficient corresponding to degree
{([{}]({}()()<{}({}<>)(())<>>))}{}{}
# Add sign to coefficient
{}>{})
# Move rest of polynomial back to right stack
(())<>{{}({}<>)(())<>}
# Set up next configuration
(<>)<>
}{}
}{}{}<>{}
# Step 3: Put polynomial in correct form
# Keeping constant term:
{}({}<
# Move to other stack to get access to terms of highest absolute degree
{{}({}<>)(())<>}<>
# Remove outer zeros
{{}{((<(())>))}{}}
# Move back to right stack to get access to lower order terms
{}{{}({}<>)(())<>}
>)<>
# While terms remain:
{
# Move term with positive coefficient
{}({}<(<()>)<>([]){{}({}<>)(())<>([])}{}>)<>{{}({}<>)<>}{}
# Move term with negative coefficient
{}({}<>)<>
}<>
K (ngn/k), 196 193 185 177 172 bytes
-2 bytes thanks to @coltim
{N::2*n:#x;+/(-m-|/m:#'b)(|0,)/'b:(+/1-2*s){,/(&0|2*x;(#1_?{y[x]&:y@|x;y}[+,/y]/!N){-x+|x,:&4}/1;&0|-2*x)}'N!({(x,'1+|x;x+/:!2)}'(0<x)|:/'+(2*!n;-1+x|-x))@'/:+(0<y)=s:!n#2}
Try it online!
ungolfed:
f:{ /args: x:dowker notation, y:crossing signs
N::2*n:#x /n:number of crossings, N:twice n
s:1-2*!n#2 /s:all possible sets of smoothing signs for the crossings (n*(2^n) matrix of -1 1)
S:{(x,'1+|x;0 1+\:x:(0<x)|:/y,-1+x|-x)} /S:smoothe the crossing numbered x,y in dowker notation (x can be negative)
a:N!(x S'2*!n)@'/:+~y=s /generate all possible smoothed knots (results consist of neighbour pairs that form sets of disjoint unknots)
u::{#1_?{y[x]&:|y x;y}[+,/x]/!N} /count number of disjoint unknots in a smoothed knot, minus one
/ ^^^^^^^^^^^^^^^^^^^^^ / transitive closure
g::{-x+|x,:&4} /if x=L(A) is a laurent polynomial represented as list of coefficients centred on A^0 (the constant term)
/ / then g[x] represents (-A^2-A^(-2))*L(A)
b:(+/s){,/(0<x)|:/(u[y]g/1;&2*x|-x)}'a /build a laurent polynomials for each set of smoothing signs
+/(-m-|/m:#'b)(|0,)/'b} /centre them and pad them to form a matrix and sum them to get the bracket polynomial