(*tableau*)
(*Description: Produces the simplex tableau corresponding to a chosen basis: Ab is the constraint matrix augmented with the RHS column b,target is the objective row (of the same width as rows of A; note its entries are the OPPOSITE of the coefficients of the target function), and basis is a list of m column indices defining the desired basis.
Returns the pivoted tableau as a formatted table with labeled rows and columns,or an error if the basis is invalid or infeasible. *)

(*Error messages*)
tableau::argerr="Dimensions of A and target do not match";
tableau::argerrb="`1` is not a basis (columns are linearly dependent, indices out of range, or wrong number of basis variables)";
tableau::argerrfb="`1` is a basis but not a feasible basis (some basic variable would assume a negative value)";

tableau[Ab_,target_,basis_]:=Module[{m,N,lastcol,Aaug,G,basisCols,var,Bvar,innertab,tab},
(*In class, our matrix A is m x n, here it is Ab and has N=n+1 columns, since last column is b*)
{m,N}=Dimensions[Ab];
(*Guard 1: target row must have same length as Ab's row width*)
If[Length[target]!=N,Message[tableau::argerr];
Return[$Failed]];
(*Guard 2: basis must have exactly m indices,all within 1..N-1*)
If[Length[basis]!=m||Min[basis]<1||Max[basis]>N-1,Message[tableau::argerrb,basis];
Return[$Failed]];
(*Guard 3: basis columns of constraint matrix must be linearly independent*)
If[Det[Ab[[Range[m],basis]]]==0,Message[tableau::argerrb,basis];
Return[$Failed]];
(*Augment Ab with the target row*)
Aaug=Append[Ab,target];(*(m+1) x N matrix*)
(*Build the (m+1)x(m+1) pivot matrix. Take the basis columns from Aaug: this is (m+1) x m. Append a {0,...,0,1} column to anchor the objective row, giving a (m+1)x(m+1) square matrix, then invert.*)
lastcol=Append[Table[0,{m}],1];
basisCols=Transpose[Append[Transpose[Aaug[[All,basis]]],lastcol]];
If[Det[basisCols]==0,Message[tableau::argerrb,basis];
Return[$Failed]];
G=Inverse[basisCols];
(*Apply pivot operations: new tableau=G.Aaug*)
innertab=G.Aaug;
(*Feasibility check: RHS column (column N) of constraint rows must be >= 0*)
If[!VectorGreaterEqual[{innertab[[Range[m],N]],Table[0,{m}]}],Message[tableau::argerrfb,basis];
Return[$Failed]];
(*Build variable labels for columns and basis-variable labels for rows*)
var=Table["x"<>ToString[i],{i,1,N-1}];
var=Prepend[Append[var," "]," "];
Bvar=Append[Table["x"<>ToString[basis[[i]]],{i,1,Length[basis]}]," "];
(*Attach row labels and header row,return as TableForm*)
tab=Prepend[MapThread[Prepend,{innertab,Bvar}],var];
(*Output: pivoted tableau as a formatted table with labeled rows and columns*)
Return[tab//TableForm]
];


(*thetas*)
(*Description: Computes the theta ratios for a pivot step. Input: tab is the raw tableau grid (the underlying array of a tableau output, before TableForm formatting),and j is the column index of the entering variable. Returns a formatted table showing, for each basic variable, the ratio of its RHS value to its entry in column j,or "(unconstrained)" if that entry is negative.Rows with a zero entry in column j are omitted.*)

thetas[tab_,j_]:=Module[{m,n,thetas,i},
(*Input: tableau tab and choice j of entering variable*)
{m,n}=Dimensions[tab[[1]]];
(*Creates list of theta ratios*)
thetas={};
For[i=2,i<=m-1,i++,
If[tab[[1,i,j+1]]>0,
thetas=Join[thetas,{{i,tab[[1,i,n]]/tab[[1,i,j+1]]}}];
];
If[tab[[1,i,j+1]]<0,
thetas=Join[thetas,{{i,"(unconstrained)"}}];
];
];
(*Output: theta-ratios for current basic variables with respect to entering variable j*)
Return[TableForm[Table[{"θ ratio for",tab[[1,thetas[[i,1]],1]],":",thetas[[i,2]]},{i,1,Length[thetas]}]]];
];