newPackage(
    "ThinSincereQuivers",
    Headline => "Construction of flow polytopes and their associated quivers",
    Version => "0.0",
    Date => "November 20, 2019",
    Authors => {
        {Name => "Mary Barker",
         Email => "marybarker@wustl.edu",
         HomePage => "https://github.com/marybarker"}, 
        {Name => "Patricio Gallardo",
         Email => "pgallard@ucr.edu",
         HomePage => "http://patriciogallardo.com/"
        }
    },
    PackageImports => {"Graphs", "Polyhedra", "LatticePolytopes"},
    PackageExports => {"Graphs", "Polyhedra"}
)
export {
-- Methods/Functions
    "allSpanningTrees",
    "basisForFlowPolytope",
    "bipartiteQuiver",
    "chainQuiver",
    "coneSystem",
    "flowPolytopeVertices",
    "getWeights",
    "incInverse",
    "isAcyclic",
    "isClosedUnderArrows",
    "isSemistable",
    "isStable",
    "isTight",
    "isWellDefined",
    "makeTight",
    "maxCodimensionUnstable",
    "maximalNonstableSubquivers",
    "maximalUnstableSubquivers",
    "mergeOnArrow",
    "mergeOnVertex",
    "potentialWalls",
    "primitiveArrows",
    "quiverIncidenceMatrix",
    "quiverEdges",
    "quiverFlow",
    "quiverVertices",
    "quiverWeights",
    "referenceThetas",
    "samePolytope",
    "stableTrees",
    "subquivers",
    "threeVertexQuiver",
    "wallType",
-- Options
    "AsSubquiver",
    "Flow",
    "ReturnSingletons",
-- Quiver objects 
    "ToricQuiver",
    "toricQuiver"
}
-----------------------------------------------------------
-- PACKAGE GLOBALS: special variable names, types, and constants
-----------------------------------------------------------
protect Axis
protect EdgesAdded
protect flow
protect IncidenceMatrix
protect NonSingletons
protect Oriented
protect Q0
protect Q1
protect Qplus
protect RavelLoops
protect Replacement
protect SavePath
protect Singletons
protect WallType
protect weights

ToricQuiver = new Type of HashTable
Wall = new Type of HashTable

-----------------------------------------------------------


-----------------------------------------------------------
-- PACKAGE METHODS/FUNCTIONS:
-----------------------------------------------------------

-----------------------------------------------------------
-- Toric Quiver constructor
-----------------------------------------------------------
toricQuiver = method(Options => {Flow => "Default"})
-- construct ToricQuiver from incidence matrix
toricQuiver(Matrix) := ToricQuiver => opts -> Q -> (
    F := 0.5*sumList(for x in entries(Q) list(for y in x list(abs(y))), Axis => "Col");
    if opts.Flow == "Canonical" then (
        F = asList(numColumns(Q):1);
    ) else if opts.Flow == "Random" then (
        F = for i in (0..#F - 1) list(random(ZZ));
    );
    -- set Q to be unit valued to apply flow
    Q = matrix(for e in entries(Q) list(for x in e list(if abs(x) > 0 then x/abs(x) else 0)));

    -- find lexicographic ordering on edges for standard quiver representation
    Qi := sortedIndices(graphEdges(Q, Oriented => true));
    new ToricQuiver from hashTable{
        IncidenceMatrix => Q_Qi,
        Q0 => toList(0..numRows(Q) - 1),
        Q1 => sort(graphEdges(Q, Oriented => true)),
        flow => F_Qi,
        weights => sumList(entries(Q*diagonalMatrix(F)), Axis => "Row"),
        synonym => "toric quiver"
    }
)
-- construct ToricQuiver from incidence matrix and a flow
toricQuiver(Matrix, List) := ToricQuiver => opts -> (Q, F) -> (
    -- set Q to be unit valued to apply flow
    Q = matrix(for e in entries(Q) list(for x in e list(if abs(x) > 0 then x/abs(x) else 0)));
    -- find lexicographic ordering on edges for standard quiver representation
    Qi := sortedIndices(graphEdges(Q, Oriented => true));
    new ToricQuiver from hashTable{
        IncidenceMatrix => Q_Qi,
        Q0 => toList(0..numRows(Q) - 1),
        Q1 => sort(graphEdges(Q, Oriented => true)),
        flow => asList(F)_Qi,
        weights => sumList(entries(Q*diagonalMatrix(F)), Axis => "Row"),
        synonym => "toric quiver"
    }
)
-- construct ToricQuiver from Toric quiver to copy graph
toricQuiver(ToricQuiver) := ToricQuiver => opts -> Q -> (
    toricQuiver(Q.IncidenceMatrix, Q.flow, Flow => opts.Flow)
)
-- construct ToricQuiver from Toric quiver (to copy graph) and list(giving a flow)
toricQuiver(ToricQuiver, List) := ToricQuiver => opts -> (Q, F) -> (
    toricQuiver(Q.IncidenceMatrix, F)
)
-- construct ToricQuiver from list of edges
toricQuiver(List) := ToricQuiver => opts -> E -> (
    Q := graphFromEdges(sort(E), Oriented => true);
    F := asList(#E:1);
    if opts.Flow == "Random" then (
        F = for i in (0..#E - 1) list(random(ZZ));
    );
    new ToricQuiver from hashTable{
        IncidenceMatrix => Q,
        Q0 => asList(0..numRows(Q) - 1),
        Q1 => E,
        flow => F,
        weights => sumList(entries(Q*diagonalMatrix(F)), Axis => "Row"),
        synonym => "toric quiver"
    }
)
-- construct ToricQuiver from list of edges and a flow
toricQuiver(List, List) := ToricQuiver => opts -> (E, F) -> (
    -- find lexicographic ordering on edges for standard quiver representation
    Qi := sortedIndices(E);

    Q := matrix graphFromEdges(E_Qi, Oriented => true);
    new ToricQuiver from hashTable{
        IncidenceMatrix => Q,
        Q0 => toList(0..numRows(Q) - 1),
        Q1 => E_Qi,
        flow => F_Qi,
        weights => sumList(entries(Q*diagonalMatrix(F)), Axis => "Row"),
        synonym => "toric quiver"
    }
)
-- construct ToricQuiver from a Graph object
toricQuiver(Graph) := ToricQuiver => opts -> G -> (
    E := for e in edges(G) list toList(e);
    toricQuiver(E, Flow => opts.Flow)
)
-- construct ToricQuiver from a Graph and a flow
toricQuiver(Graph, List) := ToricQuiver => opts -> (G, F) -> (
    E := for e in edges(G) list toList(e);
    toricQuiver(E, F)
)
-- subquiver of a ToricQuiver by taking a subset of the arrows, represented as a "child" of the original quiver
ToricQuiver ^ List := ToricQuiver => (TQ, L) -> (
    if any(L, x -> (x < 0) or (x >= #TQ.Q1)) then {
      error "invalid range for subsetting quiver edges";
    };
    newFlow := TQ.flow;
    Lc := asList(set(0..#TQ.flow - 1) - set(L));
    for i in Lc do(newFlow = replaceInList(i, 0, newFlow));
    toricQuiver(TQ.IncidenceMatrix, newFlow)
)
-- subquiver of a ToricQuiver by removing all vertices/arrows not in the subquiver
ToricQuiver _ List := ToricQuiver => (TQ, L) -> (
    if any(L, x -> (x < 0) or (x >= #TQ.Q1)) then {
      error "invalid range for subsetting quiver edges";
    };
    M := matrix(for x in entries(TQ.IncidenceMatrix_L) list(if any(x, y-> y != 0) then (x) else (continue;)));
    toricQuiver(M)
)
-- equality of two quivers:
ToricQuiver == ToricQuiver := Boolean => (TQ1, TQ2) -> (
    (TQ1.Q1 === TQ2.Q1) and (TQ1.flow == TQ2.flow)
)
------------------------------------------------------------




------------------------------------------------------------
-- OTHER EXPORTED FUNCTIONS
------------------------------------------------------------


------------------------------------------------------------
allSpanningTrees = (TQ) -> (
    Q := TQ.IncidenceMatrix;
    Q0 := numRows(Q);
    Q1 := numColumns(Q);

    --  edges of quiver Q represented as a list of tuples
    allEdges := graphEdges(Q, Oriented => true);
    allNodes := asList(0..Q0-1);

    trees := {};
    edgeIndices := {};
    
    -- in any tree, the number of edges should be #vertices - 1, 
    -- and so we need to remove Q1 - (Q0-1) edges to obtain a tree

    d := Q1 - Q0 + 1;
    if d > 0 then (
        -- try removing every combination of d edges and see if result is a tree
        dTuplesToRemove := combinations(d, asList(0..#allEdges-1), Replacement => false, Order => false);
        edgesKept := {};
        edgesRemoved := {};

        trees = for dTuple in dTuplesToRemove list (
            edgeIndices = asList(set(0..#allEdges - 1) - set(dTuple));
            edgesKept = allEdges_edgeIndices;
            edgesRemoved = allEdges_dTuple;

            reducedG := transpose(matrix(for e in edgesKept list(
                t := e#0;
                h := e#1;
                localE := asList(Q0:0);
                localE = replaceInList(h,  1, localE);
                localE = replaceInList(t, -1, localE);
                localE
            )));
            if numColumns(reducedG) > 1 then (
                notAnyCycles := not existsUnorientedCycle(reducedG);
                if isGraphConnected(reducedG) and notAnyCycles then (
                    edgeIndices
                ) else ( 
                    continue;
                )
            ) else (
                edgeIndices
            )
        );
    );
    trees
)
------------------------------------------------------------


------------------------------------------------------------
-- creates a basis for the |Q1|-|Q0|+1 dimensional subspace of R^|Q1| 
-- to write the associated flow polytopes in. 
basisForFlowPolytope = method()
basisForFlowPolytope (List, ToricQuiver) := Matrix => (ST, Q) -> (
    removedEdges := asList(set(0..#Q.Q1 - 1) - set(ST));
    es := ST | removedEdges;

    f := for i from 0 to #removedEdges - 1 list(
        edge := Q.Q1_removedEdges#i;
        edgeList := ST | {removedEdges#i};
        cycle := primalUndirectedCycle(Q.Q1_ST | {edge});

        fi := #es:0;
        for j in cycle do (
            if j >= 0 then (
                fi = replaceInList(edgeList#j, 1, fi)
            ) else (
                k := -(1 + j);
                fi = replaceInList(edgeList#k, -1, fi)
            );
        );
        fi
    );
    output := for j from 0 to #es - 1 list(
        for i from 0 to #removedEdges - 1 list(
            ff := f#i;
            ff#j
        )
    );
    matrix output
)
basisForFlowPolytope ToricQuiver := Matrix => Q -> (
    (sT, removedEdges) := spanningTree(Q.IncidenceMatrix);
    return basisForFlowPolytope(sT, Q)
)
------------------------------------------------------------


------------------------------------------------------------
bipartiteQuiver = {Flow => "Canonical"} >> opts -> (a, b) -> (
    if instance(opts.Flow, List) then (
        if #opts.Flow != a*b then (
            print("error: provided flow is not correct length.");
            return;
        );
        toricQuiver(flatten(for ai from 0 to a - 1 list(for bi from 0 to b - 1 list({ai, a+bi}))), opts.Flow)
    ) else (
        toricQuiver(flatten(for ai from 0 to a - 1 list(for bi from 0 to b - 1 list({ai, a+bi}))), Flow => opts.Flow)
    )
)
------------------------------------------------------------


------------------------------------------------------------
chainQuiver = {Flow => "Canonical"} >> opts -> (numEdges) -> (
    Es := flatten for v from 0 to #numEdges - 1 list(
        numEs := numEdges#v;
        for j from 1 to numEs list({v, v+1})
    );
    if instance(opts.Flow, List) then (
        if #opts.Flow != sum(numEdges) then (
            print("error: provided flow is not correct length.");
            return;
        );
        return toricQuiver(Es, opts.Flow)
    ) else (
        return toricQuiver(Es, Flow => opts.Flow)
    )
)
------------------------------------------------------------


------------------------------------------------------------
coneSystem = Q -> (
    STs := allSpanningTrees(Q);
    allArrows := entries transpose Q.IncidenceMatrix;
    QDim := #Q.Q1 - #Q.Q0 + 1;
    coneDim := #Q.Q0 - 1;

    -- create list of cones CT for each tree T
    treeChambers := unique for T in STs list(transpose matrix allArrows_T);
    treeChambers = for T in treeChambers list(coneFromVData T);

    if #treeChambers > 1 then (
        -- find all pairs of cones with full-dimensional intersection
        aij := for i in 0..#treeChambers-1 list(
            tci := treeChambers#i;
            for j in i+1..#treeChambers-1 list(

                tcj := treeChambers#j;
                irs := intersection(tci, tcj);
                if dim irs >= coneDim then (j) else (continue;)
            )
        );

        -- now add each cone CT to the list of admissible subcones 
        -- before adding every possible intersection to the list as well.
        ssets := for t in treeChambers list(rays t);
        addedTo := unique treeChambers; -- keep track of cones that have already been added
        lastList := for tIdx in 0..#treeChambers-1 list(t:=treeChambers#tIdx; {t, tIdx});
        -- generate all possible intersections of cones
        for ctr in 0..#STs-1 do(
            -- stopping condition: if all intersections tried in the latest loop iteration are up lower-dim
            allEmpty := true; 

            -- create a list of intersecting pairs from intersecting treeChamber elements with lastList elements
            currentList := flatten for LE in lastList list(
                i := round LE#1; -- make index an int
                TI := LE#0; -- current cone
                if toString aij#i != "null" then ( -- loop through all cones that intersect with cone i nontrivially
                    for j in aij#i list(
                        TJ := treeChambers#j;
                        TIJ := intersection(TI, TJ);
                        if (dim TIJ >= coneDim) then (
                            allEmpty = false;
                            if not isIn(TIJ, addedTo) then (
                                addedTo = addedTo | {TIJ};
                                {TIJ, j}
                            ) else (continue;)
                        ) else (continue;)
                    )
                ) else (continue;)
            );
            if allEmpty then (
               break;
            ) else (
               lastList = asList(currentList);
               ssets = ssets | apply(lastList, x -> rays x#0);
            );
        );

        -- now take the finest (in terms of containment) subsets to partition the cone system
        finestSubsets := for i in 0..#ssets-1 list(
            ssi := coneFromVData ssets#i;
            containsSomething := false;

            for j in 0..#ssets-1 do(
                if not (i == j) then (
                    ssj := coneFromVData ssets#j;
                    if contains(ssi, ssj) then (
                        containsSomething = true;
                    )
                );
            );
            if not containsSomething then (
                ssi
            ) else (continue;)
        );
        finestSubsets
    ) else (
        rays first treeChambers
    )
)
------------------------------------------------------------


------------------------------------------------------------
flowPolytopeVertices = method(Options => {Format => "SimplifiedBasis"})
flowPolytopeVertices(List, ToricQuiver) := opts -> (th, Q) -> (
    if #th != numRows Q.IncidenceMatrix then (
        print("error: the provided weight is in incorrect dimension");
        return {};
    );
    -- vertices of flow polytope correspond to regular flows on spanning trees
    allTrees := allSpanningTrees(Q);
    regularFlows := unique for x in allTrees list(
        if all(incInverse(th, Q^x), y -> y >= 0) then (
            incInverse(th, Q^x)
        ) else (continue;)
    );
    if #regularFlows < 1 then (
        {}
    ) else (
        -- simplified basis option reduces the dimension to what is strictly necessary.
        -- Recall we can represent the polytope in a lower dimensional subspace of R^Q1, 
        -- since the polytope has dimension |Q1|-|Q0|+1 <= |Q1|
        if instance(opts.Format, String) and (toString(opts.Format) != "SimplifiedBasis") then (
            regularFlows
        ) else (

            -- first generate a basis (ether user-specified or generated from first spanning tree)
            fpb := {};
            if instance(opts.Format, List) then ( -- if Format is a spanning tree
                fpb = basisForFlowPolytope(opts.Format, toricQuiver(Q, incInverse(th, Q)));
            ) else ( -- if Format is the string "SimplifiedBasis" 
                fpb = basisForFlowPolytope(toricQuiver(Q, incInverse(th, Q)));
            );

            -- translate regularFlows to contain origin by subtracting of first of them from all
            kerF := flatten for f in regularFlows list(
                ff := f - regularFlows#0;
                entries transpose solve(fpb, matrix(for fff in ff list ({round fff})))
            );

            -- translate interior point to origin(if interior lattice point exists)
            ip := interiorLatticePoints convexHull transpose matrix kerF;
            if #ip > 0 then (
                ip = first entries transpose first ip;
                for e in kerF list(e - ip)
            ) else (
                kerF
            )
        )
    )
)
flowPolytopeVertices ToricQuiver := opts -> Q -> (
    flowPolytopeVertices(Q.weights, Q, Format => opts.Format)
)
------------------------------------------------------------


