<commit_before>/*******************************************************************************
 * Copyright (c) 2013 See AUTHORS file.
 * 
 * This file is part of SleepFighter.
 * 
 * SleepFighter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * SleepFighter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with SleepFighter. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package se.chalmers.dat255.sleepfighter.challenge.math;

import java.util.Random;

import org.apache.commons.math3.linear.DecompositionSolver;
import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.RealVector;

import se.chalmers.dat255.sleepfighter.utils.debug.Debug;
import se.chalmers.dat255.sleepfighter.utils.math.MatrixUtil;
import android.content.Context;

import com.google.common.math.DoubleMath;

/*
 * Challenge: Solve a system of linear equations with three variables.
 * For the system of linear equations Ax = b, where x = (x1 x2 x3), the user is to solve
 * for either x1 or x2(just solving for x3 is too easy). 
 * The systems of linear equations generated by this class, have an unique solution, 
 * and are thus trivially solved using Gaussian elimination. 
 */
public class LinearEquationProblem implements MathProblem {
	
	private final Context context;
	
	// we use a 3x3 coefficent matrix.
	private static final int MATRIX_SIZE = 3;
	
	private int solution;
	
	private String renderedString;
	
	private Random rng = new Random();
	
	// The coefficient-matrix. 
	private RealMatrix A;
	
	// The constant vector b.
	private RealVector b;
	
	private int variableToSolveFor;
	
	public String render() {
		return this.renderedString;
	}
	
	public int solution() {
		return this.solution;
	}
	
	// Create A
	RealMatrix createCoefficients() {
		return MatrixUtil.createRandomMatrix(rng, MATRIX_SIZE, -8, 16, true);
	}
	
	// create b
	RealVector createConstantVector() {
		// 20, 60
		return MatrixUtil.createRandomVector(rng, MATRIX_SIZE, 25, 60, true);
	}
	
	public void newProblem() {
		
		generateProblem();
		Debug.d("coeff: " + this.A);
		Debug.d("constants: " + this.b);
		Debug.d("variable: " + this.variableToSolveFor);
		Debug.d("solution: " + this.solution);

		// now render the problem
		doRender();
		Debug.d("rendered problem: " + this.renderedString);

	}
	
	// find a system of linear equations with a real solution(because real solutions are easy to input on the android keyboard)
	private void generateProblem() {
		
		// We want to generate a system of linear equations Ax = b(where x = (x1 x2 x3)).
		// We'll cache the LU-decomposition of the coefficient-matrix A, and then keep on 
		// generating a constant vector b until we got a real solution for either x1 or y2.
		this.A = createCoefficients();
		DecompositionSolver ALU = new LUDecomposition(this.A).getSolver();
		
		int attempts = 0;
		
		boolean foundb = false;
		do { 
			
			Debug.d("try again");
			
			// if after 40 attempts we still can't find a good constants vector, we should give up on this 
			// coefficient matrix and try creating a new one.
			if(attempts == 20) {
				this.A = createCoefficients();
				ALU = new LUDecomposition(this.A).getSolver();
				attempts = 0;
			}
		
			this.b = this.createConstantVector();
			RealVector vsolution = MatrixUtil.solveLinearEquationSystem(ALU, b);
			
			// x1, x2, and x3 must all be integers. 
			if(!(isInteger(vsolution.getEntry(0)) &&
					isInteger(vsolution.getEntry(1)) &&
					isInteger(vsolution.getEntry(2))) ) {
				attempts++;
				continue;
			}
			
			// TODO: ensure the solutions aren't too big.
			
			this.variableToSolveFor = -1;
			
			if(!isBoringSolution((int)vsolution.getEntry(0))) {
				Debug.d("found solution x");
				this.variableToSolveFor = 0;
				
			} else if(!isBoringSolution((int)vsolution.getEntry(1))) {
				Debug.d("found solution y");
				this.variableToSolveFor = 1;
			}

			if(this.variableToSolveFor != -1) {
				foundb = true;
				Debug.d("soluton: " + vsolution); 
				this.solution = (int)vsolution.getEntry(this.variableToSolveFor);
			}
			
			attempts++;
			
		} while(!foundb);
	}
	
