package jp.ac.takushoku_u.cs;
import java.util.Set;
import java.util.Iterator;
import java.util.TreeSet;

/**
* TaskSequencePresumptionクラスは系列化された課題から、
* 目標指向性因子負荷アルファと前提指向性因子負荷ベータの取りうる範囲を推定するためのクラスです。<br>
* 本クラスのドキュメントでは、<br>
* アルファに関する(1)式を、f(v_i-1,v_i)-s_a*s_b*g(v_i-1,v_i)-f(v_i-1,v_j)+s_a*s_b*g(v_i-1,v_j)<br>
* (2)式を、s_b*g(v_i-1,v_j)-s_b*g(v_i-1,v_i)<br>
* ベータに関する(1)式を、g(v_i-1,v_i)-s_a*s_b*f(v_i-1,v_i)-g(v_i-1,v_j)+s_a*s_b*f(v_i-1,v_j)<br>
* (2)式を、s_a*f(v_i-1,v_j)-s_a*f(v_i-1,v_i)<br>
* とします。
* @version 1.0.1
* @author 笠島 裕史(Kasajima Hiroshi)
*/
/*
* 最終更新日 2005年01月07日
*/
public class TaskSequencePresumption extends TaskSequence{
	
/**
* 推定を行う系列
*/
	private Sequence series;
	
/**
* 系列を行ったグラフ
*/
	private ArithmeticMatrix matrix;
	
/**
* 正の有限非ゼロ値
*/
	private double POSITIVE_NOT_ZERO = Double.MIN_VALUE;
	
/**
* 負の有限非ゼロ値
*/
	private double NEGATIVE_NOT_ZERO = Double.MIN_VALUE * -1.0;
	
/**
* パルスの判別定数
*/
	private double PULSE_NUMBER = 1.0E-16d;
	
	
/**
* 推定を行う系列として要素0の系列を設定します。
*/
	public TaskSequencePresumption(){
		series = new Sequence();
		matrix = new ArithmeticMatrix();
		setGraph(matrix);
		setSequence(series);
		
		//TaskSequenceに設定する
		setMatrix(matrix);
	}
	
/**
* 隣接マトリクスと推定を行う系列を設定します。
* @param preSequence 設定する系列
* @param graph 系列化を行ったグラフ
* @exception NotSquareMatrixException 設定したマトリクスが正方行列ではない場合
* @exception DisagreementSequenceSizeException マトリクスとSequenceのサイズが一致しない場合
*/
	public TaskSequencePresumption(Sequence preSequence, ArithmeticMatrix graph){
		series = new Sequence();
		matrix = new ArithmeticMatrix();
		setGraph(graph);
		setSequence(preSequence);
		
		//TaskSequenceに設定する
		setMatrix(graph);
	}
	
	
/**
* ある象限における推定されたアルファの区間の集合を返します。
* @param k 象限
* @return 推定した区間の集合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getBetaRangeSet(int k)
*/
	public RangeSet getAlphaRangeSet(int k){
		if(inQuadrant(k)){
			//計算結果を入れる Range
			Range ra = new Range();
			
			//結果一時保持用の Range
			Range ran = new Range();
			
			//集合保持の RangeSet
			RangeSet hashSet = new RangeSet();
			
			//選択可能項目が入った配列
			boolean[] el = new boolean[series.getLength()];
			
			for(int i = 0; i < series.getLength(); i++){
				
				//選択可能項目を持ってくる
				System.arraycopy(getReachElement(series.getItem(i)), 0, el, 0, series.getLength());
				ran.rangeCopy(getAlphaNotItemRange(k));
				int count = 0;
				
				//選択可能項目を調べる
				for(int j = 0; j < series.getLength(); j++){
					if(el[j] && (series.getItem(i) != j)){
						ra.rangeCopy(getAlphaPresumptionRange(series.getItem(i), j, k));
						ran.rangeCopy(ran.getAndRange(ra));
						count++;
					}
				}
				if(count == 0){
					ran.rangeCopy(getAlphaNotItemRange(k));
				}
				
				//区間を保持する
				hashSet.add(new Range(ran.getMin(), ran.getMax(), ran.hasMin(), ran.hasMax()));
				
			}
			return hashSet;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ある象限における推定されたアルファの区間を返します。
* @param k 象限
* @return 推定した区間
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getBetaRange(int k)
*/
	public Range getAlphaRange(int k){
		if(inQuadrant(k)){
			RangeSet hashSet = new RangeSet(getAlphaRangeSet(k));
			Range ra = new Range();
			Range ran = new Range();
			ran.rangeCopy(getAlphaNotItemRange(k));
			
			Iterator i = hashSet.iterator();
			while(i.hasNext()){
				ra.rangeCopy((Range)i.next());
				ran.rangeCopy(ran.getAndRange(ra));
			}
			
			return ran;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ある値におけるアルファの帰属度関数の値を返します。
* @param k 象限
* @param value 指定した値
* @return 帰属度関数の値
* @exception ValueFormatException 指定した象限もしくは指定した値が取りえない値であった場合
* @see #getBetaAttribute(int k, double value)
*/
	public double getAlphaAttribute(int k, double value){
		if(inQuadrant(k)){
			if(isNormalAlpha(value)){
				RangeSet hashSet = new RangeSet(getAlphaRangeSet(k));
				int count = 0;
				Range ra = new Range();
				
				Iterator i = hashSet.iterator();
				while(i.hasNext()){
					ra.rangeCopy((Range)i.next());
					if(ra.hasValue(value)){
						count++;
					}
				}
				
				return (count * 1.0) / hashSet.size();
			}
			else{
				throw  new ValueFormatException("alpha(" + value + ")");
			}
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ある象限の取りうる区間内において帰属度関数の値が変化するアルファの値を集合で返します。
* 象限の取りうる区間の両端は集合に含まれます。
* @param k 象限
* @return 変化するアルファの値を入れた集合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getBetaAttributeSet(int k)
*/
	public Set getAlphaAttributeSet(int k){
		if(inQuadrant(k)){
			Set treeSet = new TreeSet();
			
			RangeSet hashSet = new RangeSet(getAlphaRangeSet(k));
			Range ra = new Range();
			
			Iterator i = hashSet.iterator();
			while(i.hasNext()){
				ra.rangeCopy((Range)i.next());
				treeSet.add(new Double(ra.getMin()));
				treeSet.add(new Double(ra.getMax()));
				
				if(ra.isSame()){
					if(getSAlpha(k) == 1.0){
						if(ra.getMin() == 0.0){
							treeSet.add(new Double(POSITIVE_NOT_ZERO));
						}
						else if(ra.getMin() == 1.0){
							treeSet.add(new Double(ra.getMin() - PULSE_NUMBER));
						}
						else{
							treeSet.add(new Double(ra.getMin() + PULSE_NUMBER));
							treeSet.add(new Double(ra.getMin() - PULSE_NUMBER));
						}
					}
					else{
						if(ra.getMin() == 0.0){
							treeSet.add(new Double(NEGATIVE_NOT_ZERO));
						}
						else if(ra.getMin() == -1.0){
							treeSet.add(new Double(ra.getMin() + PULSE_NUMBER));
						}
						else{
							treeSet.add(new Double(ra.getMin() + PULSE_NUMBER));
							treeSet.add(new Double(ra.getMin() - PULSE_NUMBER));
						}
					}
				}
			}
			return treeSet;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ある象限における推定されたベータの区間の集合を返します。
* @param k 象限
* @return 推定した区間の集合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getAlphaRangeSet(int k)
*/
	public RangeSet getBetaRangeSet(int k){
		if(inQuadrant(k)){
			//計算結果を入れる Range
			Range ra = new Range();
			
			//結果一時保持用の Range
			Range ran = new Range();
			
			//集合保持の RangeSet
			RangeSet hashSet = new RangeSet();
			
			//選択可能項目が入った配列
			boolean[] el = new boolean[series.getLength()];
			
			for(int i = 0; i < series.getLength(); i++){
				
				//選択可能項目を持ってくる
				System.arraycopy(getReachElement(series.getItem(i)), 0, el, 0, series.getLength());
				ran.rangeCopy(getBetaNotItemRange(k));
				int count = 0;
				
				//選択可能項目を調べる
				for(int j = 0; j < series.getLength(); j++){
					if(el[j] && (series.getItem(i) != j)){
						ra.rangeCopy(getBetaPresumptionRange(series.getItem(i), j, k));
						ran.rangeCopy(ran.getAndRange(ra));
						count++;
					}
				}
				if(count == 0){
					ran.rangeCopy(getBetaNotItemRange(k));
				}
				
				//区間を保持する
				hashSet.add(new Range(ran.getMin(), ran.getMax(), ran.hasMin(), ran.hasMax()));
				
			}
			return hashSet;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ある象限における推定されたベータの区間を返します。
* @param k 象限
* @return 推定した区間
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getAlphaRange(int k)
*/
	public Range getBetaRange(int k){
		if(inQuadrant(k)){
			RangeSet hashSet = new RangeSet(getBetaRangeSet(k));
			Range ra = new Range();
			Range ran = new Range();
			ran.rangeCopy(getBetaNotItemRange(k));
			
			Iterator i = hashSet.iterator();
			while(i.hasNext()){
				ra.rangeCopy((Range)i.next());
				ran.rangeCopy(ran.getAndRange(ra));
			}
			
			return ran;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ある値におけるベータの帰属度関数の値を返します。
* @param k 象限
* @param value 指定した値
* @return 帰属度関数の値
* @exception ValueFormatException 指定した象限もしくは指定した値が取りえない値であった場合
* @see #getAlphaAttribute(int k, double value)
*/
	public double getBetaAttribute(int k, double value){
		if(inQuadrant(k)){
			if(isNormalAlpha(value)){
				RangeSet hashSet = new RangeSet(getBetaRangeSet(k));
				int count = 0;
				Range ra = new Range();
				
				Iterator i = hashSet.iterator();
				while(i.hasNext()){
					ra.rangeCopy((Range)i.next());
					if(ra.hasValue(value)){
						count++;
					}
				}
				
				return (count * 1.0) / hashSet.size();
			}
			else{
				throw  new ValueFormatException("alpha(" + value + ")");
			}
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ある象限の取りうる区間内において帰属度関数の値が変化するベータの値を集合で返します。
* 象限の取りうる区間の両端は集合に含まれます。
* @param k 象限
* @return 変化するベータの値を入れた集合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getAlphaAttributeSet(int k)
*/
	public Set getBetaAttributeSet(int k){
		if(inQuadrant(k)){
			Set treeSet = new TreeSet();
			
			RangeSet hashSet = new RangeSet(getBetaRangeSet(k));
			Range ra = new Range();
			
			Iterator i = hashSet.iterator();
			while(i.hasNext()){
				ra.rangeCopy((Range)i.next());
				treeSet.add(new Double(ra.getMin()));
				treeSet.add(new Double(ra.getMax()));
				
				if(ra.isSame()){
					if(getSBeta(k) == 1.0){
						if(ra.getMin() == 0.0){
							treeSet.add(new Double(POSITIVE_NOT_ZERO));
						}
						else if(ra.getMin() == 1.0){
							treeSet.add(new Double(NEGATIVE_NOT_ZERO + ra.getMin()));
						}
						else{
							treeSet.add(new Double(POSITIVE_NOT_ZERO + ra.getMin()));
							treeSet.add(new Double(NEGATIVE_NOT_ZERO + ra.getMin()));
						}
					}
					else{
						if(ra.getMin() == 0.0){
							treeSet.add(new Double(NEGATIVE_NOT_ZERO));
						}
						else if(ra.getMin() == -1.0){
							treeSet.add(new Double(POSITIVE_NOT_ZERO + ra.getMin()));
						}
						else{
							treeSet.add(new Double(POSITIVE_NOT_ZERO + ra.getMin()));
							treeSet.add(new Double(NEGATIVE_NOT_ZERO + ra.getMin()));
						}
					}
				}
			}
			return treeSet;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* 他に選択可能項目の無い場合のアルファの推定された区間を返します。
* @param k 象限
* @return 推定した区間
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getBetaNotItemRange(int k)
*/
	private Range getAlphaNotItemRange(int k){
		if(inQuadrant(k)){
			if(getSAlpha(k) == 1.0){
				return new Range(0.0, 1.0, true, true);
			}
			else{
				return new Range(-1.0, 0.0, true, true);
			}
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* 他に選択可能項目の無い場合のベータの推定された区間を返します。
* @param k 象限
* @return 推定した区間
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getAlphaNotItemRange(int k)
*/
	private Range getBetaNotItemRange(int k){
		if(inQuadrant(k)){
			if(getSBeta(k) == 1.0){
				return new Range(0.0, 1.0, true, true);
			}
			else{
				return new Range(-1.0, 0.0, true, true);
			}
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* 2項目間から推定したアルファの区間を返します。
* vi と vj は設定した隣接マトリクスの項目の行番号を設定します。(項目0は仮想項目ではありません。)
* @param vi 実際に選択された項目
* @param vj 他の選択可能項目
* @param k 象限(アルファの取りうる区間）
* @return 推定できる区間
* @exception NotItemException 指定した項目が存在しない場合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @exception IllegalRelationValuesException 実際に選択された項目と選択可能項目の関係が異なる場合
* @see #getBetaPresumptionRange(int vi, int vj, int k)
*/
	public Range getAlphaPresumptionRange(int vi, int vj, int k){
		if(matrix.isRowNumber(vi)){
			if(matrix.isRowNumber(vj)){
				if(isNomalChoice(vi,vj)){
					if(inQuadrant(k)){
						double expressionOne = getDiscriminantOneAlpha(vi, vj, k);		//(1)式
						double expressionTwo = getDiscriminantTwoAlpha(vi, vj, k);		//(2)式
						double expression = getDiscriminantAlpha(vi, vj, k);		//(2)式/(1)式
						
						return getPresumptionRange(expressionOne, expressionTwo, expression, getSAlpha(k));
					}
					else{
						throw new ValueFormatException("quadrant(" + k + ")");
					}
				}
				else{
					throw new IllegalRelationValuesException("relation(" + vi + "," + vj + ")");
				}
			}
			else{
				throw new NotItemException("vj("+ vj+")");
			}
		}
		else{
				throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* 2項目間から推定したベータの区間を返します。
* vi と vj は設定した隣接マトリクスの項目の行番号を設定します。(項目0は仮想項目ではありません。)
* @param vi 実際に選択された項目
* @param vj 他の選択可能項目
* @param k 象限(ベータの取りうる区間）
* @return 推定できる区間
* @exception NotItemException 指定した項目が存在しない場合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @exception IllegalRelationValuesException 実際に選択された項目と選択可能項目の関係が異なる場合
* @see #getAlphaPresumptionRange(int vi, int vj, int k)
*/
	public Range getBetaPresumptionRange(int vi, int vj, int k){
		if(matrix.isRowNumber(vi)){
			if(matrix.isRowNumber(vj)){
				if(isNomalChoice(vi,vj)){
					if(inQuadrant(k)){
						double expressionOne = getDiscriminantOneBeta(vi, vj, k);		//(1)式
						double expressionTwo = getDiscriminantTwoBeta(vi, vj, k);		//(2)式
						double expression = getDiscriminantBeta(vi, vj, k);		//(2)式/(1)式
						
						return getPresumptionRange(expressionOne, expressionTwo, expression, getSBeta(k));
					}
					else{
						throw new ValueFormatException("quadrant(" + k + ")");
					}
				}
				else{
					throw new IllegalRelationValuesException("relation(" + vi + "," + vj + ")");
				}
			}
			else{
				throw new NotItemException("vj("+ vj+")");
			}
		}
		else{
				throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* ある2項目間で推定した区間を返します。
* @param expressionOne (1)式の計算結果
* @param expressionTwo (2)式の計算結果
* @param expression (2)式 / (1)式の計算結果
* @param k 指定した象限の条件
* @return 推定した区間
*/
	private Range getPresumptionRange(double expressionOne, double expressionTwo, double expression, double k){
		if(expressionOne == 0.0){
			if(expressionTwo > 0.0){
				if(k == 1.0){
					if(expression > 1){
						return calPresumptionZeroPlusPlusOut(expression);
					}
					else{
						return calPresumptionZeroPlusPlusIn(expression);
					}
				}
				else{
					if(expression < -1){
						return calPresumptionZeroPlusMinusOut(expression);
					}
					else{
						return calPresumptionZeroPlusMinusIn(expression);
					}
				}
			}
			else{
				if(k == 1.0){
					if(expression > 1){
						return calPresumptionZeroMinusPlusOut(expression);
					}
					else{
						return calPresumptionZeroMinusPlusIn(expression);
					}
				}
				else{
					if(expression < -1){
						return calPresumptionZeroMinusMinusOut(expression);
					}
					else{
						return calPresumptionZeroMinusMinusIn(expression);
					}
				}
			}
		}
		else if(expressionOne > 0.0){
			if(expressionTwo >= 0.0){
				if(k == 1.0){
					if(expression > 1){
						return calPresumptionPlusPlusPlusOut(expression);
					}
					else{
						return calPresumptionPlusPlusPlusIn(expression);
					}
				}
				else{
					if(expression < -1){
						return calPresumptionPlusPlusMinusOut(expression);
					}
					else if(expression == 0){
						return calPresumptionPlusPlusMinusZero(expression);
					}
					else{
						return calPresumptionPlusPlusMinusIn(expression);
					}
				}
			}
			else{
				if(k == 1.0){
					if(expression > 1){
						return calPresumptionPlusMinusPlusOut(expression);
					}
					else{
						return calPresumptionPlusMinusPlusIn(expression);
					}
				}
				else{
					if(expression <= -1){
						return calPresumptionPlusMinusMinusOut(expression);
					}
					else{
						return calPresumptionPlusMinusMinusIn(expression);
					}
				}
			}
		}
		else{
			if(expressionTwo >= 0.0){
				if(k == 1.0){
					if(expression > 1){
						return calPresumptionMinusPlusPlusOut(expression);
					}
					else if(expression == 0.0){
						return calPresumptionMinusPlusPlusZero(expression);
					}
					else{
						return calPresumptionMinusPlusPlusIn(expression);
					}
				}
				else{
					if(expression < -1){
						return calPresumptionMinusPlusMinusOut(expression);
					}
					else{
						return calPresumptionMinusPlusMinusIn(expression);
					}
				}
			}
			else{
				if(k == 1.0){
					if(expression > 1){
						return calPresumptionMinusMinusPlusOut(expression);
					}
					else{
						return calPresumptionMinusMinusPlusIn(expression);
					}
				}
				else{
					if(expression < -1){
						return calPresumptionMinusMinusMinusOut(expression);
					}
					else{
						return calPresumptionMinusMinusMinusIn(expression);
					}
				}
			}
		}
	}
	
/**
* 項目viの1つ前の既選択項目を返します。
* 返される項目番号はviを選択する前の項目です。
* 仮想項目の付与が必要な隣接マトリクスである場合、初期選択項目を与えると0が返されます。
* @param vi 選択項目
* @return 1つ前の既選択項目
* @exception NotItemException 指定した項目が存在しない場合
*/
	public int getBeforeItem(int vi){
		if(matrix.isRowNumber(vi)){
			int va = series.getNumber(vi) -1;		//viの順番、viがない場合ここで例外発生
			int v;		//既選択項目を探す
			
			if(isDummy()){		//仮想項目のある場合
				if(va < 0){
					v = 0;
				}
				else{
					v = series.getItem(va) + 1;
				}
			}
			else{
				v = series.getItem(va);
			}
			return v;
		}
		else{
			throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* アルファにおける(1)式の計算結果を返します。
* @param vi 実際の選択項目
* @param vj 選択を行わなかった選択可能項目
* @param k 象限
* @return 計算結果
* @exception NotItemException 指定した項目が存在しない場合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @exception IllegalRelationValuesException 実際に選択された項目と選択可能項目の関係が異なる場合
* @see #getDiscriminantOneBeta(int vi, int vj, int k)
*/
	public double getDiscriminantOneAlpha(int vi, int vj, int k){
		if(matrix.isRowNumber(vi)){
			if(matrix.isRowNumber(vj)){
				if(isNomalChoice(vi,vj)){
				
					//kが正しい範囲か
					if(inQuadrant(k)){
						
						int v = getBeforeItem(vi);
						if(isDummy()){		//仮想項目のある場合
							vi = vi + 1;
							vj = vj + 1;
						}
						
						return getDiscriminantOneAlpha(getF(v, vi), getG(v, vi), getF(v, vj), getG(v, vj), k);
					}
					else{
						throw new ValueFormatException("quadrant(" + k + ")");
					}
				}
				else{
					throw new IllegalRelationValuesException("relation(" + vi + "," + vj + ")");
				}
			}
			else{
				throw new NotItemException("vj("+ vj+")");
			}
		}
		else{
				throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* アルファにおける(1)式の計算結果を返します。
* @param fVi 実際の選択項目の合前提性
* @param gVi 実際の選択項目の合目標性
* @param fVj 選択を行わなかった選択可能項目の合前提性
* @param gVj 選択を行わなかった選択可能項目の合目標性
* @param k 象限
* @return 計算結果
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getDiscriminantOneBeta(double fVi, double gVi, double fVj, double gVj, int k)
*/
	public double getDiscriminantOneAlpha(double fVi, double gVi, double fVj, double gVj, int k){
		
		//kが正しい範囲か
		if(inQuadrant(k)){
			
			double sa = getSAlpha(k);
			double sb = getSBeta(k);
			return fVi - sa * sb * gVi - fVj + sa * sb * gVj;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* アルファにおける(2)式の計算結果を返します。
* @param vi 実際の選択項目
* @param vj 選択を行わなかった選択可能項目
* @param k 象限
* @return 計算結果
* @exception NotItemException 指定した項目が存在しない場合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @exception IllegalRelationValuesException 実際に選択された項目と選択可能項目の関係が異なる場合
* @see #getDiscriminantTwoBeta(int vi, int vj, int k)
*/
	public double getDiscriminantTwoAlpha(int vi, int vj, int k){
		if(matrix.isRowNumber(vi)){
			if(matrix.isRowNumber(vj)){
				if(isNomalChoice(vi,vj)){
					//kが正しい範囲か
					if(inQuadrant(k)){
						
						int v = getBeforeItem(vi);
						if(isDummy()){		//仮想項目のある場合
							vi = vi + 1;
							vj = vj + 1;
						}
					
						return getDiscriminantTwoAlpha(getF(v, vi), getG(v, vi), getF(v, vj), getG(v, vj), k);
					}
					else{
						throw new ValueFormatException("quadrant(" + k + ")");
					}
				}
				else{
					throw new IllegalRelationValuesException("relation(" + vi + "," + vj + ")");
				}
			}
			else{
				throw new NotItemException("vj("+ vj+")");
			}
		}
		else{
				throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* アルファにおける(2)式の計算結果を返します。
* @param fVi 実際の選択項目の合前提性
* @param gVi 実際の選択項目の合目標性
* @param fVj 選択を行わなかった選択可能項目の合前提性
* @param gVj 選択を行わなかった選択可能項目の合目標性
* @param k 象限
* @return 計算結果
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getDiscriminantTwoBeta(double fVi, double gVi, double fVj, double gVj, int k)
*/
	public double getDiscriminantTwoAlpha(double fVi, double gVi, double fVj, double gVj, int k){
		
		//kが正しい範囲か
		if(inQuadrant(k)){
			
			double sb = getSBeta(k);
			return sb * gVj - sb * gVi;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* アルファにおける(2)式 / (1)式の計算結果を返します。
* (1)式が0の場合は0を返します。
* @param vi 実際の選択項目
* @param vj 選択を行わなかった選択可能項目
* @param k 象限
* @return 計算結果
* @exception NotItemException 指定した項目が存在しない場合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @exception IllegalRelationValuesException 実際に選択された項目と選択可能項目の関係が異なる場合
* @see #getDiscriminantBeta(int vi, int vj, int k)
*/
	public double getDiscriminantAlpha(int vi, int vj, int k){
		if(matrix.isRowNumber(vi)){
			if(matrix.isRowNumber(vj)){
				if(isNomalChoice(vi,vj)){
					//kが正しい範囲か
					if(inQuadrant(k)){
						
						int v = getBeforeItem(vi);
						if(isDummy()){		//仮想項目のある場合
							vi = vi + 1;
							vj = vj + 1;
						}
						
						return getDiscriminantAlpha(getF(v, vi), getG(v, vi), getF(v, vj), getG(v, vj), k);
					}
					else{
						throw new ValueFormatException("quadrant(" + k + ")");
					}
				}
				else{
					throw new IllegalRelationValuesException("relation(" + vi + "," + vj + ")");
				}
			}
			else{
				throw new NotItemException("vj("+ vj+")");
			}
		}
		else{
				throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* アルファにおける(2)式 / (1)式の計算結果を返します。
* (1)式が0の場合は0を返します。
* @param fVi 実際の選択項目の合前提性
* @param gVi 実際の選択項目の合目標性
* @param fVj 選択を行わなかった選択可能項目の合前提性
* @param gVj 選択を行わなかった選択可能項目の合目標性
* @param k 象限
* @return 計算結果
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getDiscriminantBeta(double fVi, double gVi, double fVj, double gVj, int k)
*/
	public double getDiscriminantAlpha(double fVi, double gVi, double fVj, double gVj, int k){
		
		//kが正しい範囲か
		if(inQuadrant(k)){
			
			if(getDiscriminantOneAlpha(fVi, gVi, fVj, gVj, k) != 0){
				return getDiscriminantTwoAlpha(fVi, gVi, fVj, gVj, k) / getDiscriminantOneAlpha(fVi, gVi, fVj, gVj, k);
			}
			else{
				return 0;
			}
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ベータにおける(1)式の計算結果を返します。
* @param vi 実際の選択項目
* @param vj 選択を行わなかった選択可能項目
* @param k 象限
* @return 計算結果
* @exception NotItemException 指定した項目が存在しない場合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @exception IllegalRelationValuesException 実際に選択された項目と選択可能項目の関係が異なる場合
* @see #getDiscriminantOneAlpha(int vi, int vj, int k)
*/
	public double getDiscriminantOneBeta(int vi, int vj, int k){
		if(matrix.isRowNumber(vi)){
			if(matrix.isRowNumber(vj)){
				if(isNomalChoice(vi,vj)){
				
					//kが正しい範囲か
					if(inQuadrant(k)){
						
						int v = getBeforeItem(vi);
						if(isDummy()){		//仮想項目のある場合
							vi = vi + 1;
							vj = vj + 1;
						}
						
						return getDiscriminantOneBeta(getF(v, vi), getG(v, vi), getF(v, vj), getG(v, vj), k);
					}
					else{
						throw new ValueFormatException("quadrant(" + k + ")");
					}
				}
				else{
					throw new IllegalRelationValuesException("relation(" + vi + "," + vj + ")");
				}
			}
			else{
				throw new NotItemException("vj("+ vj+")");
			}
		}
		else{
				throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* ベータにおける(1)式の計算結果を返します。
* @param fVi 実際の選択項目の合前提性
* @param gVi 実際の選択項目の合目標性
* @param fVj 選択を行わなかった選択可能項目の合前提性
* @param gVj 選択を行わなかった選択可能項目の合目標性
* @param k 象限
* @return 計算結果
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getDiscriminantOneAlpha(double fVi, double gVi, double fVj, double gVj, int k)
*/
	public double getDiscriminantOneBeta(double fVi, double gVi, double fVj, double gVj, int k){
		
		//kが正しい範囲か
		if(inQuadrant(k)){
			
			double sa = getSAlpha(k);
			double sb = getSBeta(k);
			return gVi - sa * sb * fVi - gVj + sa * sb * fVj;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ベータにおける(2)式の計算結果を返します。
* @param vi 実際の選択項目
* @param vj 選択を行わなかった選択可能項目
* @param k 象限
* @return 計算結果
* @exception NotItemException 指定した項目が存在しない場合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @exception IllegalRelationValuesException 実際に選択された項目と選択可能項目の関係が異なる場合
* @see #getDiscriminantTwoAlpha(int vi, int vj, int k)
*/
	public double getDiscriminantTwoBeta(int vi, int vj, int k){
		if(matrix.isRowNumber(vi)){
			if(matrix.isRowNumber(vj)){
				if(isNomalChoice(vi,vj)){
					//kが正しい範囲か
					if(inQuadrant(k)){
						
						int v = getBeforeItem(vi);
						if(isDummy()){		//仮想項目のある場合
							vi = vi + 1;
							vj = vj + 1;
						}
					
						return getDiscriminantTwoBeta(getF(v, vi), getG(v, vi), getF(v, vj), getG(v, vj), k);
					}
					else{
						throw new ValueFormatException("quadrant(" + k + ")");
					}
				}
				else{
					throw new IllegalRelationValuesException("relation(" + vi + "," + vj + ")");
				}
			}
			else{
				throw new NotItemException("vj("+ vj+")");
			}
		}
		else{
				throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* ベータにおける(2)式の計算結果を返します。
* @param fVi 実際の選択項目の合前提性
* @param gVi 実際の選択項目の合目標性
* @param fVj 選択を行わなかった選択可能項目の合前提性
* @param gVj 選択を行わなかった選択可能項目の合目標性
* @param k 象限
* @return 計算結果
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getDiscriminantTwoAlpha(double fVi, double gVi, double fVj, double gVj, int k)
*/
	public double getDiscriminantTwoBeta(double fVi, double gVi, double fVj, double gVj, int k){
		
		//kが正しい範囲か
		if(inQuadrant(k)){
			
			double sa = getSAlpha(k);
			return sa * fVj - sa * fVi;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* ベータにおける(2)式 / (1)式の計算結果を返します。
* (1)式が0の場合は0を返します。
* @param vi 実際の選択項目
* @param vj 選択を行わなかった選択可能項目
* @param k 象限
* @return 計算結果
* @exception NotItemException 指定した項目が存在しない場合
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @exception IllegalRelationValuesException 実際に選択された項目と選択可能項目の関係が異なる場合
* @see #getDiscriminantAlpha(int vi, int vj, int k)
*/
	public double getDiscriminantBeta(int vi, int vj, int k){
		if(matrix.isRowNumber(vi)){
			if(matrix.isRowNumber(vj)){
				if(isNomalChoice(vi,vj)){
					//kが正しい範囲か
					if(inQuadrant(k)){
						
						int v = getBeforeItem(vi);
						if(isDummy()){		//仮想項目のある場合
							vi = vi + 1;
							vj = vj + 1;
						}
						
						return getDiscriminantBeta(getF(v, vi), getG(v, vi), getF(v, vj), getG(v, vj), k);
					}
					else{
						throw new ValueFormatException("quadrant(" + k + ")");
					}
				}
				else{
					throw new IllegalRelationValuesException("relation(" + vi + "," + vj + ")");
				}
			}
			else{
				throw new NotItemException("vj("+ vj+")");
			}
		}
		else{
				throw new NotItemException("vi("+ vi+")");
		}
	}
	
/**
* ベータにおける(2)式 / (1)式の計算結果を返します。
* (1)式が0の場合は0を返します。
* @param fVi 実際の選択項目の合前提性
* @param gVi 実際の選択項目の合目標性
* @param fVj 選択を行わなかった選択可能項目の合前提性
* @param gVj 選択を行わなかった選択可能項目の合目標性
* @param k 象限
* @return 計算結果
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getDiscriminantAlpha(double fVi, double gVi, double fVj, double gVj, int k)
*/
	public double getDiscriminantBeta(double fVi, double gVi, double fVj, double gVj, int k){
		
		//kが正しい範囲か
		if(inQuadrant(k)){
			
			if(getDiscriminantOneBeta(fVi, gVi, fVj, gVj, k) != 0){
				return getDiscriminantTwoBeta(fVi, gVi, fVj, gVj, k) / getDiscriminantOneBeta(fVi, gVi, fVj, gVj, k);
			}
			else{
				return 0;
			}
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* 指定された象限の値からs_aの値を返します。
* @param k 象限
* @return s_aの値
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getSBeta(int k)
*/
	private double getSAlpha(int k){
		
		//kが正しい範囲か
		if(inQuadrant(k)){
			
			double value;
			if(k == 1 || k == 4){
				value = 1.0;
			}
			else{
				value = -1.0;
			}
			return value;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* 指定された象限の値からs_bの値を返します。
* @param k 象限
* @return s_bの値
* @exception ValueFormatException 指定した象限が取りえない値であった場合
* @see #getSAlpha(int k)
*/
	private double getSBeta(int k){
		
		//kが正しい範囲か
		if(inQuadrant(k)){
		
			double value;
			if(k == 1 || k == 2){
				value = 1.0;
			}
			else{
				value = -1.0;
			}
			return value;
		}
		else{
			throw new ValueFormatException("quadrant(" + k + ")");
		}
	}
	
/**
* (1)式 = 0 かつ (2)式 > 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ (2)式/(1)式 > 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionZeroPlusPlusOut(double expression){
		return new Range();
	}
	
/**
* (1)式 = 0 かつ (2)式 > 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ 0<= (2)式/(1)式 <= 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionZeroPlusPlusIn(double expression){
		return new Range();
	}
	
/**
* (1)式 = 0 かつ (2)式 > 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ (2)式/(1)式 < -1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionZeroPlusMinusOut(double expression){
		return new Range();
	}
	
/**
* (1)式 = 0 かつ (2)式 > 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ -1 <= (2)式/(1)式 <= 0
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionZeroPlusMinusIn(double expression){
		return new Range();
	}
	
/**
* (1)式 = 0 かつ (2)式 <= 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ (2)式/(1)式 > 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionZeroMinusPlusOut(double expression){
		return new Range( 0.0, 1.0, true, true);
	}
	
/**
* (1)式 = 0 かつ (2)式 <= 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ 0 <= (2)式/(1)式 <= 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionZeroMinusPlusIn(double expression){
		return new Range( 0.0, 1.0, true, true);
	}
	
/**
* (1)式 = 0 かつ (2)式 <= 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ (2)式/(1)式 < -1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionZeroMinusMinusOut(double expression){
		return new Range( -1.0, 0.0, true, false);
	}
	
/**
* (1)式 = 0 かつ (2)式 <= 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ -1<= (2)式/(1)式 <= 0
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionZeroMinusMinusIn(double expression){
		return new Range( -1.0, 0.0, true, false);
	}
	
/**
* (1)式 > 0 かつ (2)式 >= 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ (2)式/(1)式 > 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusPlusPlusOut(double expression){
		return new Range();
	}
	
/**
* (1)式 > 0 かつ (2)式 >= 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ 0<= (2)式/(1)式 <= 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusPlusPlusIn(double expression){
		return new Range( expression, 1.0, true, true);
	}
	
/**
* (1)式 > 0 かつ (2)式 >= 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ (2)式/(1)式 < -1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusPlusMinusOut(double expression){
		return new Range();
	}
	
/**
* (1)式 > 0 かつ (2)式 >= 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ -1<= (2)式/(1)式 < 0
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusPlusMinusIn(double expression){
		return new Range();
	}
	
/**
* (1)式 > 0 かつ (2)式 >= 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ (2)式/(1)式 = 0
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusPlusMinusZero(double expression){
		return new Range( 0.0, 0.0, true, true);
	}
	
/**
* (1)式 > 0 かつ (2)式 < 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ (2)式/(1)式 > 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusMinusPlusOut(double expression){
		return new Range( 0.0, 1.0, true, true);
	}
	
/**
* (1)式 > 0 かつ (2)式 < 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ 0<= (2)式/(1)式 <= 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusMinusPlusIn(double expression){
		return new Range( 0.0, 1.0, true, true);
	}
	
/**
* (1)式 > 0 かつ (2)式 < 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ (2)式/(1)式 <= -1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusMinusMinusOut(double expression){
		return new Range( -1.0, 0.0, true, true);
	}
	
/**
* (1)式 > 0 かつ (2)式 < 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ -1 < (2)式/(1)式 <= 0
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionPlusMinusMinusIn(double expression){
		return new Range( expression, 0.0, true, true);
	}
	
/**
* (1)式 < 0 かつ (2)式 >= 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ (2)式/(1)式 > 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusPlusPlusOut(double expression){
		return new Range();
	}
	
/**
* (1)式 < 0 かつ (2)式 >= 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ 0< (2)式/(1)式 <= 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusPlusPlusIn(double expression){
		return new Range();
	}
	
/**
* (1)式 < 0 かつ (2)式 >= 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ (2)式/(1)式 = 0
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusPlusPlusZero(double expression){
		return new Range( 0.0, 0.0, true, true);
	}
	
/**
* (1)式 < 0 かつ (2)式 >= 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ (2)式/(1)式 < -1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusPlusMinusOut(double expression){
		return new Range();
	}
	
/**
* (1)式 < 0 かつ (2)式 >= 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ -1 <= (2)式/(1)式 <= 0
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusPlusMinusIn(double expression){
		return new Range( -1.0, expression, true, true);
	}
	
/**
* (1)式 < 0 かつ (2)式 < 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ (2)式/(1)式 > 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusMinusPlusOut(double expression){
		return new Range( 0.0, 1.0, true, true);
	}
	
/**
* (1)式 < 0 かつ (2)式 < 0 で、
* アルファの場合第1または4象限、ベータの場合第1または2象限 かつ 0<= (2)式/(1)式 <= 1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusMinusPlusIn(double expression){
		return new Range( 0.0, expression, true, true);
	}
	
/**
* (1)式 < 0 かつ (2)式 < 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ (2)式/(1)式 < -1
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusMinusMinusOut(double expression){
		return new Range( -1.0, 0.0, true, true);
	}
	
/**
* (1)式 < 0 かつ (2)式 < 0 で、
* アルファの場合第2または3象限、ベータの場合第3または4象限 かつ -1 <= (2)式/(1)式 <= 0
* のときの推定した区間を返します。
* @param expression (2)式 / (1)式の答え
* @return 推定した区間
*/
	private Range calPresumptionMinusMinusMinusIn(double expression){
		return new Range( -1.0, 0.0, true, true);
	}
	
/**
* 系列を設定します。
* @param preSequence 設定する系列
* @exception DisagreementSequenceSizeException すでに設定されているマトリクスとSequenceのサイズが一致しない場合
*/
	public void setSequence(Sequence preSequence){
		if(isSameSize(matrix, preSequence)){
			series.sequenceCopy(preSequence);
		}
		else{
			throw new DisagreementSequenceSizeException();
		}
	}
	
/**
* 隣接マトリクスを設定します。
* @param graph 設定する隣接マトリクス
* @exception NotSquareMatrixException 設定したマトリクスが正方行列ではない場合
*/
	private void setGraph(ArithmeticMatrix graph){
		if(graph.isSquare()){
			matrix.matrixCopy(graph);
		}
		else{
			throw new NotSquareMatrixException();
		}
	}
	
/**
* 象限が正しい範囲かチェックします。
* @param k 調べる象限
* @return 正しい範囲であれば true
*/
	private boolean inQuadrant(int k){
		return 1 <= k && k <= 4;
	}
	
/**
* 選択項目からその時の選択可能項目を返します。
* 結果はサイズが要素数(仮想項目なし)のboolean型の配列で返します。
* 選択項目自身は true として返されます。
* @param item 選択項目
* @return 検索結果の配列
* @exception NotItemException 指定した項目が存在しなかった場合
*/
	public boolean[] getReachElement(int item){
		if(matrix.isRowNumber(item)){
			return super.getReachElement(getItemReachMatrix(item, matrix.getReachMatrix()));
		}
		else{
			throw new NotItemException("item("+ item+")");
		}
	}
	
/**
* 可到達マトリクスを指定した選択項目を選んだ時の可到達マトリクスの構造にして返します。
* 初期選択項目を指定した場合は指定した可到達マトリクスと同じものが返されます。
* @param item 選択項目
* @param reachMatrix 可到達マトリクス
* @return 構造を変えた可到達マトリクス
* @exception NotItemException 指定した項目が存在しなかった場合
*/
	private ArithmeticMatrix getItemReachMatrix(int item, ArithmeticMatrix reachMatrix){
		if(matrix.isRowNumber(item)){
			for(int i = 0; series.getItem(i) != item && i < reachMatrix.getRowLength(); i++){
			
				//構造から除外する
				for(int j = 0; j < reachMatrix.getColLength(); j++){
					reachMatrix.setCell(series.getItem(i), j, 0);
				}
			}
			
			return reachMatrix;
		}
		else{
			throw new NotItemException("item("+ item+")");
		}
	}
/**
* 選択項目と選択可能項目の関係があっているかチェックします。
* @param v 選択項目
* @param vi 選択可能項目
* @return 関係が正しければ true
* @exception NotItemException 指定した項目が存在しない場合
*/
	private boolean isNomalChoice(int v, int vi){
		if(matrix.isRowNumber(v)){
			if(matrix.isRowNumber(vi)){
				boolean[] el = new boolean[series.getLength()];
				
				//選択可能項目を持ってくる
				System.arraycopy(getReachElement(v), 0, el, 0, series.getLength());
				
				return el[vi];
			}
			else{
				throw new NotItemException("vi("+ vi+")");
			}
		}
		else{
				throw new NotItemException("v("+ v+")");
		}
	}
	
/**
* 指定した隣接マトリクスとSequenceのサイズが一致するかチェックします。
* @param mat 隣接マトリクス
* @param seq 指定したSequence
* @return サイズが一致すれば true
*/
	private boolean isSameSize(ArithmeticMatrix mat, Sequence seq){
		return mat.getRowLength() == seq.getLength() && mat.getColLength() == seq.getLength();
	}
	
}