------------------------------------------------------------
-- preimage of the weight th under the incidence map. 
-- NOTE: This function assumes that th is indeed a weight
incInverse = method()
incInverse(List, ToricQuiver) := List => (th, tQ) -> (
    nonzeroFlows := for t in tQ.flow list(if t != 0 then 1 else 0);
    a := tQ.IncidenceMatrix;
    a = a * diagonalMatrix(nonzeroFlows);
    b := matrix(for t in th list {floor t}) **QQ;
    F := solve(a **QQ, b);
    flatten entries first asList F
)
------------------------------------------------------------


------------------------------------------------------------
isAcyclic = method()
isAcyclic(Matrix) := Boolean => Q -> (
    not existsOrientedCycle(Q)
)
isAcyclic(ToricQuiver) := Boolean => Q -> (
    not existsOrientedCycle(Q.IncidenceMatrix)
)
------------------------------------------------------------


------------------------------------------------------------
isClosedUnderArrows = method()
isClosedUnderArrows (Matrix, List) := Boolean => (Q, V) -> (
    Qt := transpose(Q);
    sQ := entries(Qt_V);
    all(sumList(sQ, Axis => "Row"), x -> x >= 0)
)
isClosedUnderArrows (List, Matrix) := Boolean => (V, Q) -> (
    isClosedUnderArrows(Q, V)
)
isClosedUnderArrows (List, ToricQuiver) := Boolean => (V, Q) -> (
    isClosedUnderArrows(Q.IncidenceMatrix, V)
)
isClosedUnderArrows (Matrix, ToricQuiver) := Boolean => (SQ, Q) -> (
    SQM := entries transpose SQ;
    V := positions(SQM, x -> all(x, y-> y != 0));
    isClosedUnderArrows(Q.IncidenceMatrix, V)
)
isClosedUnderArrows (ToricQuiver, ToricQuiver) := Boolean => (SQ, Q) -> (
    SQM := entries (SQ.IncidenceMatrix*diagonalMatrix(SQ.flow));
    V := positions(SQM, x -> any(x, y -> y != 0));
    isClosedUnderArrows(Q.IncidenceMatrix, V)
)
------------------------------------------------------------


