最大値

n次元分割表を考える。その分割表は総数が1となるようにセルの値を標準化してあるものとする。
2次元の分割表NxM (N<=M)において、カイ自乗値の最大値は、N-1であって、それは、表の列と行を適当に入れ替えることによって、N個の非ゼロの対角成分を持つNxNの正方行列部分と、Nx(M-N)の長方形行列部分にすることができて、しかも、このNx(M-N)の長方形行列部分は、NxN正方行列が作れるまでは、そのような正方行列にして、そこには対角成分のみがあるようにして、残りのNxM'(M'<=N)なる長方形成分を残したときに、そこは、M'個の対角成分のみが非ゼロで、残りはすべてゼロであるようにできる、そんな分割表のときである。
n次元に拡張する。次のような特殊なサイズとする。
NxNx...xNxM M>=Nなる多次元分割表(すべての次元の長さが等しいか、そうでないならば、ただ一つの次元のみがことなり、その長さは、他の次元より長い)。
カイ自乗値の「おばけ変形」のような値を定義することによって、この値の最大値も2次元におけるカイ自乗値のように、N-1をとらせることができる。
ソースメモ。

public class cubeChi2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//int df=3;
		int[] category={5,34};
		double[] data=MakeData(category);
		for(int i=0;i<data.length;i++){
			System.out.println(data[i]);
		}
		double chi=Chi(data,category);
		double chiR=ChiR(data,category);
		double chiR2=ChiR2(data,category);
		System.out.println("chi\t"+chi);
		System.out.println("chiR\t"+chiR);//おばけその1
		System.out.println("chiR2\t"+chiR2);//おばけその2

	}

	public static double ChiR(double[] data, int[] category){
		double ret =-1;
		int max=category[0];
		for(int i=1;i<category.length;i++){
			if(max<category[i]){
				max=category[i];
			}
		}
		double dim=category.length;
		//double dim = (double)max;
		double[][] marg=new double[category.length][0];
		for(int i=0;i<marg.length;i++){
			marg[i]=new double[category[i]];
		}
		int[] counter=new int[category.length];
		for(int i=0;i<data.length;i++){
			for(int j=0;j<category.length;j++){
				marg[j][counter[j]]+=data[i];
			}
			counter[0]++;
			for(int j=0;j<category.length-1;j++){
				if(counter[j]==category[j]){
					counter[j]=0;
					counter[j+1]++;
				}
			}
		}
		counter=new int[category.length];
		
		for(int i=0;i<data.length;i++){
			double value=1;
			for(int j=0;j<category.length;j++){
				value*=marg[j][counter[j]];
				
			}
			ret+=Math.pow(data[i], dim/(dim-1))/Math.pow(value,1/(dim-1));
			//ret+=(data[i]-value)*(data[i]-value)/value;
			counter[0]++;
			for(int j=0;j<category.length-1;j++){
				if(counter[j]==category[j]){
					counter[j]=0;
					counter[j+1]++;
				}
			}
		}
		/*
		for(int i=0;i<marg.length;i++){
			//double tmpsum=0;
			for(int j=0;j<marg[i].length;j++){
				System.out.print(marg[i][j]+"\t");
				//tmpsum+=marg[i][j];
			}
			//System.out.print(tmpsum);
			System.out.println();
		}
		*/
		return ret;
	}
	public static double[] MakeData(int[] category){
		int n=1;
		int N=1;
		int max=0;
		for(int i=1;i<category.length;i++){
			if(category[max]<category[i]){
				max=i;
			}
		}
		//System.out.println("max "+max);
		for(int i=0;i<category.length;i++){
			n*=category[i];
			N*=category[max];
		}
		//System.out.println("n="+n+"\t N="+N);
		double[] ret = new double[n];
		int[] counter=new int[category.length];
		for(int i=0;i<n;i++){
			
		}
		int[] keta=new int[category.length];
		keta[0]=1;
		for(int i=1;i<keta.length;i++){
			keta[i]=keta[i-1]*category[i-1];
			//System.out.println("keta "+i+" "+keta[i]);
		}
		int value=0;
		double sum=0;
		boolean loop=true;
		while(loop){
			
			value=0;
			for(int j=0;j<counter.length;j++){
				value+=keta[j]*counter[j];
			}
			//System.out.println("value\t"+value);
			//for(int j=0;j<counter.length;j++){
				//System.out.print(counter[j]+"\t");
			//}
			//System.out.println();
			if(value<n){
				ret[value]=Math.random();
				sum+=ret[value];
			}
			for(int j=0;j<counter.length;j++){
				counter[j]++;
			}
			value=0;
			if(counter[max]==category[max]){
				loop=false;
			}
			
			for(int j=0;j<counter.length;j++){
				if(counter[j]==category[j]){
					counter[j]=0;
				}
				/*
				else{
					counter[j]++;
				}
				*/
			}
			for(int j=0;j<counter.length;j++){
				value+=keta[j]*counter[j];
			}
			
			
			
		}
		for(int i=0;i<ret.length;i++){
			ret[i]/=sum;
		}
		return ret;
	}

	public static double Chi(double[] data, int[] category){
		double ret =0;
		double[][] marg=new double[category.length][0];
		for(int i=0;i<marg.length;i++){
			marg[i]=new double[category[i]];
		}
		int[] counter=new int[category.length];
		for(int i=0;i<data.length;i++){
			for(int j=0;j<category.length;j++){
				marg[j][counter[j]]+=data[i];
			}
			counter[0]++;
			for(int j=0;j<category.length-1;j++){
				if(counter[j]==category[j]){
					counter[j]=0;
					counter[j+1]++;
				}
			}
		}
		counter=new int[category.length];
		
		for(int i=0;i<data.length;i++){
			double value=1;
			for(int j=0;j<category.length;j++){
				value*=marg[j][counter[j]];
				
			}
			ret+=(data[i]-value)*(data[i]-value)/value;
			counter[0]++;
			for(int j=0;j<category.length-1;j++){
				if(counter[j]==category[j]){
					counter[j]=0;
					counter[j+1]++;
				}
			}
		}
		/*
		for(int i=0;i<marg.length;i++){
			//double tmpsum=0;
			for(int j=0;j<marg[i].length;j++){
				System.out.print(marg[i][j]+"\t");
				//tmpsum+=marg[i][j];
			}
			//System.out.print(tmpsum);
			System.out.println();
		}
		*/
		return ret;
	}

	public static double ChiR2(double[] data, int[] category){
		double ret =-1;
		int max=category[0];
		for(int i=1;i<category.length;i++){
			if(max<category[i]){
				max=category[i];
			}
		}
		double dim=category.length;
		//double dim = (double)max;
		double[][] marg=new double[category.length][0];
		for(int i=0;i<marg.length;i++){
			marg[i]=new double[category[i]];
		}
		int[] counter=new int[category.length];
		for(int i=0;i<data.length;i++){
			for(int j=0;j<category.length;j++){
				marg[j][counter[j]]+=data[i];
			}
			counter[0]++;
			for(int j=0;j<category.length-1;j++){
				if(counter[j]==category[j]){
					counter[j]=0;
					counter[j+1]++;
				}
			}
		}
		counter=new int[category.length];
		
		for(int i=0;i<data.length;i++){
			double value=1;
			for(int j=0;j<category.length;j++){
				value*=marg[j][counter[j]];
				
			}
			//ret+=Math.pow(data[i], dim/(dim-1))/Math.pow(value,1/(dim-1));
			ret+=Math.pow(data[i], 1/(dim-1))*Math.pow(value,dim/(dim-1));
			//ret+=(data[i]-value)*(data[i]-value)/value;
			counter[0]++;
			for(int j=0;j<category.length-1;j++){
				if(counter[j]==category[j]){
					counter[j]=0;
					counter[j+1]++;
				}
			}
		}
		/*
		for(int i=0;i<marg.length;i++){
			//double tmpsum=0;
			for(int j=0;j<marg[i].length;j++){
				System.out.print(marg[i][j]+"\t");
				//tmpsum+=marg[i][j];
			}
			//System.out.print(tmpsum);
			System.out.println();
		}
		*/
		return ret;
	}
}