	// boring solutions are solution that are small, boring numbers like 1 and 2. 
	// We will not allow boring solutions!
	private static boolean isBoringSolution(int solution) {
		return solution == 0 || Math.abs(solution) == 1 || Math.abs(solution) == 2;<commit_msg>Made the generation of equation systems faster.<commit_after>/*******************************************************************************
 * Copyright (c) 2013 See AUTHORS file.
 * 
 * This file is part of SleepFighter.
 * 
 * SleepFighter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * SleepFighter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with SleepFighter. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package se.chalmers.dat255.sleepfighter.challenge.math;

import java.util.Random;

import org.apache.commons.math3.linear.ArrayRealVector;
import org.apache.commons.math3.linear.DecompositionSolver;
import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.RealVector;

import se.chalmers.dat255.sleepfighter.utils.debug.Debug;
import se.chalmers.dat255.sleepfighter.utils.math.MatrixUtil;
import android.content.Context;

import com.google.common.math.DoubleMath;

/*
 * Challenge: Solve a system of linear equations with three variables.
 * For the system of linear equations Ax = b, where x = (x1 x2 x3), the user is to solve
 * for either x1 or x2(just solving for x3 is too easy). 
 * The systems of linear equations generated by this class, have an unique solution, 
 * and are thus trivially solved using Gaussian elimination. 
 */
public class LinearEquationProblem implements MathProblem {
	
	private final Context context;
	
	// we use a 3x3 coefficent matrix.
	private static final int MATRIX_SIZE = 3;
	
	private int solution;
	
	private String renderedString;
	
	private Random rng = new Random();
	
	// The coefficient-matrix. 
	private RealMatrix A;
	
	// The constant vector b.
	private RealVector b;
	
	private int variableToSolveFor;
	
	public String render() {
		return this.renderedString;
	}
	
	public int solution() {
		return this.solution;
	}
	
	// Create A
	private RealMatrix createCoefficients() {
		return MatrixUtil.createRandomMatrix(rng, MATRIX_SIZE, -5, 16, true);
	}
	
	// create the solution vector
	private RealVector createSolutionVector() {
		RealVector s;
		do {
			s = MatrixUtil.createRandomVector(rng, MATRIX_SIZE, -10, 10, true);
		} while(isBoringSolution(s));

		return s;
	}
	
	public void newProblem() {
		
		generateProblem();
		Debug.d("coeff: " + this.A);
		Debug.d("solution: " + this.solution);
		Debug.d("constants: " + this.b);

		// now render the problem
		doRender();
		Debug.d("rendered problem: " + this.renderedString);

	}
	
	// find a system of linear equations with a real solution(because real solutions are easy to input on the android keyboard)
	private void generateProblem() {
		
		this.A = createCoefficients();
		
		int attempts = 0;
		RealVector solution;
		boolean foundb = false;
		do { 
			
			Debug.d("try again");
			
			// if after 40 attempts we still can't find a good constants vector, we should give up on this 
			// coefficient matrix and try creating a new one.
			if(attempts == 40) {
				Debug.d("new coefficients matrix");
				
				this.A = createCoefficients();
				attempts = 0;
			}
			
			// Generate a solution.
			solution = this.createSolutionVector();
			
			// Now compute Ax = b(where x is the solution)
			this.b = multiply(this.A, solution);
			
			// does b satisfy our requirements?
			if(isGoodb(b)) {
				foundb = true;
			}
			
			attempts++;
			
		} while(!foundb);
		
		Debug.d("solution: " + solution.toString());
		
		// solve for either x1 or x2
		this.variableToSolveFor = rng.nextBoolean() ? 0 : 1;
		this.solution = (int)solution.getEntry(this.variableToSolveFor);
	}
	
	// multiply a 3x3 matrix by a 3 vector
	private static RealVector multiply(RealMatrix matrix, RealVector vector) {
		
		double[] m1 = matrix.getRow(0);
		double[] m2 = matrix.getRow(1);
		double[] m3 = matrix.getRow(2);
		
		double[] v = vector.toArray();
		
		
		return new ArrayRealVector(new double[]{
				m1[0] * v[0] + m1[1] * v[1] + m1[2] * v[2],
				m2[0] * v[0] + m2[1] * v[1] + m2[2] * v[2],
				m3[0] * v[0] + m3[1] * v[1] + m3[2] * v[2],
				
		});
	}
	
	// ensure that b isn't too big or too little
	private static boolean isGoodb(RealVector b) {
		final int MIN = -20;
		final int MAX = 59;
		
		return ((int)b.getEntry(0) > MIN && (int)b.getEntry(0) < MAX) &&
				 ((int)b.getEntry(1) > MIN && (int)b.getEntry(1) < MAX) && 
				 ((int)b.getEntry(2) > MIN && (int)b.getEntry(2) < MAX);
	}
	
	// boring solutions are solution that are small, boring numbers like 1 and 2. 
	// We will not allow boring solutions!
	private static boolean isBoringSolution(int solution) {
		return solution == 0 || Math.abs(solution) == 1 || Math.abs(solution) == 2;
	}
	
	private static boolean isBoringSolution(RealVector v) {
		return isBoringSolution((int)v.getEntry(0)) ||
				isBoringSolution((int)v.getEntry(1)) ||
				isBoringSolution((int)v.getEntry(2));
				
{'fraction_non_alphanumeric': 0.13504885363258198, 'fraction_numerical': 0.015962077972332397, 'mean_word_length': 3.609005795809184, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '4158510', 'n_tokens_mistral': 3633, 'n_tokens_neox': 3028, 'n_words': 1022}