allowedAACharacters = "FLIMVSPTAYHQNKDECWRG";

SetDialogPrompt ("Locate an amino-acid profile matrix file:");
fscanf (PROMPT_FOR_FILE,"String,Matrix",mapString,aaRateMatrix);
W_MATRIX_FILE = LAST_FILE_PATH;

if (Abs(mapString) == 20 && Rows(aaRateMatrix) == 20 && Columns(aaRateMatrix) == 20)
{
	/* check to see that all characters have been mapped */
	checkAAMap   = {}; /* associative array */
	for (aaIndex = 0; aaIndex < 20; aaIndex = aaIndex+1)
	{
		aChar = allowedAACharacters[aaIndex];
		checkAAMap[aChar] = aaIndex+1;
	
	}

	AAMap = {};
	for (aaIndex = 0; aaIndex < 20; aaIndex = aaIndex+1)
	{
		aChar = mapString[aaIndex];
		daIndex = checkAAMap[aChar];
		if (daIndex==0)
		{
			fprintf (stdout, "\nAmino-acid ordering provided in the file is invalid - could be duplicate or missing characters\n");
			return 0;
		}
		else
		{
			if (daIndex>10)
			{
				AAMap[aaIndex] = daIndex;
			}
			else
			{
				AAMap[aaIndex] = daIndex-1;			
			}
			checkAAMap[aChar] = 0;
		}
	}
	
	/*symmetrize the matrix*/
	
	for (aaIndex = 0; aaIndex < 19; aaIndex = aaIndex+1)
	{
		for (aaIndex2 = aaIndex+1; aaIndex2 < 20; aaIndex2 = aaIndex2+1)
		{
			aaRateMatrix[aaIndex2][aaIndex] = aaRateMatrix[aaIndex][aaIndex2];
		}
	}
	
	/* reindex the matrix */
	
	aaRateMultipliers = {21,21};
	aaRateClassIDs    = {};
	
	for (aaIndex = 0; aaIndex < 19; aaIndex = aaIndex+1)
	{
		mappedIndex = AAMap[aaIndex];
		for (aaIndex2 = aaIndex+1; aaIndex2 < 20; aaIndex2 = aaIndex2+1)
		{
			mappedIndex2 								 = AAMap[aaIndex2];
			rateLabel 									 = aaRateMatrix[aaIndex][aaIndex2]$1;
			
			aaRateMultipliers[mappedIndex][mappedIndex2] = rateLabel;
			aaRateMultipliers[mappedIndex2][mappedIndex] = rateLabel;
			
			aaRateClassIDs[rateLabel] = aaRateClassIDs[rateLabel] + 1;
		}
	}
	
	labels   = Rows (aaRateClassIDs);
	aaIndex2 = {Abs (aaRateClassIDs),2};
	
	for (aaIndex = 0; aaIndex < Abs (aaRateClassIDs); aaIndex = aaIndex + 1)
	{
		rateLabel = labels [aaIndex];
		aaIndex2 [aaIndex][0] = rateLabel;
		aaIndex2 [aaIndex][1] = "Rate class '" + rateLabel + "' with " + aaRateClassIDs [rateLabel] + " member pair";
	}
	
	ChoiceList (aaIndex, "Which rate class to constrain?", 1, SKIP_NONE, aaIndex2);
	
	if (aaIndex < 0)
	{
		return 0;
	}
	
	_rateLabelToTest = "nsClass" + aaIndex2[aaIndex][0];
	fprintf (stdout, "Selected ", _rateLabelToTest, "\n");
	aaRateMatrix = 0;	
}
else
{
	fprintf (stdout, "\nExpected a string of 20 characters followed by a 20x20 matrix\n");
	return 0;
}

CodonMatrixB = {ModelMatrixDimension,ModelMatrixDimension};

hshift = 0;

modelDefString = "";
modelDefString*16384;

_nucBiasTerms = {{"","AC__*","","AT__*"}
				 {"AC__*","","CG__*","CT__*"}
				 {"","CG__*","","GT__*"}
				 {"AT__*","CT__*","GT__*",""}};

for (h=0; h<64; h=h+1)
{
	if (_Genetic_Code[h]==10) 
	{
		hshift = hshift+1;
		continue; 
	}
	vshift = hshift;
	for (v = h+1; v<64; v=v+1)
	{
		diff = v-h;
		if (_Genetic_Code[v]==10) 
		{
			vshift = vshift+1;
			continue; 
		}
		nucPosInCodon = 2;
		if ((h$4==v$4)||((diff%4==0)&&(h$16==v$16))||(diff%16==0))
		{
			if (h$4==v$4)
			{
				transition = v%4;
				transition2= h%4;
			}
			else
			{
				if(diff%16==0)
				{
					transition = v$16;
					transition2= h$16;
					nucPosInCodon = 0;
				}
				else
				{
					transition = v%16$4;
					transition2= h%16$4;
					nucPosInCodon = 1;
				}
			}
			hs = Format(h-hshift,0,0);
			vs = Format(v-vshift,0,0);
			ts = Format(transition,0,0);
			ts2= Format(transition2,0,0);
			ps = Format(nucPosInCodon,0,0);
			aa1 = _Genetic_Code[0][h];
			aa2 = _Genetic_Code[0][v];
			if (aa1==aa2) 
			{
				modelDefString*("CodonMatrixB["+hs+"]["+vs+"] := "+_nucBiasTerms[transition][transition2]+"synRate*positionFrequencies__["+ts+"]["+ps+"];\n"+
												 "CodonMatrixB["+vs+"]["+hs+"] := "+_nucBiasTerms[transition][transition2]+"synRate*positionFrequencies__["+ts2+"]["+ps+"];\n");
			}
			else
			{
				bt = "nsClass"+aaRateMultipliers[aa1][aa2];
				modelDefString*("CodonMatrixB["+hs+"]["+vs+"] := "+_nucBiasTerms[transition][transition2]+bt+"*synRate*positionFrequencies__["+ts+"]["+ps+"];\n"+
												 "CodonMatrixB["+vs+"]["+hs+"] := "+_nucBiasTerms[transition][transition2]+bt+"*synRate*positionFrequencies__["+ts2+"]["+ps+"];\n");						
			}
		}
    }
}		
modelDefString*0;
ExecuteCommands (modelDefString);

Model MGModelB	= (CodonMatrixB,codonFrequencies,0);