------------------------------------------------------------
isSemistable = method()
isSemistable(List, ToricQuiver) := Boolean => (subQ, Q) -> (
    Qcm := Q.IncidenceMatrix;

    -- get the vertices in the subquiver
    subQVertices := positions(entries(Qcm_subQ), x -> any(x, y -> y != 0));

    -- weights of the original quiver
    Qweights := Q.weights;

    -- inherited weights on the subquiver
    weights := Qweights_subQVertices;

    -- negative weights in Q_0 \ subQ_0
    otherVertices := asList(set(0..#Qweights - 1) - set(subQVertices));
    minWeight := sum(apply({0} | asList(Qweights_otherVertices), x -> if(x <= 0) then x else 0));

    subMat := Qcm_subQ;
    tSubMat := transpose(subMat);
    subMat = transpose(tSubMat_subQVertices);

    sums := asList(
        for subset in subsetsClosedUnderArrows(subMat) list(
            sumList(weights_subset)
        )
    );
    all(sums, x -> x + minWeight >= 0)
)
isSemistable(ToricQuiver, ToricQuiver) := Boolean => (subQ, Q) -> (
    nonZeroEntries := positions(subQ.flow, x -> (x > 0) or (x < 0));
    isSemistable(nonZeroEntries, Q)
)
------------------------------------------------------------


------------------------------------------------------------
isStable = method()
isStable(List, ToricQuiver) := Boolean => (subQ, Q) -> (
    Qcm := Q.IncidenceMatrix;

    -- get the vertices in the subquiver
    subQVertices := positions(entries(Qcm_subQ), x -> any(x, y -> y != 0));

    -- weights of the original quiver
    Qweights := Q.weights;

    -- inherited weights on the subquiver
    weights := Qweights_subQVertices;

    -- negative weights in Q_0 \ subQ_0
    otherVertices := asList(set(0..#Qweights - 1) - set(subQVertices));
    minWeight := sum(apply({0} | asList(Qweights_otherVertices), x -> if(x <= 0) then x else 0));

    subMat := Qcm_subQ;
    tSubMat := transpose(subMat);
    subMat = transpose(tSubMat_subQVertices);

    sums := asList(
        for subset in subsetsClosedUnderArrows(subMat) list(
            sumList(weights_subset)
        )
    );
    all(sums, x -> x + minWeight > 0)
)
isStable(ToricQuiver, ToricQuiver) := Boolean => (subQ, Q) -> (
    nonZeroEntries := positions(subQ.flow, x -> (x > 0) or (x < 0));
    isStable(nonZeroEntries, Q)
)
------------------------------------------------------------


------------------------------------------------------------
isTight = method(Options => {Format => "Flow"})
isTight(ToricQuiver) := Boolean => opts -> Q -> (
    numArrows := #Q#Q1;
    maxUnstSubs := maximalUnstableSubquivers(Q, ReturnSingletons => true);
    if numArrows > 1 then (
        all(maxUnstSubs#NonSingletons, x -> #x != (numArrows - 1))
    ) else (
        #maxUnstSubs#Singletons < 1
    )
)
isTight(ToricQuiver, List) := Boolean => opts -> (Q, F) -> (
    if opts.Format == "Flow" then (
        isTight(toricQuiver(Q.IncidenceMatrix, F))
    ) else (
        FF := incInverse(F, Q);
        isTight(toricQuiver(Q.IncidenceMatrix, FF))
    )
)
isTight(List, ToricQuiver) := Boolean => opts -> (F, Q) -> (
    if opts.Format == "Flow" then (
        isTight(toricQuiver(Q.IncidenceMatrix, F))
    ) else (
        FF := incInverse(F, Q);
        isTight(toricQuiver(Q.IncidenceMatrix, FF))
    )
)
------------------------------------------------------------


------------------------------------------------------------
isWellDefined = method()
isWellDefined(ToricQuiver) := Boolean -> Q -> (
    -- check that the vertices are consecutive
    vertexRange := toList(0..#Q.Q0 - 1),
    if any(Q.Q0, x -> not isIn(x, vertexRange)) then (
        print("error: Toric Quiver is missing vertices");
        return false;
    );
    -- check that each edge is defined in terms of two vertices
    if any(Q.Q1, e -> (#e < 2) or (not (isIn(e#0, vertexRange) and isIn(e#1, vertexRange)))) then (
        print("error: edge is has invalid endpoint");
        return false;
    );
    -- check that the flow has the same dimension as the number of edges
    if #Q.flow != #Q.Q1 then (
        print("error: the flow of the Toric Quiver have incorrect dimension.");
        return false;
    );
    -- check that the weights have the same dimension as the number of vertices
    if #Q.weights != #Q.Q0 then (
        print("error: the weights of the Toric Quiver have incorrect dimension.");
        return false;
    );
    -- check that the weights match the flow and incidence matrix
    computedWeights := sumList(entries(Q.incidenceMatrix*diagonalMatrix(Q.flow)), Axis => "Row");
    if any(0..#Q.weights - 1, x -> computedWeights#x != Q.weights#x) then (
        print("error: Toric Quiver weights do not match its flow and incidence matrix");
        return false;
    );
    return true;
)
------------------------------------------------------------


------------------------------------------------------------
makeTight = (W, Q) -> (
    potentialF := incInverse(W, Q);
    k := entries generators kernel Q.IncidenceMatrix;
    potentialF = potentialF + flatten entries first asList(transpose(matrix({sumList(k, Axis => "Row")})));

    -- this function calls itself recursively until a tight quiver is produced
    if isTight(Q, potentialF) then (
        return toricQuiver(Q.IncidenceMatrix, potentialF);
    ) else (
        if (#stableTrees(W, Q) < 1) then (
            print("Error: provided weight W is not in C(Q) and so does not admit a tight toric quiver");
            return ;
        );

        -- find a maximal unstable subquiver, called R, of codimension 1 (this exists if not tight)
        Qcm := graphFromEdges(Q.Q1, Oriented => true)*diagonalMatrix(potentialF);
        maxUnstSubs := maximalUnstableSubquivers(toricQuiver(Q.IncidenceMatrix, potentialF), ReturnSingletons => true);
        R := first(maxUnstSubs#NonSingletons);
        Rvertices := asList set flatten Q.Q1_R;
        S := {};

        -- generate a connected subset of R0 that is closed under arrows and has weight sum <= 0
        if #R < 1 then (
            -- this is for the case of quivers with 1 arrow or similar
            Rvertices = first(maxUnstSubs#Singletons);
            S = Rvertices;
        ) else (
            success := false;
            for i from 1 to #Rvertices - 1 do (
                combs := combinations(#Rvertices - i, Rvertices, Replacement => false, Order => false);
                for c in combs do (
                    if sumList(W_c) <= 0 then (
                        if isClosedUnderArrows(c, Q_R) then (
                            success = true;
                            S = c;
                            break;
                        );
                    );
                    if success then break;
                );
                if success then break;
            );
        );

        -- alpha is an arrow in Q1 with head in R and tail in Q\R
        alpha := first toList (set(0..#Q.Q1-1) - set(R));
        a := sort(Q.Q1_alpha);
        {aMinus, aPlus} := (a_0, a_1);

        -- contract the arrow alpha to create a new quiver
        newRows := entries(Q.IncidenceMatrix);
        newCols := drop(asList(0..#Q.Q1 - 1), {alpha, alpha});
        newM := matrix(for e in Q.Q0 list(
            if e == aMinus then (
                nRs := sumList(Q.IncidenceMatrix^{aPlus, aMinus}, Axis => "Col");
                nRs_newCols
            ) else if e == aPlus then (
                continue;
            ) else (
                nR := newRows_e;
                nR_newCols
            )
        ));
        newFlow := drop(potentialF, {alpha, alpha});
        newQ := toricQuiver(newM);
        newW := getWeights(newQ.IncidenceMatrix*diagonalMatrix(newFlow));

	nonEmptyEdges := for i in 0..#newQ.Q1 - 1 list (
		e := newQ.Q1#i;
		if toString e#0 == "null" then (
			continue;
		) else (
			i
		)
	);
        return makeTight(newW, newQ_nonEmptyEdges);
    );
)
------------------------------------------------------------


------------------------------------------------------------
maxCodimensionUnstable = method()
maxCodimensionUnstable ToricQuiver := Number => (Q) -> (
    numArrows := #Q.Q1;
    maxUnstables := maximalUnstableSubquivers(Q, ReturnSingletons => true);
    if #(maxUnstables#Singletons) > 0 then (
        #Q.Q1
    ) else (
        maxUnstables = maxUnstables#NonSingletons;
        k := max(
            for sQ in maxUnstables list(
                numArrows - #sQ
            )
        );
        k
    )
)
------------------------------------------------------------


------------------------------------------------------------
maximalNonstableSubquivers = {Format => "list", ReturnSingletons => false} >> opts -> (Q) -> (
    NonstableList := nonStableSubquivers(Q, Format => "list");

    withArrows := for subQ1 in NonstableList.NonSingletons list (
        IsMaximal := true;
        for subQ2 in NonstableList#NonSingletons do (
            if isProperSubset(subQ1, subQ2) then (
                IsMaximal = false;
            );
        );
        if IsMaximal then (
            if (opts.Format == "list") then (
                subQ1) else (
                Q^subQ1
            )
        ) else (continue;)
    );
    if opts.ReturnSingletons then (
        containedSingletons := flatten for subQ1 in NonstableList#NonSingletons list (
            for x in Q.Q1_subQ1 list ({x})
        );
        withoutArrows := asList(set(NonstableList#Singletons) - set(containedSingletons));

        hashTable {NonSingletons => withArrows, Singletons => withoutArrows}
    ) else (
        hashTable {NonSingletons => withArrows}
    )
)
------------------------------------------------------------


------------------------------------------------------------
maximalUnstableSubquivers = {Format => "list", ReturnSingletons => false} >> opts -> (Q) -> (
    unstableList := unstableSubquivers(Q, Format => "list");

    withArrows := for subQ1 in unstableList.NonSingletons list (
        IsMaximal := true;
        for subQ2 in unstableList#NonSingletons do (
            if isProperSubset(subQ1, subQ2) then (
                IsMaximal = false;
            );
        );
        if IsMaximal then (
            if (opts.Format == "list") then (
                subQ1) else (
                Q^subQ1
            )
        ) else (continue;)
    );
    if opts.ReturnSingletons then (
        containedSingletons := flatten for subQ1 in unstableList#NonSingletons list (
            for x in Q.Q1_subQ1 list ({x})
        );
        withoutArrows := asList(set(unstableList#Singletons) - set(containedSingletons));
    
        hashTable {NonSingletons => withArrows, Singletons => withoutArrows}
    ) else (
        hashTable {NonSingletons => withArrows}
    )
)
------------------------------------------------------------


------------------------------------------------------------
mergeOnArrow = method()
mergeOnArrow(Matrix, ZZ, Matrix, ZZ) := ToricQuiver => (Q1, a1, Q2, a2) -> (
    if (a1 >= numColumns(Q1)) then {
      error "invalid arrow value provided";
    };
    if (a2 >= numColumns(Q2)) then {
      error "invalid arrow value provided";
    };
    Q1nr := numRows(Q1);
    Q2nr := numRows(Q2);
    Q1nc := numColumns(Q1);
    Q2nc := numColumns(Q2);
    nrow := Q1nr + Q2nr - 2;
    ncol := Q1nc + Q2nc - 1;

    q1E := asList(graphEdges(Q1, Oriented => true))_a1;
    q2E := asList(graphEdges(Q2, Oriented => true))_a2;

    c1 := asList(join(drop(0..Q1nc - 1, {a1, a1}), {a1}));
    c2 := asList(drop(0..Q2nc - 1, {a2, a2}));

    r1 := asList(join(asList(set(0..Q1nr - 1) - set(q1E)), q1E));
    r2 := asList(join(q2E, asList(set(0..Q2nr - 1) - set(q2E))));

    Q1 = entries(Q1^r1)_c1;
    Q2 = entries(Q2^r2)_c2;

    paddingSize := 0;
    toricQuiver matrix(
        for row from 0 to nrow - 1 list(
            if row < (Q1nr - 2) then (
                paddingSize = Q2nc - 1;
                join(Q1_row, asList(paddingSize:0))

            ) else if row < Q1nr then (
                join(Q1_row, Q2_(2 + row - Q1nr))
            ) else (
                j := (row - Q1nr) + 2;
                paddingSize = Q1nc;
                asList(join(paddingSize:0, Q2_j))
            )
        )
    )
)
mergeOnArrow(ToricQuiver, ZZ, Matrix, ZZ) := ToricQuiver => (Q1, a1, Q2, a2) -> (
    mergeOnArrow(Q1.IncidenceMatrix, a1, Q2, a2)
)
mergeOnArrow(Matrix, ZZ, ToricQuiver, ZZ) := ToricQuiver => (Q1, a1, Q2, a2) -> (
    mergeOnArrow(Q1, a1, Q2.IncidenceMatrix, a2)
)
mergeOnArrow(ToricQuiver, ZZ, ToricQuiver, ZZ) := ToricQuiver => (Q1, a1, Q2, a2) -> (
    mergeOnArrow(Q1.IncidenceMatrix, a1, Q2.IncidenceMatrix, a2)
)
------------------------------------------------------------


------------------------------------------------------------
mergeOnVertex = method()
mergeOnVertex(Matrix, ZZ, Matrix, ZZ) := ToricQuiver => (Q1, v1, Q2, v2) -> (
    if (v1 >= numRows(Q1)) then {
      error "invalid vertex value provided";
    };
    if (v2 >= numRows(Q2)) then {
      error "invalid vertex value provided";
    };
    nrow := numRows(Q1) + numRows(Q2) - 1;
    ncol := numColumns(Q1) + numColumns(Q2);
    Q1rs := numRows(Q1);
    Q1cs := numColumns(Q1);
    Q2cs := numColumns(Q2);

    i1 := asList(join(drop(0..numRows(Q1) - 1, {v1, v1}), {v1}));
    i2 := asList(join({v2}, drop(0..numRows(Q2) - 1, {v2, v2})));

    Q1 = entries(Q1^i1);
    Q2 = entries(Q2^i2);

    paddingSize := ncol - Q1cs;
    r := 0;
    toricQuiver matrix(
        for row in (0..nrow - 1) list(
            if row < (Q1rs - 1) then (
                Q1_row | asList(paddingSize:0)
            ) else if (row < Q1rs) then (
                Q1_row | Q2_0
            ) else (
                r = row - (Q1rs - 1);
                paddingSize = ncol - Q2cs;
                asList(paddingSize:0) | Q2_r 
            )
        )
    )
)
mergeOnVertex(ToricQuiver, ZZ, Matrix, ZZ) := ToricQuiver => (Q1, v1, Q2, v2) -> (
    mergeOnVertex(Q1.IncidenceMatrix, v1, Q2, v2)
)
mergeOnVertex(Matrix, ZZ, ToricQuiver, ZZ) := ToricQuiver => (Q1, v1, Q2, v2) -> (
    mergeOnVertex(Q1, v1, Q2.IncidenceMatrix, v2)
)
mergeOnVertex(ToricQuiver, ZZ, ToricQuiver, ZZ) := ToricQuiver => (Q1, v1, Q2, v2) -> (
    mergeOnVertex(Q1.IncidenceMatrix, v1, Q2.IncidenceMatrix, v2)
)
------------------------------------------------------------


------------------------------------------------------------
potentialWalls = method()
potentialWalls(Matrix) := Wall => (Q) -> (
    nv := numRows(Q);
    nvSet := set(0..nv - 1);
    subs := (1..ceiling(nv/2));

    -- create list of possible Qminus
    Qms := flatten(for i from 1 to floor(nv/2) list (
        combinations(i, asList(nvSet), Replacement => false, Order => false)
    ));

    alreadyMet := set ();
    Qedges := graphEdges(Q, Oriented => true);

    for Qm in Qms list(
        if member(Qm, alreadyMet) then ( 
            continue;
        ) else (
            -- restrict to only vertices/edgesin Qm
            mSums := sumList(Q^Qm, Axis => "Col");
            connectsToQm := positions(entries transpose Q^Qm, x->any(#x, y->x#y!=0));
            -- find the edges that have head and tail in Qm
            QmEdgeIndices := for s in connectsToQm list(if (mSums_s == 0) then (s) else (continue;));
            Qp := asList(nvSet - set(Qm));
            alreadyMet = alreadyMet + set ({Qp}) + set ({Qm});

            if isGraphConnected(Q^Qm_QmEdgeIndices) then (
                pSums := sumList(Q^Qp, Axis => "Col");
                connectsToQp := positions(entries transpose Q^Qp, x->any(#x, y->x#y!=0));

                QpEdgeIndices := for s in connectsToQp list(if (pSums_s == 0) then (s) else (continue;));
                if (#Qp < 2) or (isGraphConnected(Q^Qp_QpEdgeIndices)) then (
                   new Wall from hashTable ({Qplus => Qp, WallType => wallType(Qp, Q)})
                ) else (continue;)
            ) else (continue;)
        )
    )
)
potentialWalls(ToricQuiver) := Wall => (Q) -> (
    potentialWalls(Q.IncidenceMatrix*diagonalMatrix(Q.flow))
)
------------------------------------------------------------


------------------------------------------------------------
primitiveArrows = Q -> (
    Es := Q.Q1;
    PAs := for i from 0 to #Es - 1 list(
        a := Es#i;
        (isCycle, cycle) := isPathBetween(a#0, a#1, drop(Es, {i, i}), Oriented => true, SavePath => true);
        if isCycle and (#set(cycle) > 1) then (
            continue;
        ) else (
            i
        )
    );
    return PAs
)
------------------------------------------------------------


------------------------------------------------------------
quiverIncidenceMatrix = method()
quiverIncidenceMatrix(ToricQuiver) := Matrix => Q -> (
    return Q.IncidenceMatrix
)
------------------------------------------------------------


------------------------------------------------------------
quiverEdges = method()
quiverEdges(ToricQuiver) := List => Q -> (
    return Q.Q1
)
------------------------------------------------------------


------------------------------------------------------------
quiverFlow = method()
quiverFlow(ToricQuiver) := List => Q -> (
    return Q.flow
)
------------------------------------------------------------


------------------------------------------------------------
quiverVertices = method()
quiverVertices(ToricQuiver) := List => Q -> (
    return Q.Q0
)
------------------------------------------------------------


------------------------------------------------------------
quiverWeights = method()
quiverWeights(ToricQuiver) := List => Q -> (
    return Q.weights
)
------------------------------------------------------------


------------------------------------------------------------
-- this routine routines an interior point for each 
-- chamber of the coneSystem QCS associated to a toric quiver Q
referenceThetas = method()
referenceThetas(List) := List => QCS -> (
    for c in QCS list(flatten entries interiorVector c)
)
------------------------------------------------------------


------------------------------------------------------------
-- this function checks if the weights theta1 and theta2 
-- belong to the same polytope in the wall chamber decomposition for Q
samePolytope = method()
samePolytope(List, List, ToricQuiver) := Boolean => (theta1, theta2, Q) -> (
    treesTheta1 := stableTrees(theta1, Q);
    treesTheta2 := stableTrees(theta2, Q);
    if (#treesTheta1 < 1) then (
        if (#treesTheta2 < 1) then (
            return true
        ) else (
            return false
        );
    ) else if (#treesTheta2 < 1) then (
         return false
    ) else if all(0..#treesTheta1 - 1, x -> treesTheta1#x == treesTheta2#x) then (
        return true
    ) else (
        p1 := flowPolytopeVertices(theta1, Q);
        p2 := flowPolytopeVertices(theta2, Q);
        if areIsomorphic(convexHull transpose matrix p1, convexHull transpose matrix p2) then (
            return true
        ) else (
            error "cannot be determined";
        )
    )
)
------------------------------------------------------------


------------------------------------------------------------
-- this function lists all of the spanning trees T of TQ
-- such that T admits a regular flow in the preimage of weight th
stableTrees = (th, TQ) -> (
    allTrees := allSpanningTrees(TQ);
    for x in allTrees list(if all(incInverse(th, TQ_x), y -> y > 0) then sort(x) else continue )
)
------------------------------------------------------------


------------------------------------------------------------
-- yield the subquivers of a given quiver Q
subquivers = method(Options => {Format => "quiver", AsSubquiver => false})
subquivers Matrix := opts -> Q -> (
    numArrows := numColumns(Q);
    arrows := 0..(numArrows - 1);
    QFlow := 0.5*sumList(for x in entries(Q) list(for y in x list(abs(y))), Axis => "Col");

    flatten(
        for i from 1 to numArrows - 1 list (
            for c in combinations(i, arrows, Order => false, Replacement => false) list (
                if opts.Format == "list" then (
                    c
                ) else (
                    if opts.AsSubquiver then (
                        toricQuiver(Q, QFlow)^c
                    ) else (
                        toricQuiver(Q)_c
                    )
                )
            )
        )
    )
)
subquivers ToricQuiver := opts -> Q -> (
    numArrows := #Q.Q1;
    arrows := 0..(numArrows - 1);

    flatten(
        for i from 1 to numArrows - 1 list (
            for c in combinations(i, arrows, Order => false, Replacement => false) list (
                if opts.Format == "list" then (
                    c
                ) else (
                    if opts.AsSubquiver then (
                        Q^c
                    ) else (
                        Q_c
                    )
                )
            )
        )
    )
)
------------------------------------------------------------


------------------------------------------------------------
-- return ordered list of the weights for the vertices of quiver Q
getWeights = method()
getWeights(ToricQuiver) := List => Q -> (
    Q.weights
)
getWeights(Matrix) := List => Q -> (
    sumList(entries(Q), Axis => "Row")
)
------------------------------------------------------------


------------------------------------------------------------
threeVertexQuiver = method(Options => {Flow => "Canonical"})
threeVertexQuiver(List) := ToricQuiver => opts -> (numEdges) -> (
    if #numEdges != 3 then (
        print("error: need a list of 3 numbers, denoting the number of edges between each pair of vertices");
        return;
    );
    Es0 := for i from 0 to numEdges#0 - 1 list({0, 1});
    Es1 := for i from 0 to numEdges#1 - 1 list({1, 2});
    Es2 := for i from 0 to numEdges#2 - 1 list({0, 2});
    Es := Es0 | Es2 | Es1;

    if instance(opts.Flow, List) then (
        if #opts.Flow != sum(numEdges) then (
            print("error: provided flow is not correct length.");
            return;
        );
        return toricQuiver(Es, opts.Flow)
    ) else (
        return toricQuiver(Es, Flow => opts.Flow)
    )
)
------------------------------------------------------------


------------------------------------------------------------
wallType = method()
wallType(List, Matrix) := Sequence => (Qp, Q) -> (
    tp := sum(for x in sumList(Q^Qp, Axis => "Col") list(if x < 0 then (1) else (continue;)));
    tm := sum(for x in sumList(Q^Qp, Axis => "Col") list(if x > 0 then (1) else (continue;)));
    (tp, tm)
)
wallType(List, ToricQuiver) := Sequence => (Qp, Q) -> (
    wallType(Qp, Q.IncidenceMatrix*diagonalMatrix(Q.flow))
)
------------------------------------------------------------




------------------------------------------------------------
-- NON-EXPORTED AUXILIARY FUNCTIONS
------------------------------------------------------------


------------------------------------------------------------
adjacencyToIncidence = (A) -> (
    E := for i in (0..numRows(A) - 1) list(for j in (0..numColumns(A) - 1) list(if A_{j}^{i} != 0 then (i, j)));
    matrix(graphFromEdges(E), Oriented => true)

)

-- cast object x as a list
asList = x -> (
    if instance(x, List) then(
        return x
    )
    else if instance(x, Sequence) then(
        return toList(x)
    )
    else if instance(x, Set) then(
        return toList(x)
    )
    else
        return {x}
)

-- take all possible combinations of length k from list l -- 
-- optional arguments: 
-- -- Replacement(true/false) = with replacement
-- -- Order(true/false) = whether or not the ordering of combination values matters
combinations = {Replacement => true, Order => true} >> opts -> (k, l) -> (
    combs := {};
    combs1 := {};
    combs2 := {};
    if k > 1 then (
        -- if we are using combinations with replacement -- 
        if opts.Replacement then (
           combs = flatten(join(for i in l list(for j from 0 to k - 1 list(i))));
           combs1 = unique(subsets(combs, k));
           combs2 = unique(subsets(combs, k));
           for i in combs2 do (combs1 = append(combs1, reverse(i)));
        )
        else (
           combs = flatten(for i in l list(i));
           combs1 = unique(subsets(combs, k));
           combs2 = unique(subsets(combs, k));
           for i in combs2 do (combs1 = append(combs1, reverse(i)));
        );
    )
    else combs1 = for i in l list(asList(i));

    if opts.Order != true then (
        combs = unique(
            for i in combs1 list(sort(i))
        );
    ) else (
        combs = unique(flatten for c in combs1 list permutations(c));
    );
    combs
)

-- yield the edges (from a list of edges of the form {{v0,v1},..{vi, vj}}) that adjoin point p
edgesOutOfPoint = {Oriented => false} >> opts -> (p, E) -> (
    if opts.Oriented then (
        for i from 0 to #E - 1 list(e := E#i; if p != e#0 then (continue;) else (i, e))
    )
    else (
        for i from 0 to #E - 1 list(e := E#i; if (#positions(e, j -> j == p) < 1) then (continue;) else (i, e))
    )
)

-- check if there exists a cycle in a (possibly unconnected)
-- oriented graph, passed in matrix form. 
existsOrientedCycle = (G) -> (
    retVal := false;
    E := graphEdges(G, Oriented => true);
    V := asList(0..numRows(G)-1);
    for firstV in V do (
        visited := replaceInList(firstV, 1, asList(#V:0));
        result := findCycleDFS(firstV, visited, E);
        if result then (
            retVal = true;
            break;
        )
    );
    retVal
)

existsUnorientedCycle = (G) -> (
    retVal := false;
    E := graphEdges(G, Oriented => false);
    for i from 0 to #E - 1 do (
        if isEdgeInCycle(i, E) then (
            retVal = true;
            break;
        );
    );
    retVal
)

-- DFS search to find cycle in directed graph:
findCycleDFS = (startV, visited, E) -> (
    retVal := false;
    edgesOut := edgesOutOfPoint(startV, E, Oriented => true);
    for edge in edgesOut do (
        currentVisited := asList(visited);
        edgeVerts := edge#1;
        endV := edgeVerts#1;
        if visited#endV == 1 then (
            retVal = true;
            break;
        );
        if retVal then break;
        currentVisited = replaceInList(endV, 1, visited);
        retVal = findCycleDFS(endV, currentVisited, E);
    );
    retVal
)

-- yield the edges of a graph in the form of a list of pairs 
-- (v1, v2), where edge E is from v1 to v2
graphEdges = method(Options => {Oriented => false, RavelLoops => false});
graphEdges Matrix := List => opts -> (G) -> (
    E := {};
    if opts.Oriented == true then (
        E = for e in entries(transpose(G)) list(
            {position(e, i -> i < 0), 
             position(e, i -> i > 0)}
        );
    )
    else (
        E = for e in entries(transpose(G)) list(
            positions(e, i -> (i > 0 or i < 0))
        );
        if opts.RavelLoops == true then (
            E = for e in E list(if #e > 1 then e else toList(2:e#0));
        );
    );
    return E
)
graphEdges ToricQuiver := List => opts -> (G) -> (
    graphEdges(G.IncidenceMatrix, Oriented => opts.Oriented, RavelLoops => opts.RavelLoops)
)

graphVertices = method();
graphVertices Matrix := List => M -> (
    asList(0..numRows(M) - 1)
)
graphVertices ToricQuiver := List => Q -> (
    Q.Q0
)

-- yield the matrix rep of graph, given a list of edges as ordered 
-- pairs (this is the opposite of graphEdges() function. 
graphFromEdges = {Oriented => false} >> opts -> E -> (
    -- first, if oriented graph, then make sure this is reflected. 
    tailVal := 1;
    if opts.Oriented == true then (
        tailVal = -1;
    );

    nVerts := max(flatten(E))+1;
    cols := for i in E list(
        row := (nVerts:0);
        asList(replaceInList(i#0, tailVal, replaceInList(i#1, 1, row)))
    );
    transpose(matrix(cols))
)

-- checks if there is a cycle containing given edge. 
isEdgeInCycle = (i, E) -> (
    if #E > 1 then (
        e := E#i;
        if #e > 1 then (
            p := e#0;
            q := e#1;
        )
        else (
            p = e#0;
            q = e#0;
        );
        indicesToSave := drop(toList(0..(#E-1)), {i,i});
        isPathBetween(p, q, E_indicesToSave)
    )
    else (
        false
    )
)

-- check if graph is connected
isGraphConnected = G -> (
    gEdges := graphEdges(G, Oriented => false);
    gPoints := graphVertices(G);

    if (#gPoints < 2) then (
        true
    ) else (
        -- reorder the edges to list loops first
        lens := sortedIndices(for e in gEdges list(-#e));
        gEdges = gEdges_lens;

        -- check if there is a non-loop edge first
        if max(for e in gEdges list(#e)) > 1 then (
            isConnected(graph(gEdges))
        -- if there are only loops/empty edges
        ) else (
            false
        )
    )
)

isIn = (v, l) -> (
    p := positions(l, x -> x == v);
    #p > 0
)

isMaximal = method()
isMaximal(List, Matrix) := Boolean => (Qlist, Q) -> (
    returnVal := true;
    for Q2 in Qlist do (
        if isProperSubset(Q, Q2) then (
            returnVal = false;
        );
    );
    returnVal
)
isMaximal(List, ToricQuiver) := Boolean => (Qlist, Q) -> (
    Ms := for Qm in Qlist list(Qm.IncidenceMatrix);
    isMaximal(Ms, Q.IncidenceMatrix)
)

-- check if there exists a path between p and q by appending 
-- edges in E(which is a list of pairs (v1, v2). 
-- optional arguments: 
-- -- Oriented(true/false) = whether or not the graph should be oriented
-- -- SavePath(true/false) = whether or not to return the edges involved in the path
-- -- EdgesAdded(list) = internal mechanism for computing for SavePath
isPathBetween = {Oriented => false, SavePath => false, EdgesAdded => {}} >> opts -> (p, q, E) -> (
    ifPath := false;
    existsPath := false;
    currentEdges := {};
    pathsToSee := edgesOutOfPoint(p, E, Oriented => opts.Oriented);

    for edge in pathsToSee do (
        --- get the edge index and endpoints
        i := edge#0;
        e := edge#1;
        v := e#1;
        if p == e#1 then (
            v = e#0;
        );
        if opts.SavePath then (
            currentEdges = append(toList(opts.EdgesAdded), {p, v});
        );

        if q == v then (
            existsPath = true;
            break;
        )
        else (
            thisPath := {};
            remainingEdges := for j from 0 to #E - 1 list(if j == i then (continue;) else E#j);

            if opts.SavePath then (
                (ifPath, thisPath) = isPathBetween(v, q, remainingEdges, Oriented => opts.Oriented, SavePath => true, EdgesAdded => currentEdges);
            )
            else (
                ifPath = isPathBetween(v, q, remainingEdges, Oriented => opts.Oriented, EdgesAdded => currentEdges);
            );
            if ifPath then (
                existsPath = true;
                currentEdges = currentEdges | thisPath;
                break;
            );
        );
    );
    if opts.SavePath then (
        return (existsPath, currentEdges);
    )
    else (
        return existsPath;
    )
)

isProperSubset = (Q1, Q2) -> (
    if set(Q1) === set(Q2) then (
        false
    ) else (
        isSubset(set(Q1), set(Q2))
    )
)

-- gives the edges that comprise an undirected cycle in the graph G, 
-- (which is assumed to contain a single cycle) and returns the ordered cycle
--  input: G(list of tuples): edges of graph G
--  output: cycle(list of tuples): tuple representation of the edges contained in the cycle
primalUndirectedCycle = (G) -> (
    if existsUnorientedCycle(graphFromEdges(G)) then (
        for i from 0 to #G - 1 do (
            edge := G#i;
            (isCycle, cycle) := isPathBetween(edge#1, edge#0, drop(G, {i, i}), 
                                              Oriented => false, SavePath => true, EdgesAdded => {edge});
            if isCycle then (
                edgeIndices := {};
                metEdges := {};

                for cE in cycle do (
                    for gI in asList(0..#G - 1) do (
                        if isIn(gI, metEdges) then (
                            continue;
                        ) else (
                            gE := G#gI;
                            if (gE#0 == cE#0) and (gE#1 == cE#1) then (
                                metEdges = metEdges | {gI};
                                edgeIndices = edgeIndices | {gI};
                                break;
                            ) else if (gE#1 == cE#0) and (gE#0 == cE#1) then (
                                metEdges = metEdges | {gI};
                                edgeIndices = edgeIndices | {-(gI+1)};
                                break;
                            );
                        );
                    );
                );
                return edgeIndices;
            );
        );
        return {};
    ) else (
        return G;
    );
)

replaceInList = (i, v, l) -> (
    insert(i, v, drop(l, {i,i}))
)
nonStableSubquivers = method(Options => {Format => "list"})
nonStableSubquivers(ToricQuiver) := opts -> Q -> (
    numArrows := #Q.Q1;
    arrows := asList(0..numArrows - 1);

    L := flatten(for i from 1 to numArrows - 1 list (
        combinations(numArrows - i, arrows, Replacement => false, Order => false) 
    ));

    sqsWithArrows := for sQ in L list(
        if not isStable(asList(sQ), Q) then (
            if (opts.Format == "list") then (
                sQ
            ) else (
                Q^sQ
            )
        ) else (continue;)
    );
    singletonUnstableSqs := for x in positions(Q.weights, x -> x <= 0) list ({x});

    hashTable({NonSingletons => sqsWithArrows, Singletons => singletonUnstableSqs})
)


-- return the indices of the list l in order the values occur 
-- in the sorted list sort(l)
sortedIndices = (l) -> (
    sortedVals := unique(sort(l));
    flatten(for i in sortedVals list(positions(l, x -> x == i)))
)

-- Returns a spanning tree(the first one that is encountered) of 
-- the quiver Q with |Q_1| - |Q_0| + 1 edges removed. 
-- NOTE: if such a spanning tree is not possible, then it returns empty lists
--
-- input: 
--     - Q: Matrix representation of quiver
-- outputs:
--     - edges_kept(list of tuples): list of the edges in the spanning tree
--     - edges_removed(list of tuples)): list of the edges in the complement of the spanning tree
--
spanningTree = (Q) -> (
    Q0 := numRows(Q);
    Q1 := numColumns(Q);

    --  edges of quiver Q represented as a list of tuples
    allEdges := graphEdges(Q, Oriented => true);
    allNodes := asList(0..Q0-1);

    -- number of edges to remove from spanning tree
    d := Q1 - Q0 + 1;

    edgeIndices := {};
    if d > 0 then (
        dTuplesToRemove := combinations(d, asList(0..#allEdges-1), Replacement => false, Order => false);
        edgesKept := {};
        edgesRemoved := {};
        foundTree := false;

        for dTuple in dTuplesToRemove do (
            edgeIndices = asList(set(0..#allEdges - 1) - set(dTuple));
            edgesKept = allEdges_edgeIndices;
            edgesRemoved = allEdges_dTuple;

            reducedG := transpose(matrix(for e in edgesKept list(
                t := e#0;
                h := e#1;
                localE := asList(Q0:0);
                localE = replaceInList(h,  1, localE);
                localE = replaceInList(t, -1, localE);
                localE
            )));
            if numColumns(reducedG) > 1 then (
                notAnyCycles := not existsUnorientedCycle(reducedG);

                if isGraphConnected(reducedG) and notAnyCycles then (
                    foundTree = true;
                    break;
                );
            ) else (
                foundTree = true;
                break;
            );
        );
        if foundTree then (
            dTuple := asList(set(0..#allEdges - 1) - set(edgeIndices));
            return (edgeIndices, dTuple);
        ) else (
            return ({}, {});
        );
    ) else (
        return (allEdges, {});
    );
)

-- list the subsets of a quiver Q that are closed under arrows
subsetsClosedUnderArrows = method()
subsetsClosedUnderArrows Matrix := List => (Q) -> (
    currentVertices := 0..(numRows(Q) - 1);

    flatten(for i from 1 to #currentVertices - 1 list(
        for c in combinations(i, currentVertices, Order => false, Replacement => false) list(
            if isClosedUnderArrows(c, Q) then (
                c
            )
            else(continue;)
        )
    ))
)
subsetsClosedUnderArrows ToricQuiver := List => (Q) -> (
    subsetsClosedUnderArrows(Q.IncidenceMatrix)
)

-- add all elements of a list x together, and specify Axis (row/col) if x is actually a matrix or list of lists -- 
sumList = {Axis => "None"} >> opts -> x -> (
    s := 0;
    if opts.Axis == "Row" then (
        s = flatten(for i in x list(sumList(i)));
    )
    else if opts.Axis == "Col" then (
       pivoted := entries(transpose(matrix(x)));
       s = flatten(for i in pivoted list(sumList(i)));
    )
    else (
        s = sum(asList(x));
    );
    return s
)

unstableSubquivers = method(Options => {Format => "list"})
unstableSubquivers(ToricQuiver) := opts -> Q -> (
    numArrows := #Q.Q1;
    arrows := asList(0..numArrows - 1);

    L := flatten(for i from 1 to numArrows - 1 list (
        combinations(numArrows - i, arrows, Replacement => false, Order => false) 
    ));

    sqsWithArrows := for sQ in L list(
        if not isSemistable(asList(sQ), Q) then (
            if (opts.Format == "list") then (
                sQ
            ) else (
                Q^sQ
            )
        ) else (continue;)
    );
    singletonUnstableSqs := for x in positions(Q.weights, x -> x < 0) list ({x});

    hashTable({NonSingletons => sqsWithArrows, Singletons => singletonUnstableSqs})
)


------------------------------------------------------------
beginDocumentation()
multidoc ///
    Node
        Key 
            ThinSincereQuivers
        Headline
            creating and manipulating Toric Quivers
        Description
            Text
                {\em ThinSincereQuivers} is a package for creating and manipulating toric quivers.
            Text   
                For further details in the theory, we suggest the following articles and the references within them:
            Text
                @UL { 
                      {"Lutz Hille, ", HREF{"https://doi.org/10.1016/S0024-3795(02)00406-8", EM "Quivers, cones and polytopes, "}, "
                       Linear algebra and its applications 365 (2003): 215-237."},
                      {"Mátyás Domokos and  Dániel Joó, ", HREF{"https://arxiv.org/abs/1402.5096v1", 
                            EM "On the equations and classification of toric quiver varieties"},",  
                          Proceedings. Section A, Mathematics-The Royal Society of Edinburgh 146.2 (2016): 265."
                    }
                }@
            Text
                @SUBSECTION "Menu"@
            Text
                @UL {
                    {TO "Creating toric quivers"},
                    {TO "Creating subquiver representations"},
                }@
        Subnodes
            ToricQuiver
            "Creating toric quivers"
            "Creating subquiver representations"
            toricQuiver
            (symbol _, ToricQuiver, List)
            (symbol ^, ToricQuiver, List)
            (symbol ==, ToricQuiver, ToricQuiver)
            bipartiteQuiver
            chainQuiver
            threeVertexQuiver
            allSpanningTrees
            basisForFlowPolytope
            coneSystem
            flowPolytopeVertices
            incInverse
            isAcyclic
            isClosedUnderArrows
            isSemistable
            isStable
            isTight
            isWellDefined
            makeTight
            maxCodimensionUnstable
            maximalNonstableSubquivers
            maximalUnstableSubquivers
            mergeOnArrow
            mergeOnVertex
            potentialWalls
            primitiveArrows
            quiverIncidenceMatrix
            quiverEdges
            quiverFlow
            quiverVertices
            quiverWeights
            referenceThetas
            samePolytope
            stableTrees
            subquivers
            wallType
            getWeights
            AsSubquiver
            Flow
            ReturnSingletons
    Node
        Key
            ToricQuiver
        Headline
            the ToricQuiver datatype
        Description
            Text
                The ToricQuiver data type is a type of Hash Table with the following keys: 
            Text
                @UL {
                    {TT "IncidenceMatrix:", "matrix representation of the connected graph underlying the quiver"},
                    {TT "flow:              ", "list of integers representing the flow associated to each edge of the quiver"},
                    {TT "Q0:                ", "the list of vertices"},
                    {TT "Q1:                ", "the list of edges "},
                    {TT "weights:           ", "the values on each vertex induced by the flow"},
                }@
        SeeAlso
            "toricQuiver"
            "bipartiteQuiver"
            "threeVertexQuiver"
            "chainQuiver"

    Node
        Key
            toricQuiver
            (toricQuiver, List)
            (toricQuiver, List, List)
            (toricQuiver, Matrix)
            (toricQuiver, Matrix, List)
            (toricQuiver, Graph)
            (toricQuiver, Graph, List)
            (toricQuiver, ToricQuiver)
            (toricQuiver, ToricQuiver, List)
            [toricQuiver, Flow]
        Headline
            the toricQuiver constructor
        Usage
            Q = toricQuiver E
            Q = toricQuiver (E, F)
            Q = toricQuiver M
            Q = toricQuiver (M, F)
            Q = toricQuiver G
            Q = toricQuiver (G, F)
            Q = toricQuiver T
            Q = toricQuiver (T, F)
        Inputs
            E: List
                of pairs {\tt (V1, V2)} giving the edges of the quiver in terms of the vertices
            F: List 
                the flow on the quiver given as a list of integers
            G: Graph
            M: Matrix 
                of integers giving the connectivity structure of the quiver
            T: ToricQuiver 
            Flow => String
                that specifies the flow for the polytope. 
                options are 
                {\tt Default}, which takes the flow from values in the matrix, 
                {\tt Canonical}, which sets the flow to 1 for each edge, and 
                {\tt Random}, which assigns a random integer between 0 and 100 to each edge
        Outputs
            Q: ToricQuiver
        Description
            Text
                A toric quiver is a directed graph {\tt Q=(Q_0, Q_1) } where 
                {\tt Q_0} is the set of vertices associated to {\tt Q} and {\tt Q_1} is the set of arrows. 
                Also included in $Q$ is a flow, which associates an integer value to each edge. 
                The canonical flow gives a weight of 1 to each edge. 
            Text
                the ToricQuiver data type is stored as a hash table with the following keys: 
            Text
                @UL {
                    {TT "IncidenceMatrix:", "matrix representation of the connected graph underlying the quiver"},
                    {TT "flow:              ", "list of integers representing the flow associated to each edge of the quiver"},
                    {TT "Q0:                ", "the list of vertices"},
                    {TT "Q1:                ", "the list of edges "},
                    {TT "weights:           ", "the values on each vertex induced by the flow"},
                }@

            Example
                -- create a toric quiver from matrix
                Q = toricQuiver matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}})
                -- create a toric quiver from matrix with specified flow
                Q = toricQuiver(matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), {3, 1, 0, 5})
                -- create a toric quiver from a list of edges
                Q = toricQuiver {{0,1},{0,1},{0,2},{0,2}}
                -- create a toric quiver from a list of edges and a flow
                Q = toricQuiver ({{0,1},{0,1},{0,2},{0,2}}, {1,2,3,4})
                -- create a toric quiver from a matrix with keyword flow
                Q = toricQuiver(matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), Flow => "Canonical")
                -- create a toric quiver from a matrix with random flow
                Q = toricQuiver(matrix({{-1,-1,-1,-1},{0,0,1,1},{1,1,0,0}}), Flow => "Random")
                -- create a toric quiver copied from another one
                R = toricQuiver(Q)
                -- create a toric quiver copied from another, but with alternative flow
                R = toricQuiver(Q, {1,2,3,4})
        SeeAlso
            "bipartiteQuiver"
    Node
        Key
            "Creating toric quivers"
        Description
            Text
                toric quivers are represented as a type of HashTable with the following keys:
            Text
                @UL{  
                    {TT "IncidenceMatrix: ","weighted incidence matrix giving the vertex-edge connectivity structure of $Q$"},
                    {TT "Q0: ","list of vertices"},
                    {TT "Q1: ","list of edges"},
                    {TT "flow: ","list of integers giving the flow on each edge"},
                    {TT "weights: ","induced weights on vertices given by the image of the flow"},
                }@

            Text
                One can generate the quiver {\tt Q} associated to the bipartite graph 
                {\tt K_{2,3}} with a random flow {\tt w} as follows:

            Example
                Q0 = {{0,2},{0,3},{0,4},{1,2},{1,3},{1,4}}
                Q = toricQuiver(Q0, Flow => "Random")
            Text
                Alternatively, one can construct a toric quiver using any of the following constructions:
            Text
                create a toric quiver from matrix
            Example
                Q = toricQuiver matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}})
            Text
                create a toric quiver from matrix with specified flow
            Example
                Q = toricQuiver(matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), {3, 1, 0, 5})
            Text
                create a toric quiver from a list of edges
            Example
                Q = toricQuiver {{0,1},{0,1},{0,2},{0,2}}
            Text
                create a toric quiver from a list of edges and a flow
            Example
                Q = toricQuiver ({{0,1},{0,1},{0,2},{0,2}}, {1,2,3,4})
            Text
                create a toric quiver from a matrix with keyword flow
            Example
                Q = toricQuiver(matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), Flow => "Canonical")
            Text
                create a toric quiver from a matrix with random flow
            Example
                Q = toricQuiver(matrix({{-1,-1,-1,-1},{0,0,1,1},{1,1,0,0}}), Flow => "Random")
            Text
                create a toric quiver copied from another one
            Example
                R = toricQuiver(Q)
            Text
                create a toric quiver copied from another, but with alternative flow
            Example
                R = toricQuiver(Q, {1,2,3,4})
    Node
        Key
            "Creating subquiver representations"
        Description
            Text
                A subquiver is a subgraph of a quiver. Specifically, it is formed by selecting a subset $I$
                of the arrows from the original quiver, ensuring that the tails and heads of the chosen arrows 
                align with the selected vertices. In this context, there are two ways to approach a subquiver. 
                One approach is to recall the original quiver and represent the subquiver as a subset of its arrows 
                and vertices, denoted as $Q^I$. The flow of the resultant quiver will be zero along the arrows not in $I$. 
                Alternatively, we can disregard the original quiver and focus solely on the arrows and vertices of the new subquiver, represented as $Q_I$. 
                The weight of the new quiver $Q_I$ is derived from the flows of the original quiver $Q$.  
            Text
                The two methods corresponding to these ideas are referenced in the examples below. 
            Example
                Q = bipartiteQuiver(2, 3)
                -- show the subquiver consisting of arross 0, 1 and 3, by removing all of the others
                Q_{0,1,3}
                -- show the subquiver consisting of arross 0, 1 and 3, by setting flow to 0 on all other arrows 
                Q^{0,1,3}
        SeeAlso
            (symbol ^, ToricQuiver, List)
            (symbol _, ToricQuiver, List)
    Node
        Key
            (symbol _, ToricQuiver, List)
        Headline
            taking a subquiver by indexing
        Usage
            Q_L
        Inputs
            Q: ToricQuiver
            L: List
               of integers specifying which arrows to subset
        Outputs
            S: ToricQuiver
                the subquiver in question
        Description
            Text
                This method returns a the subquiver of the quiver {\tt Q} 
                that is made up of the arrows in the list {\tt L}. Note that 
                this method re-orders the subquiver labels to create a standalone quiver.
                To retain the original quiver labels on the subquiver, see the SeeAlso. 
            Example
                Q = bipartiteQuiver(2, 3)
                Q_{0,1,3}
        SeeAlso
            (symbol ^, ToricQuiver, List)
    Node
        Key
            (symbol ^, ToricQuiver, List)
        Headline
            taking a subquiver by indexing
        Usage
            Q^L
        Inputs
            Q: ToricQuiver
            L: List
               of integers specifying which arrows to subset
        Outputs
            S: ToricQuiver
                the subquiver in question
        Description
            Text
                This method returns a the subquiver of the quiver {\tt Q} 
                that is made up of the arrows in the list {\tt L}. 
            Example
                Q = bipartiteQuiver(2, 3)
                Q^{0,1,3}
        SeeAlso
            (symbol _, ToricQuiver, List)
    Node
        Key
            (symbol ==, ToricQuiver, ToricQuiver)
        Headline
            whether two toric quivers are equal.
        Usage
            Q1 == Q2
        Inputs
            Q1: ToricQuiver
            Q2: ToricQuiver
        Outputs
            B: Boolean
        Description
            Text
                This method takes two toric quivers and returns the 
                boolean of the statement {\tt Q1} is equal to {\tt Q2}. 
            Example
                Q = bipartiteQuiver(2, 3)
                R = bipartiteQuiver(2, 2)
                Q == R
            Example
                Q = toricQuiver {{0, 2}, {0, 3}, {1, 2}, {1, 3}}
                R = bipartiteQuiver(2, 2)
                Q == R
        SeeAlso
            toricQuiver
    Node
        Key
            bipartiteQuiver
            [bipartiteQuiver, Flow]
        Headline
            make a toric quiver on underlying bipartite graph
        Usage
            bipartiteQuiver (N, M)
        Inputs
            N: ZZ
                number of vertices that are sources
            M: ZZ
                number of vertices that are sinks
            Flow => 
                specify what form of flow to use. This input can be 
                either a string with values {\tt Canonical} or {\tt Random}, 
                or else a list of integer values. 
        Outputs
            Q: ToricQuiver
        Description
            Text
                This function creates the unique toric quiver whose underlying graph 
                is the complete bipartite graph with 
                {\tt N} source vertices and {\tt M} sink vertices.
            Example
                -- create a bipartite quiver with 2 sources and 3 sinks
                Q = bipartiteQuiver (2, 3)
                -- create a bipartite quiver with 2 sources and 3 sinks and a random flow
                Q = bipartiteQuiver (2, 3, Flow => "Random")
                -- create a bipartite quiver with 2 sources and 3 sinks and a specified flow
                Q = bipartiteQuiver (2, 3, Flow => {1, 2, 1, 3, 1, 4})
        SeeAlso
            toricQuiver
    Node
        Key
            chainQuiver
            [chainQuiver, Flow]
        Headline
            make a toric quiver on underlying graph in the form of a chain
        Usage
            chainQuiver E
        Inputs
            E: List
                number of edges linking each vertex to the next
            Flow => 
                specify what form of flow to use. This input can be 
                either a string with values {\tt Canonical} or {\tt Random}, 
                or else a list of integer values. 
        Outputs
            Q: ToricQuiver
        Description
            Text
                A chain quiver is a quiver where each vertex {\tt N} is connected to
                its predecessor vertex {\tt N - 1} by arrows pointing from {\tt N - 1}
                to {\tt N}, and connected to its successor vertex {\tt N + 1} by arrows
                pointing to {\tt N + 1}.
                This results in a quiver in the shape of a chain, where each pair of vertices
                along the chain is connected by a variable number of edges.
            Example
                -- create a chain quiver with 3 vertices and 6 edges
                Q = chainQuiver {1,2,3}
                -- create a chain quiver with 3 vertices and 6 edges and a random flow
                Q = chainQuiver ({1,2,3}, Flow => "Random")
                -- create a chain quiver with 3 vertices and 6 edges and a specified flow
                Q = chainQuiver ({1,2,3}, Flow => {1, 2, 1, 3, 1, 4})
        SeeAlso
            toricQuiver
    Node
        Key
            threeVertexQuiver
            (threeVertexQuiver, List)
            [threeVertexQuiver, Flow]
        Headline
            make a toric quiver on underlying graph with three vertices and a specified number of edges between each
        Usage
            threeVertexQuiver E
        Inputs
            E: List
                number of edges between each pair of vertices
            Flow => 
                specify what form of flow to use. This input can be 
                either a string with values {\tt Canonical} or {\tt Random}, 
                or else a list of integer values. 
        Outputs
            Q: ToricQuiver
        Description
            Text
                This method can be used to create any quiver in the  family of quivers that can be
                built by defining three vertices and any nonzero number of edges joining each pair of edges
            Example
                -- create a quiver with 3 vertices and 6 edges
                Q = threeVertexQuiver {1,2,3}
                -- create a quiver with 3 vertices and 6 edges and a random flow
                Q = threeVertexQuiver ({1,2,3}, Flow => "Random")
                -- create a quiver with 3 vertices and 6 edges and a specified flow
                Q = threeVertexQuiver ({1,2,3}, Flow => {1, 2, 1, 3, 1, 4})
        SeeAlso
            toricQuiver
    Node
        Key
            allSpanningTrees
        Headline
            find the spanning trees of the underlying graph
        Usage
            allSpanningTrees Q
        Inputs
            Q: ToricQuiver
        Outputs
            L: List
        Description
            Text
                This method returns all of the spanning trees of the 
                underlying graph of the quiver {\tt Q}. Trees are 
                represented as lists of arrow indices.
            Text
                The algorithm is a brute force one, which takes all size {\tt N - 1} subsets
                of the quiver arrows, where {\tt N} is the number of vertices in the quiver,
                and checks if the result is a connected graph.
            Example
                Q = bipartiteQuiver(2, 3)
                allSpanningTrees(Q)
        SeeAlso
            toricQuiver
    Node
        Key
            basisForFlowPolytope
            (basisForFlowPolytope, ToricQuiver)
            (basisForFlowPolytope, List, ToricQuiver)
        Headline
            compute the necessary basis vectors for the hyperplane of a flow polytope
        Usage
            basisForFlowPolytope Q
            basisForFlowPolytope (T, Q)
        Inputs
            Q: ToricQuiver
            T: List
                of edges comprising the spanning tree to use to generate the basis. 
        Outputs
            B: Matrix
                whose rows are the basis vectors.
        Description
            Text
                For a generic weight, theta, in $C(Q)$, the flow polytope has the same dimension as the kernel of the inc map, 
                which is $|Q_0| - |Q_1| + 1$. Moreover, given a spanning tree of the quiver, there exists a natural basis 
                for the kernel of the inc map constructed from the combinatorics of the quiver, 
                see 
                @{HREF{
                "https://www.etd.ceu.edu/2015/joo_daniel.pdf", 
                "Dániel Joó, Toric Quiver Varieties, Ph.D thesis, 
                2015."}}@
                Therefore, we can translate the flow polytope 
                to this kernel and express the polytope on such basis. 
                With basisForFlowPolytope Q, we calculate the basis for inc map from a spanning tree of it. 
                If none is provided, then one is randomly chosen.

 
            Example
                basisForFlowPolytope bipartiteQuiver(2,3)
            Example
                basisForFlowPolytope ({0,1,4,5},  bipartiteQuiver(2,3))
        SeeAlso
            flowPolytopeVertices
    Node
        Key
            coneSystem
        Headline
            compute the chamber decomposition of weights
        Usage
            coneSystem Q
        Inputs
            Q: ToricQuiver
        Outputs
            L: List
                of Cones
        Description
            Text
                The set of weights {\tt th} for which the polytope {\tt (Q,th)} is 
                nonempty lies in a fan {\tt CQ}. This fan is partitioned into cones by the 
                walls of the toric quiver {\tt Q}, and for each partition there exists 
                a unique flow polytope. For a detailed discussion see
                Lutz Hille  
                @{HREF{
                "https://doi.org/10.1016/S0024-3795(02)00406-8",
                "\"Quivers, cones and polytopes\", Linear algebra and its applications 365 (2003): 215-237."
                }}@ 

            Example
                Q = toricQuiver {{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}};
                CS = coneSystem Q
        SeeAlso
            flowPolytopeVertices
    Node
        Key
            flowPolytopeVertices
            (flowPolytopeVertices, ToricQuiver)
            (flowPolytopeVertices, List, ToricQuiver)
            [flowPolytopeVertices, Format]
        Headline
            generate the polytope associated to a toric quiver
        Usage
            flowPolytopeVertices Q
            flowPolytopeVertices(W, Q)
        Inputs
            Q: ToricQuiver
            W: List
                of integer values specifying a weight on the vertices
            Format => String
                specifying what basis to use. The default value {\tt SimplifiedBasis} 
                returns the polytope in a basis giving the minimal degree 
                necessary for polytope dimension. 
        Outputs
            : 
                Depending on the option for Format, this method returns a Matrix or List of Lists
                giving the coordinates of the vertices defining the flow polytope. 
                If the flow polytope does not exist for the given weight. Then, it returns an empty list.
        Description
            Text
                Associated with every acyclic toric quiver and weight pair is a flow polytope. This polytope can be translated to the kernel of the inc map, 
                so it is full dimensional. By default, the output lists the vertices within this vector space. To obtain the presentation in the original fiber, 
                use {\tt Format => "FullBasis"}.    
            Example
                flowPolytopeVertices(bipartiteQuiver(2, 3))
            Text 
                We can vary the weight of the quiver to define the flow polytope
            Example
                flowPolytopeVertices({-3,-3,2,2,2}, bipartiteQuiver(2, 3))
            Text 
                The user can also recover the polytope $\Delta(Q,\theta)$ within the inverse of the corresponding inc map, that is within $inc^{-1}(\theta)$. 
            Example
                flowPolytopeVertices( bipartiteQuiver(2, 3), Format => "FullBasis")
        SeeAlso
            basisForFlowPolytope
    Node
        Key
            incInverse
            (incInverse, List, ToricQuiver)
        Headline
            compute a flow in the preimage for a given weight
        Usage
            incInverse(W, Q)
        Inputs
            W: List
                of integers, specifying the weight on each vertex
            Q: ToricQuiver
        Outputs
            F: List
                giving a flow in the preimage of the input weight.
        Description
            Text
                Every integral flow induces a weight on the vertices $Q_0$ as follows: Let $a \in Q_1$ be an arrow. 
                The symbol  $a^{+} \in Q_0$ denotes its head and the symbol $a^{-} \in Q_0$ denotes its tail. 
                The so called incidence map generates a weight from the flow $\mathbf{w}$ by
                $$
                \text{inc}(\mathbf{w})(i) 
                := \sum_{a\in Q_1 \atop a^{+} = i} \mathbf{w}(a)  
                - \sum_{a\in Q_1 \atop a^{-} = i} 
                \mathbf{w}(a) \quad \text{ for all } i \in Q_0.
                $$
                The function incInverse calculates a vector in the preimage of such a map.    
            
            Example
                Q = toricQuiver(bipartiteQuiver(2,3));
                th = {-5,-1,2,2,2};
                incInverse(th, Q)
        SeeAlso
            toricQuiver
            getWeights
    Node
        Key
            isAcyclic
            (isAcyclic, Matrix)
            (isAcyclic, ToricQuiver)
        Headline
            whether a toric quiver has no cycles
        Usage
            isAcyclic M
            isAcyclic Q
        Inputs
            Q: ToricQuiver
        Outputs
            : Boolean
        Description
            Text
                This method determines whether a quiver is free from oriented cycles.
            Example
                isAcyclic bipartiteQuiver(2, 3)
            Example
                isAcyclic toricQuiver matrix({{-1, 1, -1, -1}, {1, -1, 0, 0}, {0, 0, 1, 1}})
        SeeAlso
            toricQuiver
    Node
        Key
            isClosedUnderArrows
            (isClosedUnderArrows, Matrix, List)
            (isClosedUnderArrows, List, Matrix)
            (isClosedUnderArrows, List, ToricQuiver)
            (isClosedUnderArrows, Matrix, ToricQuiver)
            (isClosedUnderArrows, ToricQuiver, ToricQuiver)
        Headline
            whether a subquiver closed under arrows
        Usage
            isClosedUnderArrows (M, V)
            isClosedUnderArrows (V, M)
            isClosedUnderArrows (V, Q)
            isClosedUnderArrows (M, Q)
            isClosedUnderArrows (SQ, Q)
        Inputs
            M: Matrix
                incidence matrix of subquiver or quiver to check
            Q: ToricQuiver
            SQ: ToricQuiver
                subquiver of Q to check 
            V: List
                set of vertices corresponding to the subquiver
        Outputs
            : Boolean
                true if the subquiver is closed under arrows with respect to the quiver, and false otherwise.
        Description
            Text
                checks that a set of vertices is closed under arrows with respect to the toricQuiver {\tt Q}. 
                That is, for any $v\in V$, then any arrow in $Q_1$ with tail $v$ must have head in $V$ as well. 
                Note that this does not require that $V\subset Q_0$.
            Text
                Note also that the attribute closed under arrows relates to the underlying graph. 
                Arrows with flow of 0 (which occur in cases where using the quiver subset form: {\tt Q^S} 
                rather than {\tt Q_S}) are considered as valid arrows. 
            Example
                isClosedUnderArrows ({0, 2, 3}, bipartiteQuiver(2, 3))
                isClosedUnderArrows ({2, 3, 4}, bipartiteQuiver(2, 3))
            Example
                Q = threeVertexQuiver {1, 2, 3}
                SQ = Q_{0,1}
                isClosedUnderArrows (SQ, Q)
            Example
                Q = threeVertexQuiver {1, 2, 3}
                SQ = Q^{0,1}
                isClosedUnderArrows (SQ, Q)
        SeeAlso
            toricQuiver
    Node
        Key
            isSemistable
            (isSemistable, List, ToricQuiver)
            (isSemistable, ToricQuiver, ToricQuiver)
        Headline
            whether a subquiver is semistable with respect to a given weight
        Usage
            isSemistable (L, Q)
            isSemistable (sQ, Q)
        Inputs
            L: List
                of the indices of arrows in {\tt Q} that make up the subquiver in question
            Q: ToricQuiver
            SQ: ToricQuiver
                A subquiver of the quiver {\tt Q}
        Outputs
            : Boolean
                true if the subquiver is semistable, and false otherwise.
        Description
            Text
                This function determines if a given subquiver 
                is semistable with respect to the weight saved on {\tt Q}. 
                A subquiver {\tt SQ} of the quiver {\tt Q} is semistable if for every subset 
		{\tt V} of the vertices of {\tt Q} that is also {\tt SQ}-successor closed, 
		the sum of the weights associated to {\tt V} is nonnegative. 
            Example
                isSemistable ({0, 1}, bipartiteQuiver(2, 3))
            Example
                isSemistable ({0, 1, 3, 4, 5}, bipartiteQuiver(2, 3))
            Example
                Q = bipartiteQuiver(2, 3);
                S = first(subquivers(Q, Format => "quiver", AsSubquiver => true))
                isSemistable (S, Q)
        SeeAlso
    Node
        Key
            isStable
            (isStable, List, ToricQuiver)
            (isStable, ToricQuiver, ToricQuiver)
        Headline
            whether a subquiver is semistable with respect to a given weight
        Usage
            isStable (L, Q)
            isStable (SQ, Q)
        Inputs
            L: List
                of the indices of arrows in {\tt Q} that make up the subquiver in question
            Q: ToricQuiver
            SQ: ToricQuiver
                A subquiver of the quiver {\tt Q}
        Outputs
            : Boolean
                true if the subquiver is stable, and false otherwise.
        Description
            Text 
                This function determines if a given subquiver 
                is stable with respect to the weight saved on {\tt Q}. 
                A subquiver {\tt SQ} of the quiver {\tt Q} is stable if for every subset 
		{\tt V} of the vertices of {\tt Q} that is also {\tt SQ}-successor closed, 
		the sum of the weights associated to {\tt V} is positive. 
            Example
                Q = bipartiteQuiver(2, 3);
                P = Q^{0,1,4,5};
                isStable(P, Q)
            Example
                isStable ({0, 1}, bipartiteQuiver(2, 3))
            Example
                Q = bipartiteQuiver(2, 3)
                S = first(subquivers(Q, Format => "quiver", AsSubquiver => true))
                isStable (S, Q)
        SeeAlso
    Node
        Key
            isTight
            (isTight, ToricQuiver)
            (isTight, ToricQuiver, List)
            (isTight, List, ToricQuiver)
            [isTight, Format]
        Headline
            determine if toric quiver is tight
        Usage
            isTight Q
            isTight(Q, W)
            isTight(W, Q)
            isTight(W, Q, Format => "Flow")
            isTight(W, Q, Format => "Weight")
        Inputs
            Q: ToricQuiver
            W: List
            Format => 
                specify whether input W is a flow (integer values associated to each arrow) 
                or the image of the flow under the map {\tt weights} (integer values associated to each vertex). 
        Outputs
            : Boolean
                true if the toric quiver is tight with respect to the specified flow, and false otherwise
        Description
            Text
                A toric quiver $Q$ is tight with respect to a given flow if there is no maximal 
                unstable subquiver of codimension 1. That is, every unstable subquiver of $Q$ 
                has at most $|Q_1|-2$ arrows. This method determines if a toric quiver $Q$ is 
                tight with respect to the vertex weights induced by its flow. 
            Example
                isTight bipartiteQuiver(2, 3)
            Example
                isTight bipartiteQuiver(2, 3, Flow => "Random")
            Example
                isTight (bipartiteQuiver(2, 3), {2,1,2,3,2,3})
            Example
                isTight ({0,0,0,0,0,1}, bipartiteQuiver(2, 3))
        SeeAlso
    Node
        Key
            isWellDefined
            (isWellDefined, ToricQuiver)
        Headline
            determine if toric quiver is correctly constructed
        Usage
            isWellDefined Q
        Inputs
            Q: ToricQuiver
        Outputs
            : Boolean
                true if the vertices and edges of the toric quiver agree, and if the flow for the quiver is a preimage for the weight. Otherwise, false.
        Description
            Text
                This method checks that the various attributes associated to the given toric 
                quiver are in the correct dimension. It also checks that the weights for the
                quiver are induced by the flow, and that the vertices and edges are constructed
                without gaps or missing data.
            Example
                isTight bipartiteQuiver(2, 3, Flow => "Random")
        SeeAlso
    Node
        Key
            makeTight
        Headline
            return a tight quiver with the same flow polytope
        Usage
            makeTight(W, Q)
        Inputs
            W: List
               of values corresponding to a weight on each arrow of {\tt Q}
            Q: ToricQuiver
        Outputs
            Q: ToricQuiver
                that is tight with respect to the flow on the input, and which has the same flow polytope as the input.
        Description
            Text
                Let $\theta$ be an integral weight assigned to the vertices of a quiver $Q$. The quiver $Q$ is called $\theta$-tight if for every arrow $\alpha$, 
                the subquiver $Q\setminus \alpha$ is $\theta$-stable. Every quiver can be tightened by contraction of certain arrows in Q and changing the weight accordingly, 
                see Section 4 at
                @{HREF{"https://link.springer.com/article/10.1007/s00229-009-0255-6", 
                "Altmann, Klaus, and Duco van Straten. \"Smoothing of quiver varieties.\" manuscripta mathematica 129 (2009): 211-230."}}@ 
            Example
                Q = bipartiteQuiver(2,3)
                w = {-5,-1,2,2,2}
                makeTight(w, Q)
        SeeAlso
    Node
        Key
            maxCodimensionUnstable
            (maxCodimensionUnstable, ToricQuiver)
        Headline
            compute the maximal codimension of the unstable loci of a quiver
        Usage
            maxCodimensionUnstable Q
        Inputs
            Q: ToricQuiver
        Outputs
            : ZZ
        Description
            Text
                It computes the maximal codimension of the unstable loci a given quiver {\tt Q}
            Example
                maxCodimensionUnstable bipartiteQuiver(2, 3)
            Text     
                We note that this value can range from $|Q_1|$, as is the case with the quiver associated 
                with the projective space, to 1 when the quiver is not tight.
            Example 
                maxCodimensionUnstable toricQuiver({{0,1},{0,1},{0,1}})
        SeeAlso
    Node
        Key
            maximalNonstableSubquivers
            [maximalNonstableSubquivers, ReturnSingletons]
            [maximalNonstableSubquivers, Format]
        Headline
            return the maximal subquivers that are semistable
        Usage
            maximalNonstableSubquivers Q
        Inputs
            Q: ToricQuiver
            ReturnSingletons => Boolean
                Whether or not to return singleton vertices subquivers
            Format => String
                format for representing the subquivers
        Outputs
            L: HashTable
                consisting of two keys: {\tt Nonsingletons} and {\tt Singletons}
        Description
            Text
                This method takes all of the possible subquivers of a given quiver {\tt Q} 
                and returns those that are not stable, and which are maximal with respect to the weight on the quiver {\tt Q}.
            Text
                Subquivers are represented by lists of arrows, except in the case of subquivers that consist of singleton vertices. 
            Example
                maximalNonstableSubquivers bipartiteQuiver (2, 3)
        SeeAlso
    Node
        Key
            maximalUnstableSubquivers
            [maximalUnstableSubquivers, ReturnSingletons]
            [maximalUnstableSubquivers, Format]
        Headline
            return the maximal subquivers that are unstable
        Usage
            maximalUnstableSubquivers Q
        Inputs
            Q: ToricQuiver
            ReturnSingletons => Boolean
                Whether or not to return singleton vertices subquivers
            Format => String
                format for representing the subquivers
        Outputs
            L: HashTable
                consisting of two keys: {\tt Nonsingletons} and {\tt Singletons}
        Description
            Text
                This method takes all of the possible subquivers of a given quiver {\tt Q} 
                and returns those that are both unstable and maximal with respect to the weight on the quiver {\tt Q}.
            Text
                Subquivers are represented by lists of arrows, except in the case of subquivers that consist of singleton vertices. 
            Example
                maximalUnstableSubquivers bipartiteQuiver (2, 3)
        SeeAlso
    Node
        Key
            mergeOnArrow
            (mergeOnArrow, ToricQuiver, ZZ, ToricQuiver, ZZ)
            (mergeOnArrow, ToricQuiver, ZZ, Matrix, ZZ)
            (mergeOnArrow, Matrix, ZZ, Matrix, ZZ)
            (mergeOnArrow, Matrix, ZZ, ToricQuiver, ZZ)
        Headline
            join two quivers together by identifying an arrow from each
        Usage
            mergeOnArrow (Q1, A1, Q2, A2)
            mergeOnArrow (Q1, A1, M2, A2)
            mergeOnArrow (M1, A1, M2, A2)
            mergeOnArrow (M1, A1, Q2, A2)
        Inputs
            A1: ZZ
            A2: ZZ
            M1: Matrix
            M2: Matrix
            Q1: ToricQuiver
            Q2: ToricQuiver
        Outputs
            : ToricQuiver
                obtained by merging the two provided quivers together at the specified arrows
        Description
            Text
                This method creates a new quiver from joining two toricQuivers together by identifying arrow $A1$ in $Q1$ with arrow $A2$ in $Q2$. 
                The input matrices must correspond to valid graphs, and the integers must correspond to arrows in each of the provided quiver objects.
            Example
                mergeOnArrow (bipartiteQuiver (2, 3), 0, bipartiteQuiver (2, 3), 0)
            Example
                mergeOnArrow (bipartiteQuiver (2, 3), 0, matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), 0)
            Example
                mergeOnArrow (matrix ({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), 0, bipartiteQuiver (2, 3), 0)

        SeeAlso
    Node
        Key
            mergeOnVertex
            (mergeOnVertex, ToricQuiver, ZZ, ToricQuiver, ZZ)
            (mergeOnVertex, ToricQuiver, ZZ, Matrix, ZZ)
            (mergeOnVertex, Matrix, ZZ, Matrix, ZZ)
            (mergeOnVertex, Matrix, ZZ, ToricQuiver, ZZ)
        Headline
            join two quivers together by identifying a vertex from each
        Usage
            mergeOnVertex (Q1, V1, Q2, V2)
            mergeOnVertex (Q1, V1, M2, V2)
            mergeOnVertex (M1, V1, M2, V2)
            mergeOnVertex (M1, V1, Q2, V2)
        Inputs
            M1: Matrix
            M2: Matrix
            Q1: ToricQuiver
            Q2: ToricQuiver
            V1: ZZ
            V2: ZZ
        Outputs
            : ToricQuiver
                obtained by merging the two provided quivers together at the specified vertices
        Description
            Text
                This method creates a new quiver from joining two toricQuivers together by identifying 
                vertex $V1$ in $Q1$ with vertex $V2$ in $Q2$. The input matrices must correspond to valid graphs,
                and the integers must correspond to vertices in each of the provided quiver objects.
            Example
                mergeOnVertex (bipartiteQuiver (2, 3), 1, bipartiteQuiver (2, 3), 0)
            Example
                mergeOnVertex (bipartiteQuiver (2, 3), 1, matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), 0)
                mergeOnVertex (matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), 1, bipartiteQuiver (2, 3), 0)
        SeeAlso
    Node
        Key
            potentialWalls
            (potentialWalls, ToricQuiver)
            (potentialWalls, Matrix)
        Headline
            lists the potential walls in the weight chamber decomposition for a given quiver
        Usage
            potentialWalls Q
            potentialWalls M
        Inputs
            Q: ToricQuiver
        Outputs
            : List
                of potential walls for he cone system associated to the toric quiver
        Description
            Text
                Every wall can be represented uniquely by a partition of the vertices 
                {\tt Q0} of {\tt Q} into two sets {\tt Qplus} and {\tt Qminus}. As a partition 
                can be expressed in terms of only one of the subsets, only one of the two sets {\tt Qplus} 
                and {\tt Qminus} is used in every case. 
                Thus we denote the wall {\tt W} by the subset of vertices {\tt Qplus} used for defining it. 

            Text
                This method is written to compute the potential walls based on the incidence matrix,
                in the case of a flow of all unit values, or based on the entire quiver if the flow is nontrivial.

            Example
                potentialWalls toricQuiver {{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}}
            Example
                potentialWalls chainQuiver {1}
        SeeAlso
    Node
        Key
            primitiveArrows
        Headline
            list the primitive arrows in a quiver
        Usage
            primitiveArrows Q
        Inputs
            Q: ToricQuiver
        Outputs
            L: List
                of arrow indices corresponding to the primitive arrows in {\tt Q}
        Description
            Text
                This method returns a list of the arrows in the provided quiver that are primitive.
                An arrow {\tt a=(v0,v1)} in the quiver {\tt Q} is primitive if there exists an 
                oriented non-empty path from {\tt v0} to {\tt v1} in {\tt Q} that is distinct from {\tt a}. 
                Thus, if the arrow {\tt a} is primitive, then removing it from the quiver results in a quiver 
                that still contains a path between its endpoints {\tt v0} and {\tt v1}.
            Example
                primitiveArrows toricQuiver {{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}}
        SeeAlso
    Node
        Key
            quiverIncidenceMatrix
            (quiverIncidenceMatrix, ToricQuiver)
        Headline
            return the graph incidence matrix attribute associated to the toric quiver
        Usage
            quiverIncidenceMatrix Q
        Inputs
            Q: ToricQuiver
        Outputs
            M: Matrix
                that is the incidence matrix for the graph of the toric quiver
        Description
            Text
                This method returns the incidence matrix that is stored in the quiver.
            Example
                Q = bipartiteQuiver(2, 3);
                quiverIncidenceMatrix Q
        SeeAlso
            ToricQuiver
    Node
        Key
            quiverEdges
            (quiverEdges, ToricQuiver)
        Headline
            return the graph edges associated to the toric quiver
        Usage
            quiverEdges Q
        Inputs
            Q: ToricQuiver
        Outputs
            E: List
                of edges, each of which is a pair of vertices.
        Description
            Text
                This method returns the list of edges that are in the graph of the provided toric quiver.
            Example
                Q = bipartiteQuiver(2, 3);
                quiverEdges Q
        SeeAlso
            ToricQuiver
    Node
        Key
            quiverFlow
            (quiverFlow, ToricQuiver)
        Headline
            return the flow attribute associated to the toric quiver
        Usage
            quiverFlow Q
        Inputs
            Q: ToricQuiver
        Outputs
            F: List
                the flow for the toric quiver
        Description
            Text
                This method returns the flow of the provided toric quiver, which is a list of numeric values.
            Example
                Q = bipartiteQuiver(2, 3, Flow=> {1, 2, 3, 4, 5, 6});
                quiverFlow Q
        SeeAlso
            ToricQuiver
            incInverse
    Node
        Key
            quiverVertices
            (quiverVertices, ToricQuiver)
        Headline
            return the vertices of the toric quiver
        Usage
            quiverVertices Q
        Inputs
            Q: ToricQuiver
        Outputs
            V: List
                of the vertices in the quiver
        Description
            Text
                This method returns the vertices that are in the provided toric quiver.
            Example
                Q = bipartiteQuiver(2, 3);
                quiverVertices Q
        SeeAlso
            ToricQuiver
    Node
        Key
            quiverWeights
            (quiverWeights, ToricQuiver)
        Headline
            return the weight attribute associated to the toric quiver
        Usage
            quiverWeights Q
        Inputs
            Q: ToricQuiver
        Outputs
            W: List
                of the weights induced by the flow on the quiver
        Description
            Text
                This method returns the weights of the provided toric quiver.
                The weights are the image of the quiver flow under the inc map, which is defined as
                $$
                \text{inc}(\mathbf{w})(i) 
                := \sum_{a\in Q_1 \atop a^{+} = i} \mathbf{w}(a)  
                - \sum_{a\in Q_1 \atop a^{-} = i} 
                \mathbf{w}(a) \quad \text{ for all } i \in Q_0.
                $$
                where for any arrow $a\in Q_1$, we denote its head as $a^{+} \in Q_0$ and its tail as $a^{-} \in Q_0$.
            Example
                Q = bipartiteQuiver(2, 3);
                quiverWeights Q
        SeeAlso
            ToricQuiver
            incInverse
    Node
        Key
            referenceThetas
            (referenceThetas, List)
        Headline
            return a weight for all polytopes associated to a toric quiver
        Usage
            referenceThetas QCS
        Inputs
            QCS: List
                of cones comprising the chamber decomposition for weights
        Outputs
            L: List
                of weights
        Description
            Text
                This method uses the {\tt interiorVector} method for a Cone from the {\tt Polyhedra}
                package to generate a single internal poin for each of the cones in the input list {\tt QCS}.
            Example
                Q = toricQuiver {{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}};
                CS = coneSystem Q;
                referenceThetas CS
        SeeAlso
    Node
        Key
            samePolytope
            (samePolytope, List, List, ToricQuiver)
        Headline 
            whether two weights produce the same flow polytope
        Usage
            samePolytope(Th1, Th2, TQ)
        Inputs
            Th1: List
            Th1: List
            TQ: ToricQuiver
        Outputs
            B: Boolean
                whether the two weights correspond to the same polytope
        Description
            Text
                This function returns either a boolean value of {\tt true} or else a string
                describing why the outcome cannot be determined. It requires that polytopes be 
                smooth and that the set of stable trees for both weights be nonempty.
                This is computed by calculating the flow polytope for the toric quiver with each
                of the two weights and comparing the resulting polytopes. The polytopes are considered
                equal if they are isomorphic, using the areIsomorphic method in the LatticePolytopes package.
            Example
                Q = toricQuiver({{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}});
                samePolytope({-3,2,-1,2},{-2,1,-2,3}, Q)    
        SeeAlso
            toricQuiver
            flowPolytopeVertices
        Caveat
            This operation is computationally expensive, and may not perform well for quivers whose chamber systems are comprised of many subchambers.
    Node
        Key
            stableTrees
        Headline
            return the spanning trees that are stable
        Usage
            stableTrees(th, Q)
        Inputs
            th: List
                of weights corresponding to each vertex
            Q: ToricQuiver
        Outputs
            L: List
                of lists, each representing the arrows that comprise a spanning tree that is stable with respect to the weight th
        Description
            Example
                Q = bipartiteQuiver(2,3);
                th = {-3,-3,2,2,2};
                stableTrees(th, Q)
        SeeAlso
    Node
        Key
            subquivers
            (subquivers, Matrix)
            (subquivers, ToricQuiver)
            [subquivers, Format]
            [subquivers, AsSubquiver]
        Headline
            return all possible subquivers of a given quiver
        Usage
            subquivers M
            subquivers Q
        Inputs
            M: Matrix
            Q: ToricQuiver
            Format => String
                options include {\tt quiver}, which returns a list of quivers, and {\tt list}, 
                which returns a list of arrows for each subquiver
            AsSubquiver => Boolean
                if Format is specified as {\tt quiver}, then applying 
                {\tt AsSubquiver = true} insures that the matrix representation 
                of the subquiver is the same size as the matrix original quiver
        Outputs
            L: List
                of either quiver objects, or arrow indices
        Description
            Text 
                A subquiver is a subgraph of a quiver. Specifically, it is formed by selecting a subset of the arrows
                from the original quiver, ensuring that the tails and heads of the chosen arrows correspond to the selected vertices. 
                There are several ways to represent a subquiver:
            Text      
                @UL {
                    {"Using a list of arrow indices to indicate the selected arrows. "}, 
                    {"Selecting a subset of rows and columns from the original incidence matrix. Here, we leverage the fact that columns 
                      in the incidence matrix correspond to arrows in the quiver."},
                }@
            Text
                subquivers Q list all possible subquivers of Q.
            
            Example
                Q = chainQuiver {2}
                subquivers Q
                subquivers(Q, Format => "list")
            Example
                subquivers bipartiteQuiver(2, 2)
                subquivers(bipartiteQuiver(2, 2), Format => "list")
                subquivers(bipartiteQuiver(2, 2), Format => "quiver", AsSubquiver => true)
        SeeAlso
            AsSubquiver
    Node
        Key
            wallType
            (wallType, List, ToricQuiver)
            (wallType, List, Matrix)
        Headline
            get the type of a wall for a given quiver
        Usage
            wallType (Qplus, Q)
            wallType (Qplus, M)
        Inputs
            Q: ToricQuiver
            M: Matrix
            Qplus: List
        Outputs
            WT: Sequence
                having two nonnegative integer entries
        Description
            Text
                Every wall can be represented uniquely by a partition of the vertices 
                {\tt Q0} of {\tt Q} into two sets {\tt Qplus} and {\tt Qminus}. 
                We denote the wall {\tt W} by the subset of vertices {\tt Qplus} used for defining it. 
            Text
                The type of the wall is defined as {\tt (t+,t-)} where {\tt t^+} 
                is the number of arrows starting {\tt Qplus} and ending in 
                {\tt Qminus}, and {\tt t-} is the number of arrows starting {\tt Qminus} 
                and ending in {\tt Qplus}. 

            Text
                This method is written to compute the wall type based on the incidence matrix,
                in the case of a trivial flow, or the entire quiver.

            Example
                wallType({0,2,3}, bipartiteQuiver(2, 3))
            Example
                wallType({0,2,3}, quiverIncidenceMatrix(bipartiteQuiver(2, 3)))
            Example
                wallType({1,2,3}, chainQuiver({2,3,4}))
        SeeAlso
    Node
        Key
            getWeights
            (getWeights, Matrix)
            (getWeights, ToricQuiver)
        Headline
            image of the flow on the vertices
        Usage
            getWeights M
            getWeights Q
        Inputs
            M: Matrix
            Q: ToricQuiver
        Outputs
            L: List
                of integers, corresponding to the image of the flow of the provided toric quiver under the $Inc$ map
        Description
            Text
                This method returns the weight of the quiver.
                This vector is the image of its flow under the $inc$ map, which is defined as
                $$
                \text{inc}(\mathbf{w})(i) 
                := \sum_{a\in Q_1 \atop a^{+} = i} \mathbf{w}(a)  
                - \sum_{a\in Q_1 \atop a^{-} = i} 
                \mathbf{w}(a) \quad \text{ for all } i \in Q_0.
                $$
                where for any arrow $a\in Q_1$, we denote its head as $a^{+} \in Q_0$ and its tail as $a^{-} \in Q_0$.
            Example
                Q = bipartiteQuiver(2, 3, Flow => "Random")
                getWeights Q
        SeeAlso
            incInverse
-- documentation for symbols
    Node
        Key
            AsSubquiver
        Description
            Text
                option for subquiver representation. Applying
                {\tt AsSubquiver = true} insures that the matrix representation 
                of the subquiver is the same size as the matrix original quiver. 
                If false, then the subquiver is returned as a standalone quiver 
                represented by only the vertices and arrows comprising the subquiver. 
            Example
                subquivers(bipartiteQuiver(2, 2), Format => "quiver", AsSubquiver => true)
                subquivers(bipartiteQuiver(2, 2), Format => "quiver", AsSubquiver => false)
        SeeAlso
            subquivers
    Node
        Key
            Flow
        Description
            Text
                optional argument that can be a string with values {\tt Canonical}, which assigns 
                a value of 1 to each edge, or {\tt Random}, which assigns random integer values. 
            Example
                -- create a toric quiver from a matrix with keyword flow
                Q = toricQuiver(matrix({{-1,-1,-1,-1},{1,1,0,0},{0,0,1,1}}), Flow => "Canonical")
                -- create a toric quiver from a matrix with random flow
                Q = toricQuiver(matrix({{-1,-1,-1,-1},{0,0,1,1},{1,1,0,0}}), Flow => "Random")
                -- create a bipartite quiver with a random flow
                Q = bipartiteQuiver(2, 3, Flow => "Random")
        SeeAlso
            toricQuiver
    Node
        Key
            ReturnSingletons
        Description
            Text
                This is an optional argument for the function {\tt maximalNonstableSubquivers},
                which allows the user to consider single vertices as subquivers. For most computations, 
                these subquivers are trivial, and are ignored. 
            Example
                maximalNonstableSubquivers(bipartiteQuiver (2, 3), ReturnSingletons => true)
                maximalNonstableSubquivers(bipartiteQuiver (2, 3), ReturnSingletons => false)
        SeeAlso
            maximalNonstableSubquivers
///
TEST ///
    testQuiverConstruction = Q -> (
        -- assert (isWellDefined(Q));
        AllSubquivers = subquivers(Q, Format => "list");
        EdgeSubsets = subsets(#quiverEdges(Q));
        assert (#AllSubquivers == #EdgeSubsets - 2);
    )
    Q = threeVertexQuiver {1,2,3};
    testQuiverConstruction(Q)

    Q = bipartiteQuiver(2, 2);
    testQuiverConstruction(Q);
    assert (allSpanningTrees Q == {{1, 2, 3}, {0, 2, 3}, {0, 1, 3}, {0, 1, 2}});
    assert (not isClosedUnderArrows({1, 2}, Q));
    munsbs = maximalNonstableSubquivers(Q, ReturnSingletons => true)
    vals = flatten for key in keys(munsbs) list(munsbs#key)
    assert (vals === {{0}, {1}, {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}})
    CS = coneSystem Q;
    rts = referenceThetas CS;
    assert (#CS == #rts);

    Q = bipartiteQuiver(2, 3);
    testQuiverConstruction(Q)
    assert (#potentialWalls(Q) == 11)
    assert isTight Q
    assert (getWeights Q === {-3, -3, 2, 2, 2})
    assert (flowPolytopeVertices Q == {{-1, 1}, {-1, 0}, {1, -1}, {0, -1}, {1, 0}, {0, 1}})
    assert (entries basisForFlowPolytope Q === {{-1, 0}, {0, -1}, {1, 1}, {1, 0}, {0, 1}, {-1, -1}})
    QConeSystem = coneSystem Q;
    th = {-5, -1, 2, 2, 2};
    F = incInverse(th, Q)
    assert not isTight(F, Q)
    assert isAcyclic makeTight(th, Q);
    assert not isSemistable({1, 2}, Q)
    assert isStable({1, 2, 3, 4}, Q)
    assert (stableTrees(th, Q) === {{0, 1, 2, 5}, {0, 1, 2, 4}, {0, 1, 2, 3}})
    assert (maxCodimensionUnstable(Q) == 6)
    assert (wallType({0,2,3}, Q) == (1, 2))

    M = maximalUnstableSubquivers(Q);
    for v in values M do (
        assert (#v == 6)
    )

    P = chainQuiver {2, 2}
    testQuiverConstruction(P)

    Q = chainQuiver {1, 2, 3}
    testQuiverConstruction(Q)
    assert (mergeOnVertex(P, 2, Q, 0) == chainQuiver {2, 2, 1, 2, 3})
    assert (mergeOnArrow(P, 3, Q, 0) == chainQuiver {2, 2, 2, 3})

    Q = toricQuiver {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}}
    testQuiverConstruction(Q)
    assert (primitiveArrows Q === {0, 3, 5})
    assert samePolytope({-3, 2, -1, 2}, {-2, 1, -2, 3}, Q)
    assert (#potentialWalls Q > 0);
///
end--
