package recunn.datasets;


import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import recunn.datastructs.DataSequence;
import recunn.datastructs.DataSet;
import recunn.datastructs.DataStep;
import recunn.loss.LossArgMax;
import recunn.loss.LossSoftmax;
import recunn.model.LinearUnit;
import recunn.model.Model;
import recunn.model.Nonlinearity;

/*
 * Based on https://research.facebook.com/researchers/1543934539189348
*/

public class bAbI extends DataSet{
	
	public static void main(String[] args) throws Exception {
		System.out.println("testing...");
		
		Random rng = new Random();
		bAbI data = new bAbI(3, 100, true, rng);
		
		System.out.println("done.");
	}
	
	public bAbI(int setId, int totalExamples, boolean onlySupportingFacts, Random rng) throws Exception {	
		final File folder = new File("datasets/bAbI/en/");
		List fileNamesTrain = new ArrayList<>();
		List fileNamesTest = new ArrayList<>();
		for (final File fileEntry : folder.listFiles()) {
	        String path = fileEntry.getPath();
	        if (path.contains("train")) {
	        	if (path.contains("qa"+setId+"_")) {
	        		fileNamesTrain.add(path);
	        	}
	        }
	        else if (path.contains("test")) {
	        	if (path.contains("qa"+setId+"_")) {
	        		fileNamesTest.add(path);
	        	}
	        }
	        else {
	        	throw new Exception("Unknown file type");
	        }
	    }
		
		List storiesTrain = getStories(fileNamesTrain, onlySupportingFacts);
		List storiesTest = getStories(fileNamesTest, onlySupportingFacts);
		
		while (storiesTrain.size() > totalExamples) {
			storiesTrain.remove(rng.nextInt(storiesTrain.size()));
		}
		while (storiesTest.size() > totalExamples) {
			storiesTest.remove(rng.nextInt(storiesTest.size()));
		}
		
		configureVocab(storiesTrain, storiesTest);
		
		training = getSequences(storiesTrain);
		testing = getSequences(storiesTest);
		validation = null;
		
		lossTraining = new LossSoftmax();
		lossReporting = new LossArgMax();

		inputDimension = training.get(0).steps.get(0).input.w.length;

		int loc = 0;
		while (training.get(0).steps.get(loc).targetOutput == null) {
			loc++;
		}
		outputDimension = training.get(0).steps.get(loc).targetOutput.w.length;
	}
	
	public static final String[] TASK_NAMES = {
		"Single Supporting Fact",
		"Two Supporting Facts",
		"Three Supporting Facts",
		"Two Arg. Relations",
		"Three Arg. Relations",
		"Yes/No Questions",
		"Counting",
		"Lists/Sets",
		"Simple Negation",
		"Indefinite Knowledge",
		"Basic Coreference",
		"Conjunction",
		"Compound Coreference",
		"Time Reasoning",
		"Basic Deduction",
		"Basic Induction",
		"Positional Reasoning",
		"Size Reasoning",
		"Path Finding",
		"Agent's Motivations"
	};

	class Statement {
		public Statement(String line) {
			String[] parts = line.split("\t");
			if (parts.length > 1) {
				String[] words = parts[0].replace("?", " ?").split(" ");
				lineNum = Integer.parseInt(words[0]);
				for (int i = 1; i < words.length; i++) {
					question.add(words[i].toLowerCase());
				}
				
				answer = parts[1].toLowerCase();
				String[] facts = parts[2].split(" ");
				for (int i = 0; i < facts.length; i++) {
					supportingFacts.add(Integer.parseInt(facts[i]));
				}
				isFact = false;
			}
			else {
				String[] words = line.replace("."," .").split(" ");
				lineNum = Integer.parseInt(words[0]);
				for (int i = 1; i < words.length; i++) {
					fact.add(words[i].toLowerCase());
				}
				isFact = true;
			}
		}
		
		@Override
		public String toString() {
			String result = lineNum + "";
			if (isFact) {
				for (String word : fact) {
					result += " " + word;
				}
			}
			else {
				for (String word : question) {
					result += " " + word;
				}
				result += " -> " + answer;
				for (Integer i : supportingFacts) {
					result += " " + i;
				}
			}
			return result;
		}
		boolean isFact = true;
		List fact = new ArrayList<>();
		List question = new ArrayList<>();
		String answer;
		List supportingFacts = new ArrayList<>();
		int lineNum;
	}
	
