My first answer was not really adequate. Here is another way, related and also heuristic, but I think more likely to succeed. We again get the Hermite form (HNF). We use a bit if integer programming to get an integer combination from these that is nonnegative and furthermore strictly positive in all columns that do not have pivots in the HNF. For code purposes I take a shortcut here and also omit finding the transformation matrix, and furthermore assume there are no zero columns. All these simplifications are easy to redress.
We form this nonnegative vector with the added stipulation that the first vector in the HNF is multiplied by 1. This will allow us to enforce the condition that the conversion matrix be invertible over the integers. The heuristic part is that I have no proof this can always be done. (So maybe it's obvious, maybe it's wrong...) Were it to fail one could of course use a different basis vector from the HNF, but again, I don't know if one can always get a positive vector in this way.
With this vector we can form a full basis that is nonnegative. I'll illustrate with an example.
First I start with a set of random linearly independent nonnegative integer vectors.
SeedRandom[111123];
nvecs = 7;
dim = 12;
randPosVecs = RandomInteger[{0, 10}, {nvecs, dim}];
MatrixRank[posvecs] == nvecs
(* Out[1096]= True *)
I use a utility to create a "random" unimodular matrix by multiplying an upper triangular matrix with ones on the main diagonal with a lower triangular matrix similarly constructed.
randUnimodularMatrix[n_] := Module[
{top, bot, bands},
top = IdentityMatrix[n] +
SparseArray[
Table[Band[{1, j}] -> RandomInteger[{-10, 10}, n - j + 1], {j, 2,
n}], {n, n}];
bot = IdentityMatrix[n] +
SparseArray[
Table[Band[{j, 1}] -> RandomInteger[{-10, 10}, n - j + 1], {j, 2,
n}], {n, n}];
top . bot]
We'll create one and check unimodularity.
randuni = randUnimodularMatrix[nvecs];
Det[randuni]
(* Out[1098]= 1 *)
Now we apply this to our nonnegative basis.
vecs = randuni . randPosVecs
(* Out[1110]= {{-28, -207, -276, -359, -53, -192, -446, -374, -252, \
-377, -243, -178}, {274, -54, 242, 297, 253, 285, 321, 495, 96, 415,
795, 276}, {29, -293, -302, -461, -265, -380, -621, -754, -102, \
-587, -426, -516}, {42, -450, -464, -679, -302, -493, -913, -905, \
-248, -741, -433, -617}, {279, 114, 193, -374, -55, 113, -334, -648,
192, -361, -749, -197}, {-35, -89, -98, -32, -30, -88, -73, -18, \
-69, -44, 78, -54}, {3, 84, 81, 72, 36, 80, 111, 90, 51, 86, -7, 79}} *)
So we have a mix of positive and negative values. Furthermore the HNF is not all nonnegstive. We will use it to create a new basis though.
newvecs = HermiteDecomposition[vecs][[2]]
(* Out[1111]= {{1, 0, 0, 0, 0, 0, 6681, 10707, -9738, 8753, 14524,
8735}, {0, 1, 0, 0, 0, 0, 19558, 31395, -28519, 25667, 42568,
25591}, {0, 0, 1, 0, 0, 0, 13724, 22079, -20023, 18053, 29923,
17976}, {0, 0, 0, 1, 0, 0, 13508, 21689, -19697, 17732, 29407,
17676}, {0, 0, 0, 0, 1, 0, 20948, 33657, -30554, 27517, 45627,
27422}, {0, 0, 0, 0, 0, 1, 15135, 24311, -22073, 19876, 32959,
19810}, {0, 0, 0, 0, 0, 0, 22488, 36125, -32798, 29535, 48975,
29435}} *)
Here is the ILP step where we create a vector that is noonnegative, with strictly positive values in all non-pivot columns.
tvars = Array[t, nvecs];
t[1] = 1;
posvec = tvars . newvecs;
ptot = Total[posvec];
{min, vals} =
Minimize[{ptot,
Join[Thread[posvec >= 0],
Thread[posvec[[Length[newvecs] + 1 ;;]] >= 1]]}, Rest@tvars,
Integers];
tvals = tvars /. vals;
posvec = tvals . newvecs
(* Out[1125]= {1, 3, 4, 9, 11, 0, 3, 11, 4, 6, 5, 3} *)
Now we create a full basis. I add appropriate multiples of posvec
to the second through last vector in newvecs
, which we know is a basis set. I use posvec
itself for the first basis vector. It is straightforward to show from the construction that this is in fact a basis set, that is, comes from an invertible (over the integers) transformation of the original basis.
nnvecs = Table[
vec = newvecs[[j]];
qvec =
Table[If[posvec[[k]] == 0, 0, Floor[vec[[k]]/posvec[[k]]]], {k,
Length[vec]}];
qmin = Min[qvec, 0];
vec - qmin*posvec
, {j, Length[newvecs]}
];
nnvecs[[1]] = posvec;
First check that these are all nonnegative.
Map[MinMax, nnvecs]
(* Out[1081]= {{0, 9}, {1, 13863}, {0, 10558}, {0, 111614}, {0,
36362}, {0, 40519}, {0, 185970}} *)
Next show that this basis comes from an invertible transformation of newvecs
(so all integers and determinant is +-1).
cmat = LinearSolve[Transpose@newvecs, Transpose@nnvecs];
Union[Flatten[Map[IntegerQ, cmat, {2}]]]
Det[cmat]
(* Out[1087]= {True}
Out[1088]= 1 *)
Though this is redundant, we also show that it is a basis for the original vecs
by noting that they have the same HNF.
HermiteDecomposition[nnvecs][[2]] === HermiteDecomposition[newvecs][[2]]
(* Out[1090]= True *)
So the open question is whether this can be made into a guaranteed algorithm.
Also on the unfortunate side is that the result, while a basis, is not going to deliver what I believe are called extremal or elementary fluxes (in reference to the underlying problem, which I believe is to do compoutations with a mass-action chemical reaction network).
xx = Array[x, 5]; FindInstance[{xx . Nm == 0, xx >= 0}, xx, Reals, 3]
. Are those solutions good for your purposes? You could also skip the explicit positivity condition and replace it with thePositiveReals
domain specification. $\endgroup$m = {3, 6, 9, 12};
then you canApply
theGCD
function to that list as follows:GCD @@ m
. That's a general solution to the problem of using functions that accept sequences of arguments on lists. $\endgroup$