<commit_before><?php
/*
	Kemeny-Young part of the Condorcet PHP Class

	Last modified at: Condorcet Class v0.14

	By <NAME> - MIT LICENSE (Please read LICENSE.txt)
	https://github.com/julien-boudry/Condorcet_Schulze-PHP_Class
*/

namespace Condorcet ;

// Note : This class use some configuration method preset at the bottom of this file.

// Kemeny-Young is a Condorcet Algorithm | http://en.wikipedia.org/wiki/Kemeny%E2%80%93Young_method
class KemenyYoung implements namespace\Condorcet_Algo
{
	// Limits
	public static $_maxCandidates = 6 ; // Beyond, and for the performance of PHP on recursive functions, it would be folly for this implementation.

		public static function setMaxCandidates ($max)
		{
			if (is_int($max))
			{
				self::$_maxCandidates = $max ;
			}
		}

	// Config
	protected $_Pairwise ;
	protected $_CandidatesCount ;
	protected $_Candidates ;

	// Kemeny Young
	protected $_PossibleRanking ;
	protected $_RankingScore ;
	protected $_Result ;


	public function __construct (array $config)
	{
		$this->_Pairwise = $config['_Pairwise'] ;
		$this->_CandidatesCount = $config['_CandidatesCount'] ;
		$this->_Candidates = $config['_Candidates'] ;

		if ($this->_CandidatesCount > self::$_maxCandidates)
		{
			throw new namespace\CondorcetException(101,self::$_maxCandidates) ;
		}
	}


/////////// PUBLIC ///////////


	// Get the Kemeny ranking
	public function getResult ($options = null)
	{
		// Cache
		if ( $this->_Result === null )
		{
			$this->calcPossibleRanking();
			$this->calcRankingScore();
			$this->makeRanking();
		}

		if (!is_null($options) && isset($options['noConflict']) && $options['noConflict'] === true)
		{
			$conflicts = $this->conflictInfos() ;
			if ( $conflicts !== false)
			{
				return $this->conflictInfos() ;
			}
		}

		// Return
		return $this->_Result ;
	}


	public function getStats ()
	{
		$this->getResult();

			//////

		$explicit = array() ;

		foreach ($this->_PossibleRanking as $key => $value)
		{
			$explicit[$key] = $value ;

			// Human readable
			foreach ($explicit[$key] as &$candidate_key)
			{
				$candidate_key = namespace\Condorcet::getStatic_CandidateId($candidate_key, $this->_Candidates);
			}

			$explicit[$key]['score'] = $this->_RankingScore[$key] ;
		}

		return $explicit ;
	}

		protected function conflictInfos ()
		{
			$max = max($this->_RankingScore) ;

			$conflict = -1 ;
			foreach ($this->_RankingScore as $value)
			{
				if ($value === $max)
				{
					$conflict++ ;
				}
			}

			if ($conflict === 0) 
				{return false ;}
			else
			{
				return ($conflict + 1).';'.max($this->_RankingScore) ;
			}
		}


/////////// COMPUTE ///////////


	//:: Kemeny-Young ALGORITHM. :://

