I have several suggestions:
1. You can use the IIS= option in the SOLVE WITH LP statement to identify an irreducible infeasible set. For your problem, this will likely return a cycle, as you suspected.
2. You can use the CYCLE= option in the SOLVE WITH NETWORK statement to find a cycle.
For suggestions 1 and 2, you can report the source of infeasibility to the data preparer to correct. But even after correction, there might be another cycle.
3. You can use the CYCLE= option in the SOLVE WITH NETWORK statement to find all cycles (MAXCYCLES=ALL). Then report them all to the data preparer to correct.
4. You can use the MILP solver to find a minimum set of arcs whose removal will eliminate all cycles. To do this, you could introduce a binary variable IsRemoved[i,j] for each arc <i,j>, do step 3 to find all cycles, impose a "cover" constraint sum {<i,j> in ARCS_cycle[c]} IsRemoved[i,j] >= 1 that forces at least one arc to be removed from each cycle, and minimize sum {<i,j> in prec} IsRemoved[i,j]. Then remove the arcs for which IsRemoved[i,j] > 0.5 (a safe comparison for = 1) and proceed with the LP solve.
5. You can introduce a slack variable to measure constraint violation, minimize the sum of slacks, impose an objective cut, and solve again with the original objective:
var slack{prec} >= 0;
min infeasibility = sum {<i,j> in prec} slack[i,j];
con ptime{<i,j> in prec}:
s[i] + duration[i] <= s[j] + slack[i,j];
solve;
num mininfeasibility;
mininfeasibility = infeasibility.sol;
con objectivecut:
infeasibility <= mininfeasibility;
solve obj objective;
By the way, a cycle for which all durations are 0 is fine. It just means that those activities must all happen at the same time.
... View more