	class Story {
		public Story(List statements, boolean onlySupportingFacts) {
			
			if (onlySupportingFacts == true) {
				Set supportingFactsAndQuestions = new HashSet<>();
				for (Statement statement : statements) {
					if (statement.isFact == false) {
						supportingFactsAndQuestions.add(statement.lineNum);
						supportingFactsAndQuestions.addAll(statement.supportingFacts);
					}
				}
				List trimmed = new ArrayList<>();
				for (Statement statement : statements) {
					if (supportingFactsAndQuestions.contains(statement.lineNum)) {
						trimmed.add(statement);
					}
				}
				this.statements = trimmed;
			}
			else {
				this.statements = statements;
			}
		}
		List statements;
		
		@Override
		public String toString() {
			String result = "";
			for (Statement statement : statements) {
				result += statement.toString() + "\n";
			}
			return result;
		}
	}
	
	List getStories(List fileNames, boolean onlySupportingFacts) throws Exception {
		List statements = new ArrayList<>();
		for (String fileName : fileNames) {	
			File file = new File(fileName);
			List lines = Files.readAllLines(file.toPath(), Charset.defaultCharset());
			for (String line : lines) {
				statements.add(new Statement(line));
			}
		}
		List stories = new ArrayList<>();
		int prevNum = 0;
		List storyList = new ArrayList<>();
		boolean containsQuestion = false;
		int errors = 0;
		for (Statement statement : statements) {
			if (statement.lineNum < prevNum) {
				if (containsQuestion == false) {
					//System.out.println("Incomplete story");
					//for (Statement st : storyList) {
					//	System.out.println(st);
					//}
					errors++;
				}
				else {
					Story story = new Story(storyList, onlySupportingFacts);
					//System.out.println(story);
					stories.add(story);
				}
				containsQuestion = false;
				storyList = new ArrayList<>();
			}
			if (statement.isFact == false) {
				containsQuestion = true;
			}
			storyList.add(statement);
			prevNum = statement.lineNum;
		}
		Story story = new Story(storyList, onlySupportingFacts);
		//System.out.println(story);
		stories.add(story);
		if (errors > 0) {
			System.out.println("WARNING: " + errors + " INCORRECT STORIES REMOVED.");
		}
		return stories;
	}

	
	List inputVocab = new ArrayList<>();
	List outputVocab = new ArrayList<>();
	
	private void configureVocab(List storiesTrain, List storiesTest) {
		Set inputVocabSet = new HashSet<>();
		Set outputVocabSet = new HashSet<>();
		List allStories = new ArrayList<>();
		allStories.addAll(storiesTrain);
		allStories.addAll(storiesTest);
		for (Story story : allStories) {
			for (Statement statement : story.statements) {
				if (statement.isFact) {
					for (String word : statement.fact) {
						inputVocabSet.add(word);
					}
				}
				else {
					for (String word : statement.question) {
						inputVocabSet.add(word);
					}
					outputVocabSet.add(statement.answer);
				}
			}
		}

		for (String word : inputVocabSet) {
			inputVocab.add(word);
		}
		for (String word : outputVocabSet) {
			outputVocab.add(word);
		}
		
		Collections.sort(inputVocab);
		Collections.sort(outputVocab);
		
		System.out.println("Possible answers: ");
		for (int i = 0; i < outputVocab.size(); i++) {
			System.out.println("\t["+i+"]: " + outputVocab.get(i));
		}
	}
	
	private List getSequences(List stories) {
		int inputDimension = inputVocab.size();
		int outputDimension = outputVocab.size();
		List sequences = new ArrayList<>();;
		for (Story story : stories) {
			
			List steps = new ArrayList<>();
			
			for (Statement statement : story.statements) {
				if (statement.isFact) {
					for (int w = 0; w < statement.fact.size(); w++) {
						double[] input = new double[inputDimension];
						for (int i = 0; i < inputDimension; i++) {
							if (statement.fact.get(w).equals(inputVocab.get(i))) {
								input[i] = 1.0;
								break;
							}
						}
						steps.add(new DataStep(input, null));
					}
				}
				else {
					for (int w = 0; w < statement.question.size(); w++) {
						double[] input = new double[inputDimension];
						double[] targetOutput = null;
						for (int i = 0; i < inputDimension; i++) {
							if (statement.question.get(w).equals(inputVocab.get(i))) {
								input[i] = 1.0;
								break;
							}
						}
						steps.add(new DataStep(input, targetOutput));
					}
					double[] input = new double[inputDimension];
					double[] targetOutput = new double[outputDimension];
					for (int i = 0; i < outputDimension; i++) {
						if (statement.answer.equals(outputVocab.get(i))) {
							targetOutput[i] = 1.0;
							break;
						}
					}
					steps.add(new DataStep(input, targetOutput));
				}
			}
			sequences.add(new DataSequence(steps));
		}
		return sequences;
	}

	@Override
	public void DisplayReport(Model model, Random rng) throws Exception {

	}

	@Override
	public Nonlinearity getModelOutputUnitToUse() {
		return new LinearUnit();
	}
}

 

Ads help maintain this website.