	protected function calcPossibleRanking ()
	{
		$this->_PossibleRanking = array() ;

		$arrangements = $this->calcPermutation($this->_CandidatesCount);
		
		$i_arrangement = 1 ;
		foreach ($this->_Candidates as $CandidateId => $CandidateName)
		{
			$start = $i_arrangement ;

			// Create the possible and the first place

			for ($i = 1 ; $i <= ($arrangements / $this->_CandidatesCount) ; $i++)
			{
				// Less clean than to start the recursion from the beginning, but really much faster, and that from 4 candidates!
				$this->_PossibleRanking[$i_arrangement][1] = $CandidateId ;

				// Prepare empty arrays
				for ($ir = 2 ; $ir <= $this->_CandidatesCount ; $ir++ )
				{
					$this->_PossibleRanking[$i_arrangement][$ir] = null ;
				}

				$i_arrangement++ ;
			}

			// Recursive function to populate rank 2 to x rank.
			$this->rPossibleRanking($start, $i_arrangement - 1) ;
		}<commit_msg>Kemeny-Young : Using new cache<commit_after><?php
/*
	Kemeny-Young part of the Condorcet PHP Class

	Last modified at: Condorcet Class v0.14

	By <NAME> - MIT LICENSE (Please read LICENSE.txt)
	https://github.com/julien-boudry/Condorcet_Schulze-PHP_Class
*/

namespace Condorcet ;

// Note : This class use some configuration method preset at the bottom of this file.

// Kemeny-Young is a Condorcet Algorithm | http://en.wikipedia.org/wiki/Kemeny%E2%80%93Young_method
class KemenyYoung implements namespace\Condorcet_Algo
{
	// Limits
	public static $_maxCandidates = 6 ; // Beyond, and for the performance of PHP on recursive functions, it would be folly for this implementation.

		public static function setMaxCandidates ($max)
		{
			if (is_int($max))
			{
				self::$_maxCandidates = $max ;
			}
		}

	// Config
	protected $_Pairwise ;
	protected $_CandidatesCount ;
	protected $_Candidates ;

	// Kemeny Young
	protected $_PossibleRanking ;
	protected $_RankingScore ;
	protected $_Result ;


	public function __construct (array $config)
	{
		$this->_Pairwise = $config['_Pairwise'] ;
		$this->_CandidatesCount = $config['_CandidatesCount'] ;
		$this->_Candidates = $config['_Candidates'] ;

		if ($this->_CandidatesCount > self::$_maxCandidates)
		{
			throw new namespace\CondorcetException(101,self::$_maxCandidates) ;
		}
	}


/////////// PUBLIC ///////////


	// Get the Kemeny ranking
	public function getResult ($options = null)
	{
		// Cache
		if ( $this->_Result === null )
		{
			$this->calcPossibleRanking();
			$this->calcRankingScore();
			$this->makeRanking();
		}

		if (!is_null($options) && isset($options['noConflict']) && $options['noConflict'] === true)
		{
			$conflicts = $this->conflictInfos() ;
			if ( $conflicts !== false)
			{
				return $this->conflictInfos() ;
			}
		}

		// Return
		return $this->_Result ;
	}


	public function getStats ()
	{
		$this->getResult();

			//////

		$explicit = array() ;

		foreach ($this->_PossibleRanking as $key => $value)
		{
			$explicit[$key] = $value ;

			// Human readable
			foreach ($explicit[$key] as &$candidate_key)
			{
				$candidate_key = namespace\Condorcet::getStatic_CandidateId($candidate_key, $this->_Candidates);
			}

			$explicit[$key]['score'] = $this->_RankingScore[$key] ;
		}

		return $explicit ;
	}

		protected function conflictInfos ()
		{
			$max = max($this->_RankingScore) ;

			$conflict = -1 ;
			foreach ($this->_RankingScore as $value)
			{
				if ($value === $max)
				{
					$conflict++ ;
				}
			}

			if ($conflict === 0) 
				{return false ;}
			else
			{
				return ($conflict + 1).';'.max($this->_RankingScore) ;
			}
		}


/////////// COMPUTE ///////////


	//:: Kemeny-Young ALGORITHM. :://

	protected function calcPossibleRanking ()
	{
		$path = __DIR__ . '/KemenyYoung-Data/'.$this->_CandidatesCount.'.data' ;

		// But ... where are the data ?! Okay, old way now...
		if (!file_exists($path))
			{ $this->doPossibleRanking(); return ; }

		$this->_PossibleRanking = unserialize(file_get_contents($path));

		$i = 0 ;
		foreach ($this->_Candidates as $candidate_id => $candidate_name)
		{
			$identity = 'C'.$i;

			foreach ($this->_PossibleRanking as &$onePossibleRanking)
			{
				$onePossibleRanking = str_replace($identity, $candidate_id, $onePossibleRanking);
			}

			$i++;
		}
	}

	protected function doPossibleRanking ()
	{
		$this->_PossibleRanking = array() ;

		$arrangements = $this->calcPermutation($this->_CandidatesCount);
		
		$i_arrangement = 1 ;
		foreach ($this->_Candidates as $CandidateId => $CandidateName)
		{
			$start = $i_arrangement ;

			// Create the possible and the first place

			for ($i = 1 ; $i <= ($arrangements / $this->_CandidatesCount) ; $i++)
			{
				// Less clean than to start the recursion from the beginning, but really much faster, and that from 4 candidates!
				$this->_PossibleRanking[$i_arrangement][1] = $CandidateId ;

				// Prepare empty arrays
				for ($ir = 2 ; $ir <= $this->_CandidatesCount ; $ir++)
				{
					$this->_PossibleRanking[$i_arrangement][$ir] = null ;
				}

				$i_arrangement++ ;
			}

			// Recursive function to populate rank 2 to x rank.
			$this->rPossibleRanking($start, $i_arrangement - 1) ;
		}
{'fraction_non_alphanumeric': 0.1577323563440031, 'fraction_numerical': 0.005784805244890089, 'mean_word_length': 3.182795698924731, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 71, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1878367', 'n_tokens_mistral': 3136, 'n_tokens_neox': 2588, 'n_words': 584}