/*This code is an implementation of the work done by Srijian Anil as 
*the B.Tech project at Dhirubhai Ambani Institute of Information and Communication, Technology, under the supervision of  Prof. Manish K. Gupta (www.guptalab.org)
 * contact id : anil_srijan@daiict.ac.in  
 * 		212ruler@gmail.com
 */
 
/*						
 * The code inputs the number of nodes n, and teh file name in which the output is to be stored.
 * For range of values of d, rho and theta, Incidence matrices for all these values is generated and printed.
 * For the Incidence matrix generated of dimensions n*theta, weight of each row is d, and weight of each column is rho.
 */


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Scanner;


public class FRcode {
	
	public static int n;
	public static int d;
	public static int theta;
	public static int rho;
	static boolean check=true;	
	static PrintWriter pw = null ;
	 public static void main(String[] args) throws IOException
	 {
		 System.out.println("Enter the number of nodes, n");
		 Scanner input = new Scanner(System.in);
		 int in = input.nextInt();
		 System.out.println("Enter name of the file to store the output");
		 BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));							
		 String line = stdin.readLine();
		 pw = new PrintWriter(new File("/Users/srijan/Downloads/"+line+".txt"));
		 //pw=new PrintWriter(new File("C://Users/Srijan/Desktop/"+line+".txt"));

 	 
/*	 The code snippet below is for entering all the four parameters	
  
  	BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
	System.out.println("Enter n , d, theta, rho");		 
	String line;		 
	while ((line = stdin.readLine()) != null && lin6
	String[] in = line.split(" ");
	if (in.length == 4) 
	{
	 n = Integer.parseInt(in[0]);
     d = Integer.parseInt(in[1]);
     theta = Integer.parseInt(in[2]);
     rho = Integer.parseInt(in[3]);
	 }				 	
	 else 
		System.out.println("Please enter all four values");			 
 	}
*/
		 
		 int[][] FRmatrix = new int[n][theta];
			if(n*d != theta*rho) 
			{
				System.out.println("Please follow n*d==theta*rho");
			}
			else
		     {
		    	 for(n=0;n<in+1;n++)
		    	 {
		    		 System.out.println("n= "+n);
		    		 pw.println("n= "+n);
		    		 for(rho=2;rho<n+1;rho++)
		    		 {
		    			 for(d=1;d<n;d++)
		    			 {	 
		    			 if((n*d)%rho==0)
		    			 {
		    				theta=(n*d)/rho;
		    				System.out.println("\n");		    																										// Printing on 
		    				System.out.println("n= "+n+",  d= "+d+", theta= "+theta+", rho= "+rho+"\n");	//    console
		    				
		    				pw.println("\n");																													//  Writing in the
		    				pw.println("n= "+n+",  d= "+d+", theta= "+theta+", rho= "+rho+"\n");		//   file
		    				
		    				FRmatrix =  generator();	    					        // Calling the generator method
		    				if(check==true)									// If all conditions are satisfied
		    					PrintMatrix(FRmatrix);							// print the matrix
		    				else																						// If not print error	
		    					{
		    						System.out.println("\n\n\n\n\n\n-------------------Error---------------------------\n\n\n\n\n");
		    					}	    			
		    			 }			
		    			 }
		    			 System.out.println("\n");
		    			 pw.println("\n");
		    		 }	  
		    	 
		     }
		     }
			pw.close();												//	Closing the file writer
	 }

	 
//-----------------------------------------------------PrintMatrix method prints the matrix----------------------------------------------------//

	private static void PrintMatrix(int[][] rmatrix) {
		
		int i=0,j=0,a=0;
		for(i=0;i<n;i++)
		{	for(j=0;j<theta;j++)
				{
				System.out.print(rmatrix[i][j]+" ");
				pw.print(rmatrix[i][j]);
				}
		System.out.print("\n");
		pw.println("");
		}
	}

