/**
 * This class writes English and Picture files
 * for the approximate compilation, derived in
 * Tuc07a- arXiv:0706.0479, for the evolution operator
 * e^{iH_{tree}}, where H_{tree} is proportional to
 * the incidence matrix of a balanced binary tree graph.
 */
public class TreeSEO_writer extends SEO_writer{
	//private String 	_filePrefix;
	//private int 		_numBits;

	
	private int _logLvs; //log of the number of leaves, 
    //called \Gamma in Tuc07.
    //The number of leaves is 1<<_logLvs = 2^_logLvs.
    //The number of nodes (and of states and of rows) is 
    //1<<(_logLvs + 1) = 2^(_logLvs + 1)
    private double 	_strength;
    private int		_numTrots;
    
/**
 *
 */
    public TreeSEO_writer(
        String 	filePrefix,
        int 	numBits,
        double 	strength,
        int 	numTrots)
    {
        super(filePrefix + "_qtree", numBits);
        
         _logLvs = numBits - 1;// _logLvs >= 1
        _strength= strength;
        _numTrots = numTrots;
         
        
    	write();

        closeFiles();

    }
/**
 * 
 */
    public TreeSEO_writer(
    		java.io.PrintWriter  englishOut,
    		java.io.PrintWriter  pictureOut,
    		Boolean doWrite,
    		int numBits,
    		int numBitsInP0Pad,
            double 	strength,
            int 	numTrots)
        {
        	super(englishOut, pictureOut, numBits, numBitsInP0Pad);
 
            _logLvs = numBits - 1;// _logLvs >= 1
            _strength= strength;
            _numTrots = numTrots;

        	if(doWrite){write();}
        }
    
/**
 * 
 */
	public void write(){
		
        int numControls;
        int targetBitPosition;
        int lam, j, b, controlCounter;

        OneBitRot pos90degsRotY =  new OneBitRot(Math.PI/4, OneBitRot.Y_AXIS);
        OneBitRot neg90degsRotY =  new OneBitRot(-Math.PI/4, OneBitRot.Y_AXIS);

        //Part 1: right side, curly F^dagger matrices
        Controls controls = new Controls(_numBits, 1);//just one control
    	for(lam = _logLvs-1; lam>=0 ; lam--){	       	
        	controls.setControl(0, lam+1, true);
	        writeControlledGate(
	        		0,//targetPosition
	        		controls, 
	        		neg90degsRotY);//OneBitGate
	        for(j = 0 ; j<lam; j++){
	        	writeControlledBitSwap(j, j+1, controls);
	        }
        }
       
    	int loopNum = 0;
    	if(_numTrots>1){
    		loopNum = getLineCount();
    		writeLOOP(loopNum, _numTrots);
    	}
        
        //Part 2: Gamma matrices
        
        //numStrands = number of strands. 
        //0<= strand < numStrands
        int numStrands = 1<<(_logLvs - 1);
        //for logLvs = 5, strand classes 0, 1, 2, 4, 8
        //Classes are labelled by their first strand
        //Strand classes in general: 0, 1, 2, 4, 2^(_logLvs -2)

        int strand  = 0;
        int log2Strand = 0;
        Nautilus naut;
        int numCompartments;
        while(strand<numStrands){
        	int lamMinStrand = lamMin(strand);
        	int deltaLam = 0;
            for(lam=_logLvs; lam>=lamMinStrand; lam--){
            	numCompartments = lam - lamMinStrand;
            	naut = new Nautilus(_numTrots>1?_strength/_numTrots:_strength, 
            			numCompartments, deltaLam);
            	//commenting the next statement makes lamIsMax always true
            	//taking away the g^3 correction
            	deltaLam++;
            	
                //right side
            	for(j=numCompartments -1; j>=0; j--){
                    numControls = j+1;
                    controls = new Controls(_numBits, numControls);
                    controlCounter=0;
                    for(b=lam; b>= lam-j; b--){
                        controls.setControl(controlCounter, b, false);
                        controlCounter++;
                    }
                    targetBitPosition = lam - j -1;
                    writeControlledGate(
                        targetBitPosition, 
                        controls, 
                        new OneBitRot(naut.getTheta(numCompartments -j), 
                        		OneBitRot.X_AXIS));
                    
                }//end of right side

                //middle
                numControls = _logLvs - log2Strand;
                controls = new Controls(_numBits, numControls);
                controlCounter=0;
                for(b=_logLvs; b> lam; b--){
                    controls.setControl(controlCounter, b, false);
                    controlCounter++;
                }
                targetBitPosition = lam;
                for(b=lam-1; b>=0; b--){
                    controls.setControl(controlCounter, b, 
                        ((strand>>b)&1)!=1);
                    controlCounter++;
                    if(controlCounter==numControls)break;
                }
                writeControlledGate(
                    targetBitPosition, 
                    controls, 
                    new OneBitRot(naut.getRho(numCompartments), 
                    		OneBitRot.X_AXIS));
                
                //left side
                for(j=0; j<numCompartments; j++){
                    numControls = j+1;
                    controls = new Controls(_numBits, numControls);
                    controlCounter=0;
                    for(b=lam; b>= lam-j; b--){
                        controls.setControl(controlCounter, b, false);
                        controlCounter++;
                    }
                    targetBitPosition = lam - j -1;
                    writeControlledGate(
                        targetBitPosition, 
                        controls, 
                        new OneBitRot(-naut.getTheta(numCompartments - j), 
                        		OneBitRot.X_AXIS));
                }//end of left side

                

            }//lam loop
            if(strand==0){
                strand = 1;
            }else{
                strand = strand<<1;
            }
            if(strand>1){log2Strand++;}
        }//strand loop

        if(_numTrots>1){writeNEXT(loopNum);}
        
        //Part 3: left side, curly F matrices
        controls = new Controls(_numBits, 1);//just one control
        for(lam = 0; lam< _logLvs; lam++){
	       	controls.setControl(0, lam+1, true);
	        for(j = lam-1 ; j>=0; j--){
	        	writeControlledBitSwap(j, j+1, controls);     	
	        }
	        writeControlledGate(
	        		0,//targetPosition
	        		controls, 
	        		pos90degsRotY);//OneBitGate
        }

		
		
		
		
	}

/**
 * lamMin = lambda minimum
 */
    
    public static int lamMin(int strand){
        return (int)Math.ceil(Globals.log2(strand + 1)) + 1;
    }
/**
 *
 */    
    public static void main(String[] args){
        
        new TreeSEO_writer(
            "test",// filePrefix,
            2, //numBits,
            .3, //strength
            0//numTrots
            );
           
        
    }   
    
}
