*/
final int Ap[]=config.getGdScoreComputation() == GDScoreComputationEnum.GD_RH?new int[pairsNumber+1]:null;
final int Ap_threadStart[]=new int[ThreadNumber+1];for(int i=0;i<Ap_threadStart.length;++i) Ap_threadStart[i]=-1;
// one array per thread.
final IntArrayList Ai_array[]=new IntArrayList[ThreadNumber];
final DoubleArrayList Ax_array[]=new DoubleArrayList[ThreadNumber];
final double b[] =new double[pairsNumber];
final int currentPosition[]=new int[ThreadNumber];// stores the last used index in the Ai and Ax arrays.
final double k = config.getAttenuationK();
// We need next to no locking since state pairs considered are disjoint and work arrays are split between threads.
List<HandleRow<List<CmpVertex>>> handlerList = new LinkedList<HandleRow<List<CmpVertex>>>();
for(int threadCnt=0;threadCnt<ThreadNumber;++threadCnt)
handlerList.add(new HandleRow<List<CmpVertex>>()
{
IntArrayList tmpAi = null;
/** Used to detect non-consecutive state pair numbers - in this case an internal error should be reported. */
int prevStatePairNumber =-1;
final int debugThread = -1;
DetermineDiagonalAndRightHandSideInterface ddrhInstance = null;
@Override
public void init(int threadNo)
{
// instances of ddrh are stateful, hence we need one per thread.
if (ddrh == null) ddrhInstance = new DDRH_default();
else
try {// from http://forums.sun.com/thread.jspa?threadID=767974
ddrhInstance = ddrh.getDeclaredConstructor(new Class[]{GDLearnerGraph.class}).newInstance(new Object[] { GDLearnerGraph.this });
} catch (Exception e) {
Helper.throwUnchecked("failed to create an instance of ddrh", e);
}
if (config.getGdScoreComputation() == GDScoreComputationEnum.GD_RH)
{// since we need 'em, allocate the arrays.
tmpAi = new IntArrayList(getExpectedIncomingPerPairOfStates()*pairsNumber);
Ai_array[threadNo]=new IntArrayList(expectedMatrixSize/ThreadNumber+getExpectedIncomingPerPairOfStates());
Ax_array[threadNo]=new DoubleArrayList(expectedMatrixSize/ThreadNumber+getExpectedIncomingPerPairOfStates());
}
currentPosition[threadNo]=0;
}
Set<Integer> sourceData = new TreeSet<Integer>();
@Override
public void handleEntry(Entry<CmpVertex, Map<Label, List<CmpVertex>>> entryA, int threadNo)
{
IntArrayList Ai = Ai_array[threadNo];
DoubleArrayList Ax = Ax_array[threadNo];
Collection<Entry<Label,List<CmpVertex>>> rowA_collection = matrixInverse.transitionMatrix.get(entryA.getKey()).entrySet();
// Now iterate through states
Iterator<Entry<CmpVertex,Map<Label,List<CmpVertex>>>> stateB_It = matrixInverse.transitionMatrix.entrySet().iterator();
while(stateB_It.hasNext())
{
Entry<CmpVertex,Map<Label,List<CmpVertex>>> stateB = stateB_It.next();
Map<Label,List<CmpVertex>> rowB = stateB.getValue();
// At this point, we consider a pair of states (entryA.getKey(),stateB),
// by iterating through inputs associated with incoming transitions and
// attempting to check if there is a match.
int currentStatePair = incompatiblePairs[vertexToIntNR(stateB.getKey(),entryA.getKey())];// the order
// of arguments is important:
// we have to iterate such that each thread has a continuous sequence of state pair numbers
// (and these numbers are never shared between threads).
if (currentStatePair >= 0)
{// this state pair is not an outright reject - if it is, we do not need to fill in b[currentStatePair]
// and not even go through the column because entries in the column reflect the contribution of the
// compatibility of this pair to the compatibility of state pairs leading to currentStatePair.
// Since currentStatePair is a reject, all pairs leading to it should be labelled rejects too
// (this is the task of findIncompatiblePairs() ) and thus we do not need to consider this pair at all.
// Now we check that we go through the sequence of pairs without missing any;
// a failure at this point means that we are now going through pairs in a different order
// than when findIncompatiblePairs did when building incompatiblePairs.
assert prevStatePairNumber < 0 || currentStatePair == prevStatePairNumber+1;prevStatePairNumber=currentStatePair;
if (Ap_threadStart[threadNo] < 0) Ap_threadStart[threadNo]=currentStatePair;
if (debugThread == threadNo) System.out.println("thread "+threadNo+" is considering states: ("+entryA+","+stateB+"), with state pair number "+currentStatePair);
int colEntriesNumber=0;
ddrhInstance.compute(entryA.getKey(),stateB.getKey(), entryA.getValue(),matrixForward.transitionMatrix.get(stateB.getKey()));
b[currentStatePair]=ddrhInstance.getRightHandSide();
if (debugThread == threadNo) System.out.println("shared outgoing: "+ddrhInstance.getRightHandSide());
if (config.getGdScoreComputation() == GDScoreComputationEnum.GD_RH)
{// if score computation is GD_DIRECT, no matrix will be filled in.
tmpAi.setQuick(colEntriesNumber++, currentStatePair);// we definitely need a diagonal element, hence add it.
for(Entry<Label,List<CmpVertex>> outLabel:rowA_collection)
{
List<CmpVertex> to = rowB.get(outLabel.getKey());
if (to != null)
{// matched pair of transitions, now we need to build a cross-product
// of the states leading to the current pair of states, that is,
// to (entryA.getKey(),stateB)
sourceData.clear();
int maxSize = colEntriesNumber+outLabel.getValue().size()*to.size();
if (tmpAi.elements().length < maxSize)
{
if (linearWarningsEnabled )
System.out.println("buildMatrix: warning - resizing arrays tmpAi[thread "+threadNo+"] from "+tmpAi.elements().length+" to "+maxSize);
tmpAi.ensureCapacity(maxSize);
}
if (debugThread == threadNo) System.out.println("matched "+outLabel.getKey());
for(CmpVertex srcA:outLabel.getValue())
for(CmpVertex srcB:to)
{
// It is possible that for the same inputs (srcA,srcB)=(A,B) and (B,A)
// in this case, we have to avoid including (B,A) in the list, but
// it is not known in advance if any such case occurs, so we have to store
// the pairs we encountered and eliminate them.
int sourcePair = incompatiblePairs[vertexToIntNR(srcB, srcA)];
// If sourcePair <0, it means that we are attempting to add an entry for a
// row we've already discarded as incompatible, hence ignore this entry.
if (sourcePair >= 0 && !sourceData.contains(sourcePair))
{
sourceData.add(sourcePair);
if (debugThread == threadNo) System.out.println(outLabel.getKey()+" : "+srcB+","+srcA);
tmpAi.setQuick(colEntriesNumber++,sourcePair);
}
}
}
}
// At this point, we populated Ai and b with elements for the current row (number currentStatePair),
// so it is time to sort these entries. There is no need to populate Ax right now:
// all we care about is the state pairs from which there have been transitions leading to the
// current state (and a diagonal element).
cern.colt.Sorting.quickSort(tmpAi.elements(),0, colEntriesNumber,new cern.colt.function.IntComparator() {
@Override public int compare(int o1, int o2) { return o1-o2; }});
if (debugThread == threadNo) { for(int i=0;i< colEntriesNumber;++i) System.out.print(tmpAi.getQuick(i)+" ");System.out.println(); }
// Now we have to copy the result to the target array.
int pos = currentPosition[threadNo]-1;// the position where to start writing into Ai and Ax, minus 1 since it will be incremented when we find the our new value is above prev (below).
Ap[currentStatePair]=pos+1;// Ap maps each state pair to the corresponding position in Ai and Ax. We record here the first index (in Ai) of the current column
int prev = -1;
boolean diagonalSet = false;
// Check if we have the capacity in the arrays for this column - in an ugly way,
// but resizing for each element as per Ax.add seems ridiculous.
int expectedMaxSize = pos+colEntriesNumber+1;
if (Ax.elements().length < expectedMaxSize)
{
if (linearWarningsEnabled && config.getDebugMode())
System.out.println("buildMatrix: warning - resizing arrays Ax[thread "+threadNo+"] and Ai[thread "+threadNo+"] from "+Ax.elements().length+" to "+expectedMaxSize);
Ax.ensureCapacity(expectedMaxSize);
Ai.ensureCapacity(expectedMaxSize);
}
for(int i=0;i<colEntriesNumber;++i)
{
int currentValue = tmpAi.getQuick(i);
if(currentValue!=prev)
{
prev=currentValue;++pos;
if (!diagonalSet && currentValue == currentStatePair)
{// this is the time to handle a diagonal. When this condition becomes true,
// currentValue == currentStatePair for the first time.
double rightHandSide = ddrhInstance.getDiagonal();
if (rightHandSide == 0)
rightHandSide = 1; // if neither element of a pair of states has an outgoing transition, force the identity to ensure that the solution will be zero.
if (debugThread == threadNo) System.out.println("setting diagonal to "+rightHandSide);
Ax.setQuick(pos,rightHandSide);
Ai.setQuick(pos,prev);
diagonalSet = true;
// Now that we've added a diagonal, skip to the next element (we always add an entry for a diagonal, hence we have to "eat" it here.
}
else
{// new value but not a diagonal.
Ax.setQuick(pos,-k);
Ai.setQuick(pos,prev);
}
}
else Ax.setQuick(pos,Ax.getQuick(pos)-k);
}
++pos;
if (debugThread == threadNo) { System.out.println("thread "+threadNo+" results:");for(int i=currentPosition[threadNo];i<pos;++i) System.out.println(i+ ": "+Ai.getQuick(i)+ " , "+Ax.getQuick(i)); }
currentPosition[threadNo]=pos;
}// if (config.getGdScoreComputation() == GDScoreComputationEnum.GD_RH)
}// if (incompatiblePairs[currentStatePair] != PAIR_INCOMPATIBLE)
if (stateB.getKey().equals(entryA.getKey())) break; // we only process a triangular subset.