//----------------------------------------------------generator method generates the matrix----------------------------------------------------//

	private static int[][] generator() {
	
		int i,j,flag=0,a=0,fill=0,temp = 0,mem=0,k=0,p=0,c=0;
		int[] row = new int[n];													 	
		int[] colm = new int[theta];
		int[] rcnt = new int[n];
		int[] ccnt = new int[theta]; 
		int[][] matrix = new int[n][theta];
/*
  i is for iteration of the rows
  j is for iteration of the columns
  flag is to hold the minimum column weight
  fill is to check row if first element is being filled or not
  temp is the value of the column form which the row iteration has to be started again
  mem stores the value of the column in which first 1 was filled, in previous iteration
  a holds the row index for which coinciding 1 is present in the same column
  k is for iteration for columns from the current column till the end
  p checks for when to increase flag, or the minimum weight of all the columns
  c checks for whether matrix has comparable values of d and rho with n and theta
  
  int[]row stores the weight of each row
  int[]column stores the weight of each column 
  rcnt and ccnt are arrays to check whether each element of []row and []column are equal to d and rho respectively 
  int[][] matrix is the Incidence matrix to be generated
*/		
		for(i=0;i<n;i++)
		{			
			for(j=temp;j<theta;j++)
			{
/*If n==theta and for comparable values of d and n i.e d>n/2, follow the cyclic shift approach for generating the matrix. This is done so as to reduce the complexity.
*/
				if(n==theta && d>n/2)
				{				
					c=1;							//Sets the check =1, that the cyclic shift method is to be followed.
					if(fill==0)						// First element of the iteration being filled, 
					{																		
						mem=temp;					//	mem stores the current column value		
						fill=1;
					}
					else if (colm[j]<rho)
					{
						fill=1;
						matrix[i][j]=1;					// Other than the first element is filled, 
						row[i]++;
						colm[j]++;
						if(row[i]==d)
							break;						
					}
					else
					{
						continue;
					}
				}
/* For all other values */	
		
				else if(colm[j]<rho && fill==0)					// The first element of the iteration is to be filled
				
				{					
					if(matrix[i][j]==1)
					{														
						continue;					// If element already present, continue
					}
					fill=1;
					mem=j;
					matrix[i][j]=1;
					row[i]++;
					colm[j]++;
					for(a=0;a<i;a++)					// Find the row with which 1 is coinciding in the filled column		
					{
						if(matrix[a][j]==1)
							break;
					}
					p=0;
					for(k=j+1;k<theta;k++)					//Finds the column with minimum weight, accordingly increment flag
					{
						if(colm[k]<=flag && matrix[a][j]!=1)
						{
							p=1;
							break;
						}
						if(colm[k]<=flag && matrix[a][j]==1 )
						{
							p=2;
						}						
					}
					if(p==0)														
						{
						flag++;						// No column with minimum weight equals the flag value, increment flag
						}
					if(p==1)
					{
						System.out.println("I was called");
					}
					continue;
				}
				
				else if(fill==1)						// Other than first element is being filled
				{
					if(colm[j]>=rho || row[i]>=d)				// If values of the column and row are already full
					{
						break;
					}
					if(matrix[i][j]==1)					// If element already 1, continue	
					{
						continue;						
					}
					if(colm[j]==flag)											
					{	
						if(matrix[a][j]==0)			        //checks if the column has a coinciding 1 with the row stored in a 												
						{
						matrix[i][j]=1;
						colm[j]++;
						row[i]++;
						if(flag>0)
							a++;
						if(row[i]==d)
							break;
						else
							continue;
						}
						else if(p==2)				 	// for p=2, the minimum weight column exists, 
						{					 	//	but not satisfying the coinciding 1 clause,	
							matrix[i][j]=1;			 	// Fill all these columns having minimum weight		 											  			//    so weight of all the columns are matched evenly	
							colm[j]++;
							row[i]++;							
							if(row[i]==d)
								{
								p=3;	
								break;
								}
							else 
								continue;							
						}						
					}
					else
					{
						continue;
					}					
				}				
			}									//closing the inner loop for column iterations	
			fill=0;	
			if(c==1)								// Check if the case is n==theta, d>n/2 
			{
				if(row[i]<d || temp>=theta)					// Check if row weight and column weights are satisfied
 				{
					fill=1;
					i=i-1;
					temp=0;
				}
				else
				{
					fill=0;
					temp=mem+1;
					if(temp>=theta)
						temp=0;					
				}
			}
			else if(row[i]<d)							// Checks if the row has been fully filled, 
			{
				temp=mem+1;							//If not start the iteration again for the same row
				i=i-1;								// for the column next to the first column of the previous iteration	
			}
			else
			{
				temp=0;								// If row has been filled with d 1's, start again from column 0
			}
		}										//closing the outer loop for row iterations
 
/* Now checking whether all columns and rows have rho and d 1's respectively */	
	
		for(i=0;i<n;i++)
		{
			for(j=0;j<theta;j++)
			{
				if(matrix[i][j]==1)
					{
					rcnt[i]++;
					ccnt[j]++;
					}					
			}
			if(rcnt[i]!=d)
			{
				check=false;
				break;
			}		
		}		
		for(j=0;i<theta;i++)
		{
				if(ccnt[j]==rho)
				{
					continue;
				}
				else
				{
				check=false;
				break;
				}
		}

			
		return matrix;									// return the generated incidence matrix
	}
}
