package jp.ac.takushoku_u.cs;

/**
* SPTableクラスはS-P表作成を行うクラスです。
* @version 1.1.2
* @author 笠島 裕史(Kasajima Hiroshi)
*/
/*
* 最終更新日 2005年01月18日
*/
public class SPTable{
	
/**
* SP表を作成する前のデータを保持するマトリクス。
*/
	private ArithmeticMatrix matrix;
	
/**
* 並べ替えた後、その行は元は何行目であったか行番号を保持する配列。
*/
	private int[] baseRow;
	
/**
* 並べ替えた後、その列は元は何列目であったか列番号を保持する配列。
*/
	private int[] baseCol;
	
/** 
* 注意マーク表示用の定数で、注意マークを出力する正答率の判定の値。
*/
	private static final double SPTABLE_CAUTION_MARK_SCORE_AVERAGE1 = 0.85;
	
/**
* 注意マーク表示用の定数で、注意マーク``!''を出力しなければならない注意係数値を表す。
*/
	private static final double SPTABLE_CAUTION_MARK_CAUTION_VALUE1 = 0.5;
	
/**
* 注意マーク表示用の定数で、注意マーク``!!''を出力しなければならない注意係数値を表す。
*/
	private static final double SPTABLE_CAUTION_MARK_CAUTION_VALUE2 = 0.75;
	
/**
* 注意マークの表示なしを示す定数を表す。
*/
	private static final int SPTABLE_CAUTION_MARK_NON = 0;
	
/**
* 注意マークの表示なしを表す。
*/
	private static final String SPTABLE_CAUTION_MARK_NONSTRING = "";
	
/**
* 注意マーク``!''を示す定数を表す。
*/
	private static final int SPTABLE_CAUTION_MARK_ONE = 1;
	
/**
* 注意マーク``!''表示を表す。
*/
	private static final String SPTABLE_CAUTION_MARK_ONESTRING = "!";
	
/**
* 注意マーク''!!``を示す定数を表す。
*/
	private static final int SPTABLE_CAUTION_MARK_TWO = 2;
	
/**
* 注意マーク''!!``表示を表す。
*/
	private static final String SPTABLE_CAUTION_MARK_TWOSTRING = "!!";
	
/**
* マトリクスサイズのデフォルト値。
*/
	private static final int SPTABLE_MATRIX_VALUE = 5;
	
	
/**
* 設定されているデフォルトのサイズで分析を行うマトリクスを設定し、分析を行います。<BR>
* マトリクスの要素は全て0となります。
*/
	public SPTable(){
		ArithmeticMatrix baseMatrix = new ArithmeticMatrix(SPTABLE_MATRIX_VALUE, SPTABLE_MATRIX_VALUE);
		setSPMatrix(baseMatrix);
	}
	
/**
* S-P表を作成するマトリクスを設定し分析を行います。
* @param baseMatrix SP表を作成するマトリクス
*/
	public SPTable(ArithmeticMatrix baseMatrix){
		setSPMatrix(baseMatrix);
	}
	
/**
* S-P表を作成するマトリクスを設定し分析を行います。
* @param baseMatrix SP表を作成するマトリクス
*/
	public SPTable(BooleanMatrix baseMatrix){
		setSPMatrix(baseMatrix.toArithmeticMatrix());
	}
	
/**
* S-P表を返します。
* @return S-P表
* @see #getSPFullMatrix()
*/
	public ArithmeticMatrix getSPMatrix(){
		baseRow = arrangeArray(matrix.getRowSumArray());
		baseCol = arrangeArray(matrix.getColSumArray());
		
		ArithmeticMatrix changeMatrix = new ArithmeticMatrix();
		changeMatrix.matrixCopy(matrix);
		changeMatrix.matrixCopy(getStudentChangeMatrix(matrix, baseRow));
		changeMatrix.matrixCopy(getProblemChangeMatrix(changeMatrix, baseCol));
		
		//並べ替えた結果をS-P表に追加
		for (int i = 0; i < changeMatrix.getRowLength(); i++){
			changeMatrix.setRowName(i, matrix.getRowName(baseRow[i]));
		}
		for (int j = 0; j < changeMatrix.getColLength(); j++){
			changeMatrix.setColName(j, matrix.getColName(baseCol[j]));
		}
		
		return changeMatrix;
	}
		
/**
* 注意係数値を含めたS-P表を返します。<BR>
* マトリクスに正答数、正答者数、正答率、注意係数値、注意マークが含まれます。
* S-P表を作成する前のマトリクスに比べサイズが4行、4列分大きくなっています。
* 注意マークは数字で表示され、`!'が`1'、`!!'が`2'となります。
* @return 注意係数値を含めたS-P表
* @see #getSPMatrix()
* @see #getSPStringMatrix()
*/
	public ArithmeticMatrix getSPFullMatrix(){
		String rowName[] = new String[matrix.getRowLength()+4];
		String colName[] = new String[matrix.getColLength()+4];
		
		System.arraycopy(matrix.getRowNameArray(), 0, rowName, 0, matrix.getRowLength());
		System.arraycopy(matrix.getColNameArray(), 0, colName, 0, matrix.getColLength());
		rowName[matrix.getRowLength()] = "正答者数";
		rowName[matrix.getRowLength()+1] = "正答率";
		rowName[matrix.getRowLength()+2] = "注意係数";
		rowName[matrix.getRowLength()+3] = "注意マーク";
		
		colName[matrix.getColLength()] = "正答数";
		colName[matrix.getColLength()+1] = "正答率";
		colName[matrix.getColLength()+2] = "注意係数";
		colName[matrix.getColLength()+3] = "注意マーク";
		
		ArithmeticMatrix spFullMatrix = new ArithmeticMatrix(matrix.getRowLength()+4,matrix.getColLength()+4, rowName, colName);
		ArithmeticMatrix spMatrix = new ArithmeticMatrix(matrix.getRowLength(), matrix.getColLength());
		spMatrix.matrixCopy(getSPMatrix());
		
		//S-P表のコピー
		spFullMatrix.matrixCopy(spMatrix, 0, 0, 0, 0, spMatrix.getRowLength(), spMatrix.getColLength());
		
		//生徒側の処理
		for(int i = 0; i < spMatrix.getRowLength(); i++){
			spFullMatrix.setRowName(i, spMatrix.getRowName(i));		//生徒名コピー
			spFullMatrix.setCell(i,matrix.getColLength(),getStudentSum(getBaseRow(i)));		//正答数
			spFullMatrix.setCell(i,matrix.getColLength()+1,getStudentAverage(getBaseRow(i)));		//平均正答率
			spFullMatrix.setCell(i,matrix.getColLength()+2,getStudentAttentionCoefficient(getBaseRow(i)));		//注意係数
			spFullMatrix.setCell(i,matrix.getColLength()+3, getStudentAttentionNumber(getBaseRow(i)));		//注意マーク
		}
		
		//問題側の処理
		for(int j = 0; j < spMatrix.getColLength(); j++){
			spFullMatrix.setColName(j, spMatrix.getColName(j));		//問題名コピー
			spFullMatrix.setCell(matrix.getRowLength(), j,getProblemSum(getBaseCol(j)));		//正答者数
			spFullMatrix.setCell(matrix.getRowLength()+1, j,getProblemAverage(getBaseCol(j)));		//平均正答率
			spFullMatrix.setCell(matrix.getRowLength()+2, j,getProblemAttentionCoefficient(getBaseCol(j)));		//注意係数
			spFullMatrix.setCell(matrix.getRowLength()+3, j,getProblemAttentionNumber(getBaseCol(j)));		//注意マーク
		}
		
		//全体の平均正答率の追加
		spFullMatrix.setCell(getStudentNumber()+1, getProblemNumber()+1, getAverage());
		return spFullMatrix;
	}
	
/**
* 注意係数値を含めたS-P表を返します。<BR>
* マトリクスに正答数、正答者数、正答率、注意係数値、注意マークが含まれます。
* S-P表を作成する前のマトリクスに比べサイズが4行、4列分大きくなっています。
* 注意マークは`!'や`!!'で表現されます。
* @return 注意係数値を含めたS-P表
* @see #getSPMatrix()
* @see #getSPFullMatrix()
*/
	public StringMatrix getSPStringMatrix(){
		String rowName[] = new String[matrix.getRowLength()+4];
		String colName[] = new String[matrix.getColLength()+4];
		
		System.arraycopy(matrix.getRowNameArray(), 0, rowName, 0, matrix.getRowLength());
		System.arraycopy(matrix.getColNameArray(), 0, colName, 0, matrix.getColLength());
		rowName[matrix.getRowLength()] = "正答者数";
		rowName[matrix.getRowLength()+1] = "正答率";
		rowName[matrix.getRowLength()+2] = "注意係数";
		rowName[matrix.getRowLength()+3] = "注意マーク";
		
		colName[matrix.getColLength()] = "正答数";
		colName[matrix.getColLength()+1] = "正答率";
		colName[matrix.getColLength()+2] = "注意係数";
		colName[matrix.getColLength()+3] = "注意マーク";
		
		StringMatrix spFullMatrix = new StringMatrix(matrix.getRowLength()+4,matrix.getColLength()+4, rowName, colName);
		ArithmeticMatrix spMatrix = new ArithmeticMatrix(matrix.getRowLength(), matrix.getColLength());
		spMatrix.matrixCopy(getSPMatrix());
		
		//S-P表のコピー
		spFullMatrix.matrixCopy(spMatrix.toStringMatrix(), 0, 0, 0, 0, spMatrix.getRowLength(), spMatrix.getColLength());
		
		//生徒側の処理
		for(int i = 0; i < spMatrix.getRowLength(); i++){
			spFullMatrix.setRowName(i, spMatrix.getRowName(i));		//生徒名コピー
			spFullMatrix.setCell(i,matrix.getColLength(),getStudentSum(getBaseRow(i))+"");		//正答数
			spFullMatrix.setCell(i,matrix.getColLength()+1,getStudentAverage(getBaseRow(i))+"");		//平均正答率
			spFullMatrix.setCell(i,matrix.getColLength()+2,getStudentAttentionCoefficient(getBaseRow(i))+"");		//注意係数
			spFullMatrix.setCell(i,matrix.getColLength()+3, getStudentAttentionMark(getBaseRow(i)));		//注意マーク
		}
		
		//問題側の処理
		for(int j = 0; j < spMatrix.getColLength(); j++){
			spFullMatrix.setColName(j, spMatrix.getColName(j));		//問題名コピー
			spFullMatrix.setCell(matrix.getRowLength(), j,getProblemSum(getBaseCol(j))+"");		//正答者数
			spFullMatrix.setCell(matrix.getRowLength()+1, j,getProblemAverage(getBaseCol(j))+"");		//平均正答率
			spFullMatrix.setCell(matrix.getRowLength()+2, j,getProblemAttentionCoefficient(getBaseCol(j))+"");		//注意係数
			spFullMatrix.setCell(matrix.getRowLength()+3, j,getProblemAttentionMark(getBaseCol(j)));		//注意マーク
		}
		
		//全体の平均正答率の追加
		spFullMatrix.setCell(getStudentNumber()+1, getProblemNumber()+1, getAverage()+"");
		return spFullMatrix;
	}
	
/**
* 正答数(または正答者数)の多い順に並べ替えます。
* @param totalArray 各生徒(問題)の正答数を入れた配列
* @return 並べ替えた配列は元の何番目にあったかを示します
*/
	private int[] arrangeArray(double[] totalArray){
		int number; //最大の行番号保持
		int[] returnArray = new int[totalArray.length];
		
		//単純選択法でソート
		for (int i = 0; i < totalArray.length; i++){
			number = i;
			for (int j = 0; j < totalArray.length; j++){ 
				if (totalArray[number] < (int)totalArray[j]){
					number = j;
				}
			}
			totalArray[number] = -1;
			returnArray[i] = number;
		}
		return returnArray;
	}
	
/**
* 正答数の多い順に並べ替えたマトリクスを返します。
* @param baseMatrix 分析元のマトリクス
* @param row 行番号を正答数の多い順に並べ替えた配列
* @return 並べ替えたマトリクス
*/
	private ArithmeticMatrix getStudentChangeMatrix(ArithmeticMatrix baseMatrix,int[] row){
		ArithmeticMatrix rowChangeMatrix = new ArithmeticMatrix();
		rowChangeMatrix.matrixCopy(baseMatrix);
		int max = (int) baseMatrix.getRowSum(row[0]); //その時の正答数(格納したうちの最小値)
		max++;
		int roop = 1; //同じ正答数が何人続いているか
		for (int i = 0; i < baseMatrix.getRowLength(); i++){
			
			//要素の格納
			for (int j = 0; j < baseMatrix.getColLength(); j++){
				rowChangeMatrix.setCell(i, j, baseMatrix.getCell(row[i], j));
			}
			
			//格納した中で同一の正答数の生徒がいない場合
			if (max > baseMatrix.getRowSum(row[i])){
				roop = 1;
				max = (int)baseMatrix.getRowSum(row[i]);
			}
			//同一の正答数がいる場合
			else{
				roop++;
				int compareI = i; //比較する際のiの値
				for (int k = 1; k < roop; k++){
					//2者を比較するTureの場合は交換を行う
					if (compareStudent(baseMatrix, row[compareI-1], row[compareI])){
						//元の行番号を格納した配列の交換
						int temp = row[compareI];
						row[compareI] = row[compareI-1];
						row[compareI-1] = temp;
						
						//要素の交換
						for (int m = 0; m < baseMatrix.getColLength(); m++){
							rowChangeMatrix.setCell(compareI-1, m, baseMatrix.getCell(row[compareI-1], m));
							rowChangeMatrix.setCell(compareI, m, baseMatrix.getCell(row[compareI], m));
						}
						compareI--;
					}
					else{
						//ループを抜ける
						k = roop;
					}
				}
			}
		}
		return rowChangeMatrix;
	}
	
/**
* 正答者数の多い順に並べ替えたマトリクスを返します。
* @param baseMatrix 正答者の多い順に並べ替え終わったマトリクス
* @param col 列番号を正答者数の多い順に並べ替えた配列
* @return 並べ替えたマトリクス
*/
	private ArithmeticMatrix getProblemChangeMatrix(ArithmeticMatrix baseMatrix,int[] col){
		ArithmeticMatrix colChangeMatrix = new ArithmeticMatrix();
		colChangeMatrix.matrixCopy(baseMatrix);
		int max = (int) baseMatrix.getColSum(col[0]); //その時の正答数(格納したうちの最小値)
		max++;
		int roop = 1; //同じ正答数が何人続いているか
		for (int i = 0; i < baseMatrix.getColLength(); i++){
			
			//要素の格納
			for (int j = 0; j < baseMatrix.getRowLength(); j++){
				colChangeMatrix.setCell(j, i, baseMatrix.getCell(j, col[i]));
			}
			
			//格納した中で同一の正答者数の問題がない場合
			if (max > baseMatrix.getColSum(col[i])){
				roop = 1;
				max = (int) baseMatrix.getColSum(col[i]);
			}
			//同一の正答者数がいる場合
			else{
				roop++;
				int compareI = i; //比較する際のiの値
				for (int k = 1; k < roop; k++){
					//2者を比較するTureの場合は交換を行う
					if (compareProblem(baseMatrix, col[compareI-1], col[compareI])){
						//元の行番号を格納した配列の交換
						int temp = col[compareI];
						col[compareI] = col[compareI-1];
						col[compareI-1] = temp;
						
						//要素の交換
						for (int m = 0; m < baseMatrix.getRowLength(); m++){
							colChangeMatrix.setCell(m, compareI-1, baseMatrix.getCell(m, col[compareI-1]));
							colChangeMatrix.setCell(m, compareI, baseMatrix.getCell(m, col[compareI]));
						}
						compareI--;
					}
					else{
						//ループを抜ける
						k = roop;
					}
				}
			}
		}
		return colChangeMatrix;
	}
	
/**
* 同一の正答数の生徒同士を比較します。
* @param baseMatrix 入れ替えを行う前のマトリクス
* @param studentA 比較する生徒番号1
* @param studentB 比較する生徒番号2
* @return 比較結果が 生徒1 < 生徒2 の時 True 、 生徒1 >= 生徒2 の時 False を返します
*/
	private boolean compareStudent(ArithmeticMatrix baseMatrix, int studentA, int studentB){
		int studentATotal = 0; //正答した生徒の問題の総正答数
		int studentBTotal = 0;
		for (int i = 0; i < baseMatrix.getColLength(); i++){
			studentATotal = (int) baseMatrix.getCell(studentA, i) * 
				(int) baseMatrix.getColSum(i) + studentATotal;
			studentBTotal = (int) baseMatrix.getCell(studentB, i) * 
				(int) baseMatrix.getColSum(i) + studentBTotal;
		}
		return studentATotal < studentBTotal;
	}
/**
* 同一の正答者数の問題同士を比較します。
* @param baseMatrix 入れ替えを行う前のマトリクス
* @param problemA 比較する問題番号1
* @param problemB 比較する問題番号2
* @return 比較結果が 問題1 < 問題2 の時 True 、 問題1 >= 問題2 の時 False を返します
*/
	private boolean compareProblem(ArithmeticMatrix baseMatrix, int problemA, int problemB){
		int problemATotal = 0; //正答している問題の総正答者数
		int problemBTotal = 0;
		for (int i = 0; i < baseMatrix.getRowLength(); i++){
			problemATotal = (int) baseMatrix.getCell(i, problemA) * 
				(int) baseMatrix.getRowSum(i) + problemATotal;
			problemBTotal = (int) baseMatrix.getCell(i, problemB) * 
				(int) baseMatrix.getRowSum(i) + problemBTotal;
		}
		return problemATotal < problemBTotal;
	}
	
/**
* 指定した学習者(行)の正答数を返します。
* @param row 指定したい学習者の並べ替える前の行番号
* @return 指定した学習者の正答数
* @exception NotItemException 指定した学習者が存在しない場合
* @see #getProblemSum(int col)

*/
	public int getStudentSum(int row){
		if (matrix.isRowNumber(row)){
			return (int)matrix.getRowSum(row);
		}
		else{
			throw new NotItemException("row("+ row +")");
		}
	}
	
/**
* 指定した問題(列)の正答者数を返します。
* 指定する問題の並べ替える前の列番号
* @return 指定した問題の正答者数
* @exception NotItemException 指定した問題が存在しない場合
* @see #getStudentSum(int row)
*/
	public int getProblemSum(int col){
		if (matrix.isColNumber(col)){
			return (int)matrix.getColSum(col);
		}
		else{
			throw new NotItemException("col("+ col +")");
		}
	}
	
/**
* S曲線配列を返します。
* 配列の要素番号がS-P表における行番号に対応しています。
* 格納された値はS曲線のすぐ右の列番号を示します。
* @return S曲線配列
* @see #getPArray()
*/
	public int[] getSArray(){
		int sArray[] = new int[getStudentNumber()];
		for (int i = 0; i < getStudentNumber(); i++){
			sArray[i] = (int) matrix.getRowSum(getBaseRow(i));
		}
		return sArray;
	}
	
/**
* P曲線配列を返します。
* 配列の要素番号がS-P表における列番号に対応しています。
* 格納された値はP曲線の直下の行番号を示します。
* @return P曲線配列
* @see #getSArray()
*/
	public int[] getPArray(){
		int pArray[] = new int[getProblemNumber()];
		for (int i = 0; i < getProblemNumber(); i++){
			pArray[i] = (int) matrix.getColSum(getBaseCol(i));
		}
		return pArray;
	}
	
/**
* 指定した学習者(行)の正答率を返します。
* @param row 指定する学習者の並べ替える前の行番号
* @return 指定した学習者の平均正答率
* @exception NotItemException 指定した学習者が存在しない場合
* @see #getProblemAverage(int col)
*/
	public double getStudentAverage(int row){
		if (matrix.isRowNumber(row)){
			return getStudentSum(row) * 1.0 / getProblemNumber() * 100.0;
		}
		else{
			throw new NotItemException("row("+ row +")");
		}
	}
/**
* 指定した問題(列)の正答率を返します。
* @param col 指定する問題の並べ替える前の列番号
* @return 指定した問題の平均正答率
* @exception NotItemException 指定した問題が存在しない場合
* @see #getStudentAverage(int row)
*/
	public double getProblemAverage(int col){
		if (matrix.isColNumber(col)){
			return getProblemSum(col) * 1.0 / getStudentNumber() * 100.0;
		}
		else{
			throw new NotItemException("col("+ col +")");
		}
	}
	
/**
* 生徒全体の平均正答数を返します。
* @return 平均正答数
* @see #getProblemAverage()
* @see #getAverage()
*/
	public double getStudentAverage(){
		double value = 0.0;
		for (int i = 0; i < getStudentNumber(); i++){
			value = getStudentSum(i) + value;
		}
		return value / getStudentNumber();
	}
	
/**
* 問題全体の平均正答者数を返します。
* @return 平均正答者数
* @see #getStudentAverage()
* @see #getAverage()
*/
	public double getProblemAverage(){
		double value = 0.0;
		for (int i = 0; i < getProblemNumber(); i++){
			value = getProblemSum(i) + value;
		}
		return value / getProblemNumber();
	}
	
/**
* S-P表全体の平均正答率を返します。
* @return 平均正答率
* @see #getStudentAverage()
* @see #getProblemAverage()
*/
	public double getAverage(){
		double value = 0.0;
		for (int i = 0; i < getStudentNumber(); i++){
			value = getStudentSum(i) + value;
		}
		return value * 100 / (getStudentNumber() * getProblemNumber());
	}
	
/**
* 指定した学習者(行)の注意係数を返します。
* @param row 指定する学習者の並べ替える前の行番号
* @return 指定した学習者の注意係数
* @exception NotItemException 指定した学習者が存在しない場合
* @see #getProblemAttentionCoefficient(int col)
*/
	public double getStudentAttentionCoefficient(int row){
		if (matrix.isRowNumber(row)){
		
		//S曲線の収得
		int sArray[] = new int[getStudentNumber()];
		System.arraycopy(getSArray(), 0, sArray, 0, getStudentNumber());
		
		//生徒SiのS曲線から左の``0''に対応する問題の正答者数の和
		double zeroProblem;
		
		//生徒SiのS曲線から右の``1''に対応する問題の正答者数の和
		double oneProblem;
		
		//生徒SiのS曲線から左の問題の正答者数の和
		double leftProblem;
		
		//戻り値
		double value;
			
			//正答数0の場合(特異点)
			if (getStudentSum(row) == 0.0){
				value = 1.0;
			}
			
			//全問正答の場合
			else if (getStudentSum(row) == getProblemNumber()){
				value = 0.0;
			}
			else{
				zeroProblem = 0.0;
				oneProblem = 0.0;
				leftProblem = 0.0;
				
				//S曲線から左
				for (int j = 0; j < sArray[getSPRow(row)]; j++){
					if (matrix.getCell(row, getBaseCol(j)) == 0){
						zeroProblem = getProblemSum(getBaseCol(j)) + zeroProblem;
					}
					leftProblem = getProblemSum(getBaseCol(j)) + leftProblem;
				}
				
				//S曲線より右
				for (int k = sArray[getSPRow(row)]; k < getProblemNumber(); k++){
					if (matrix.getCell(row, getBaseCol(k)) == 1){
						oneProblem = getProblemSum(getBaseCol(k)) + oneProblem;
					}
				}
				
				//注意係数の計算
				value = (zeroProblem - oneProblem) / 
					(leftProblem - getStudentSum(row) * getProblemAverage());
			}
		return value;
	}
		else{
			throw new NotItemException("row("+ row +")");
		}
	}
	
/**
* 指定した問題(列)の注意係数を返します。
* @param col 指定する問題の並べ替える前の列番号
* @return 指定した問題の注意係数
* @exception NotItemException 指定した問題が存在しない場合
* @see #getStudentAttentionCoefficient(int row)
*/
	public double getProblemAttentionCoefficient(int col){
		if (matrix.isColNumber(col)){
		
		//P曲線の収得
		int pArray[] = new int[getProblemNumber()];
		System.arraycopy(getPArray(), 0, pArray, 0, getProblemNumber());
		
		//問題IiのP曲線から上の``0''に対応する生徒の正答数の和
		double zeroStudent;
		
		//問題IiのP曲線から下の``1''に対応する生徒の正答数の和
		double oneStudent;
		
		//問題IiのP曲線から上の生徒の正答者の和
		double upStudent;
		
		//戻り値
		double value;
			
			//正答者数0の場合(特異点)
			if (getProblemSum(col) == 0.0){
				value = 1.0;
			}
			
			//全員正答の場合
			else if (getProblemSum(col) == getStudentNumber()){
				value = 0.0;
			}
			else{
				zeroStudent = 0.0;
				oneStudent = 0.0;
				upStudent = 0.0;
				
				//P曲線から上
				for (int j = 0; j < pArray[getSPCol(col)]; j++){
					if (matrix.getCell(getBaseRow(j), col) == 0){
						zeroStudent = getStudentSum(getBaseRow(j)) + zeroStudent;
					}
					upStudent = getStudentSum(getBaseRow(j)) + upStudent;
				}
				
				//P曲線より下
				for (int k = pArray[getSPCol(col)]; k < getStudentNumber(); k++){
					if (matrix.getCell(getBaseRow(k), col) == 1){
						oneStudent = getStudentSum(getBaseRow(k)) + oneStudent;
					}
				}
				
				//注意係数の計算
				value = (zeroStudent - oneStudent) / 
					(upStudent - getProblemSum(col) * getStudentAverage());
			}
			return value;
		}
		else{
			throw new NotItemException("col("+ col +")");
		}
	}
	
/**
* 学習者の注意マークを返します。
* @param row 指定する学習者の並べ替える前の行番号
* @return 指定した学習者の注意マーク
* @exception NotItemException 指定した学習者が存在しない場合
* @see #getProblemAttentionMark(int col)
* @see #getStudentAttentionNumber(int row)
*/
	public String getStudentAttentionMark(int row){
		if (matrix.isRowNumber(row)){
		
		//注意係数
		double attention = getStudentAttentionCoefficient(row);
		
		//戻り値
		String mark;
			if (getStudentAverage(row) < SPTABLE_CAUTION_MARK_SCORE_AVERAGE1 * 100){
				if (SPTABLE_CAUTION_MARK_CAUTION_VALUE2 <= attention){
					mark = SPTABLE_CAUTION_MARK_TWOSTRING;
				}
				else if (SPTABLE_CAUTION_MARK_CAUTION_VALUE1 <= attention){
					mark = SPTABLE_CAUTION_MARK_ONESTRING;
				}
				else{
					mark = SPTABLE_CAUTION_MARK_NONSTRING;
				}
			}
			else{
				mark = SPTABLE_CAUTION_MARK_NONSTRING;
			}
			return mark;
		}
		else{
			throw new NotItemException("row("+ row +")");
		}
	}
	
/**
* 問題の注意マークを返します。
* @param col 指定する問題の並べ替える前の列番号
* @return 指定した問題の注意マーク
* @exception NotItemException 指定した問題が存在しない場合
* @see #getStudentAttentionMark(int row)
* @see #getProblemAttentionNumber(int col)
*/
	public String getProblemAttentionMark(int col){
		if (matrix.isColNumber(col)){
		//注意係数
		double attention = getProblemAttentionCoefficient(col);
		
		//戻り値
		String mark;
		
			if (getProblemAverage(col) < SPTABLE_CAUTION_MARK_SCORE_AVERAGE1 * 100){
				if (SPTABLE_CAUTION_MARK_CAUTION_VALUE2 <= attention){
					mark = SPTABLE_CAUTION_MARK_TWOSTRING;
				}
				else if (SPTABLE_CAUTION_MARK_CAUTION_VALUE1 <= attention){
					mark = SPTABLE_CAUTION_MARK_ONESTRING;
				}
				else{
					mark = SPTABLE_CAUTION_MARK_NONSTRING;
				}
			}
			else{
				mark = SPTABLE_CAUTION_MARK_NONSTRING;
			}
			return mark;
	}
		else{
			throw new NotItemException("col("+ col +")");
		}
	}
	
/**
* 学習者の注意マークを返します。
* マークなしの場合は0、`!'の場合は1、`!!'の場合は2で示されます。
* @param row 指定する学習者の並べ替える前の行番号
* @return 指定した学習者の注意マーク
* @exception NotItemException 指定した学習者が存在しない場合
* @see #getProblemAttentionNumber(int col)
* @see #getStudentAttentionMark(int row)
*/
	public int getStudentAttentionNumber(int row){
		if (matrix.isRowNumber(row)){
		//注意係数
		double attention = getStudentAttentionCoefficient(row);
		
		//戻り値
		int mark;
			if (getStudentAverage(row) < SPTABLE_CAUTION_MARK_SCORE_AVERAGE1 * 100){
				if (SPTABLE_CAUTION_MARK_CAUTION_VALUE2 <= attention){
					mark = SPTABLE_CAUTION_MARK_TWO;
				}
				else if (SPTABLE_CAUTION_MARK_CAUTION_VALUE1 <= attention){
					mark = SPTABLE_CAUTION_MARK_ONE;
				}
				else{
					mark = SPTABLE_CAUTION_MARK_NON;
				}
			}
			else{
				mark = SPTABLE_CAUTION_MARK_NON;
			}
			return mark;
		}
		else{
			throw new NotItemException("row("+ row +")");
		}
	}
	
/**
* 問題の注意マークを返します。
* マークなしの場合は0、`!'の場合は1、`!!'の場合は2で示されます。
* @param col 指定する問題の並べ替える前の列番号
* @return 指定した問題の注意マーク
* @exception NotItemException 指定した問題が存在しない場合
* @see #getStudentAttentionNumber(int row)
* @see #getProblemAttentionMark(int col)
*/
	public int getProblemAttentionNumber(int col){
		if (matrix.isColNumber(col)){
		//注意係数
		double attention = getProblemAttentionCoefficient(col);
		
		//戻り値
		int mark;
		
			if (getProblemAverage(col) < SPTABLE_CAUTION_MARK_SCORE_AVERAGE1 * 100){
				if (SPTABLE_CAUTION_MARK_CAUTION_VALUE2 <= attention){
					mark = SPTABLE_CAUTION_MARK_TWO;
				}
				else if (SPTABLE_CAUTION_MARK_CAUTION_VALUE1 <= attention){
					mark = SPTABLE_CAUTION_MARK_ONE;
				}
				else{
					mark = SPTABLE_CAUTION_MARK_NON;
				}
			}
			else{
				mark = SPTABLE_CAUTION_MARK_NON;
			}
			return mark;
		}
		else{
			throw new NotItemException("col("+ col +")");
		}
	}
	
/**
* S-P表を作成する前のマトリクスを返します。
* @return S-P表作成前のマトリクス
*/
	public ArithmeticMatrix getBaseSPMatrix(){
		return matrix;
	}
	
/**
* S-P表に存在する学習者数(行数)を返します。
* @return 学習者数
* @see #getProblemNumber()
*/
	public int getStudentNumber(){
		return matrix.getRowLength();
	}
	
/**
* S-P表に存在する問題数(列数)を返します。
* @return 問題数
* @see #getStudentNumber()
*/
	public int getProblemNumber(){
		return matrix.getColLength();
	}
	
/**
* 指定した行はS-P表作成前のマトリクスでは何行目にあったか、元の行番号を返します。
* @param row S-P表における行番号
* @return 元の表における行番号
* @exception NotItemException 指定された行番号が存在しない場合
* @see #getBaseCol(int col)
* @see #getBaseRowArray()
*/
	public int getBaseRow(int row){
		if (matrix.isRowNumber(row)){ //マトリクスの範囲内かどうかを調べる
		return baseRow[row];
		}
		else{
			throw new NotItemException("row("+ row +")");
		}
	}
	
/**
* S-P表作成前のマトリクスでは何行目にあったか、元の行番号を示した配列を返します。
* @return 行番号の入った配列
* @see #getBaseColArray()
* @see #getBaseRow(int row)
*/
	public int[] getBaseRowArray(){
		return baseRow;
	}
	
/**
* 指定した列はS-P表作成前のマトリクスでは何列目にあったか、元の列番号を返します。
* @param col S-P表における列番号
* @return 元の表における列番号
* @exception NotItemException 指定された列番号が存在しない場合
* @see #getBaseRow(int row)
* @see #getBaseColArray()
*/
	public int getBaseCol(int col){
		if (matrix.isColNumber(col)){ //マトリクスの範囲内かどうかを調べる
		return baseCol[col];
		}
			else{
			throw new NotItemException("col("+ col +")");
		}
	}
	
/**
* S-P表作成前のマトリクスでは何列目にあったか、元の列番号を示した配列を返します。
* @return 列番号の入った配列
* @see #getBaseRowArray()
* @see #getBaseCol(int col)
*/
	public int[] getBaseColArray(){
		return baseCol;
	}
	
/**
* 指定した行はS-P表作成後のマトリクスでは何行目にあるか、行番号を返します。
* @param row 元の表における行番号
* @return S-P表における行番号
* @exception NotItemException 指定された行番号が存在しない場合
*/
	private int getSPRow(int row){
		if (matrix.isRowNumber(row)){ //マトリクスの範囲内かどうかを調べる
			for(int i = 0; i < getStudentNumber(); i++){
				if(row == baseRow[i]){
					return i;
				}
			}
		}
			throw new NotItemException("row("+ row +")");
	}
	
/**
* 指定した列はS-P表作成後のマトリクスでは何列目にあるか、列番号を返します。
* @param col 元の表における列番号
* @return S-P表における列番号
* @exception NotItemException 指定された列番号が存在しない場合
*/
	private int getSPCol(int col){
		if (matrix.isColNumber(col)){ //マトリクスの範囲内かどうかを調べる
			for(int i = 0; i < getProblemNumber(); i++){
				if(col == baseCol[i]){
					return i;
				}
			}
		}
			throw new NotItemException("col("+ col +")");
	}
	
/**
* S-P表を作成する前のマトリクスを設定します。
* @param baseMatrix 設定を行うマトリクス
*/
	private void setBaseMatrix(ArithmeticMatrix baseMatrix){
		matrix = new ArithmeticMatrix(baseMatrix.getRowLength(), baseMatrix.getColLength());
		matrix.matrixCopy(baseMatrix);
	}
	
/**
* 並べ替える前の行番号を保持した配列を生成します。
* @param baseMatrix 分析対象のマトリクス
*/
	private void setBaseRow(ArithmeticMatrix baseMatrix){
		baseRow = new int[baseMatrix.getRowLength()];
	}
	
/**
* 並べ替える前の列番号を保持した配列を生成します。
* @param baseMatrix 分析対象のマトリクス
*/
	private void setBaseCol(ArithmeticMatrix baseMatrix){
		baseCol = new int[baseMatrix.getColLength()];
	}
	
/**
* S-P表を作成する元となるマトリクスを設定し、S-P表を作成します。
* @param baseMatrix 作成を行う元となるマトリクス
*/
	public void setSPMatrix(ArithmeticMatrix baseMatrix){
		setBaseMatrix(baseMatrix);
		setBaseRow(matrix);
		setBaseCol(matrix);
	}
	
/**
* S-P表を作成する元となるマトリクスの要素を修正します。
* @param row 修正する要素の行
* @param col 修正する要素の列
* @param value 修正値
* @exception NotElementException 指定した要素が存在しない場合
* @exception ValueFormatException 修正する値が0または1以外の値である場合
* @see #setSPMatrix(ArithmeticMatrix baseMatrix)
*/
	public void setElement(int row, int col, int value){
		if (matrix.isMatrixEntityPoint(row, col)){
			if(value == 0.0 || value == 1.0){
				matrix.setCell(row, col, value);
			}
			else{
				throw new ValueFormatException("value("+value+")");
			}
		}
		else{
			throw new NotElementException("Point(" + row + "," + col + ")");
		}
	}
}