<commit_before>package sudoku.time;

import common.time.AbstractTime;
import common.time.Time;
import java.util.Collections;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import sudoku.Claim;
import sudoku.Rule;
import sudoku.technique.Sledgehammer;

/**
 * <p>A Time in which some Claims are {@link Claim#setFalse(SolutionEvent) set false}.</p>
 * 
 * <p>This class is a base class for Times the denote events in the process of 
 * solving a sudoku puzzle, including direct {@link SolutionEvents SolutionEvents} 
 * in which a Technique changes the puzzle and indirect 
 * {@link AutoResolve AutoResolve} events in which changes made to the puzzle 
 * by some processing event allow a part of the puzzle to 
 * {@link Rule#validateState(SolutionEvent) automatically detect} a 
 * solving action that it can take locally.</p>
 * @author fiveham
 *
 */
public abstract class FalsifiedTime extends AbstractTime {
	
	private final Set<Claim> falsified;
	
	/**
	 * <p>Constructs a FalsifiedTime having the specified {@code parent} and 
	 * the specified {@code falsified} Claims.</p>
	 * @param parent the event which caused this event
	 * @param falsified the Claims set false in this event itself
	 * @throws NoUnaccountedClaims if all the Claims in {@code falsified} are 
	 * accounted for as false by other {@code FalsifiedTime}s that are nth 
	 * parents of this one
	 */
	public FalsifiedTime(Time parent, Set<Claim> falsified){
		super(parent);
		Set<Claim> upFalsified = upFalsified(this, true);
		this.falsified = Collections.unmodifiableSet(falsified.stream().filter((fc) -> !upFalsified.contains(fc)).collect(Collectors.toSet()));
		if(this.falsified.isEmpty()){
			throw new NoUnaccountedClaims("No unaccounted-for Claims specified.");
		}
	}
	
	/**
	 * <p>Returns a Set of all the Claims falsified in all the 
	 * FalsifiedTime nth parents of this FalsifiedTime.</p>
	 * @return a Set of all the Claims falsified in all the 
	 * FalsifiedTime nth parents of this FalsifiedTime
	 */
	private static Set<Claim> upFalsified(Time time, boolean skip){
		return skip(time.upTrail().stream(), skip)
				.filter(FalsifiedTime.class::isInstance)
				.map(FalsifiedTime.class::cast)
				.map(FalsifiedTime::falsified)
				.collect(Sledgehammer.massUnionCollector());
	}
	
	private static Stream<Time> skip(Stream<Time> stream, boolean skip){
		return skip ? stream.skip(1) : stream;
	}
	
	/**
	 * <p>Returns the set of claims set false by the operation that 
	 * this time node represents.</p>
	 * 
	 * <p>{@link Set#add(Object) Additions} to the returned Set write 
	 * through to the underlying collection.</p>
	 * @return the set of claims set false by the operation that 
	 * this time node represents
	 */
	public Set<Claim> falsified(){
		return falsified;
	}
	
	@Override
	public String toString(){
		StringBuilder result = new StringBuilder(toStringStart());
		result.append(" falsifying ").append(falsified().size())
				.append(" Claims directly, and ").append(deepFalse())
				.append(" Claims indirectly.").append(System.lineSeparator())
				.append("Direct: ").append(falsified()).append(System.lineSeparator());
		
		for(Time t : children()){
			String str = t.toString();
			for(Scanner s = new Scanner(str); s.hasNextLine();){
				result.append("  ").append(s.nextLine()).append(System.lineSeparator());
			}
		}
		
		return result.toString();
	}
	
	/**
	 * <p>A short description of this type of Time. The output of 
	 * {@code toString()} begins with this. A trailing space should 
	 * not be included.</p>
	 * @return
	 */
	protected abstract String toStringStart();
	
	private int deepFalse(){
		int count = 0;
		
		Set<Time> layer = new HashSet<>(children());
		while(!layer.isEmpty()){
			Set<Time> newLayer = new HashSet<>();
			for(Time t : layer){
				newLayer.addAll(t.children());
				if(t instanceof FalsifiedTime){
					FalsifiedTime ft = (FalsifiedTime) t;
					count += ft.falsified().size();
				}
			}
			layer = newLayer;
		}
		
		return count;
	}
	
	public static class NoUnaccountedClaims extends RuntimeException{
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 7063069284727178843L;
		
		NoUnaccountedClaims(String s){
			super(s);
		}
	}
}<commit_msg>document FalsifiedTime<commit_after>package sudoku.time;

import common.time.AbstractTime;
import common.time.Time;
import java.util.Collections;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import sudoku.Claim;
import sudoku.Rule;
import sudoku.technique.Sledgehammer;

/**
 * <p>A Time in which some Claims are 
 * {@link Claim#setFalse(FalsifiedTime) set false}.</p>
 * 
 * <p>This class is a base class for {@code Time}s that denote events in 
 * the process of solving a sudoku puzzle, including direct 
 * {@link TechniqueEvent}s in which a Technique changes the puzzle and 
 * indirect {@link Rule.AutoResolve AutoResolve} events in which changes 
 * made to the puzzle by some solution event allow a part of the puzzle 
 * to {@link Rule#validateState(FalsifiedTime) automatically detect} a 
 * solving action that it can take locally.</p>
 * @author fiveham
 *
 */
public abstract class FalsifiedTime extends AbstractTime {
	
	private final Set<Claim> falsified;
	
	/**
	 * <p>Constructs a FalsifiedTime having the specified {@code parent} and 
	 * representing the falsification of Claims from {@code falsified} that 
	 * are not included as {@link #falsified() claims} of any nth-parents of 
	 * this Time that are instances of FalsifiedTime.</p>
	 * @param parent the event which caused this event and of which this 
	 * event is a part
	 * @param falsified a superset of the Claims set false in this event
	 * @throws NoUnaccountedClaims if all the Claims in {@code falsified} are 
	 * accounted for as false by this Time's {@code FalsifiedTime} nth-parents
	 */
	public FalsifiedTime(Time parent, Set<Claim> falsified){
		super(parent);
		Set<Claim> upFalsified = upFalsified(this, true);
		this.falsified = Collections.unmodifiableSet(falsified.stream().filter((fc) -> !upFalsified.contains(fc)).collect(Collectors.toSet()));
		if(this.falsified.isEmpty()){
			throw new NoUnaccountedClaims("No unaccounted-for Claims specified.");
		}
	}
	
	/**
	 * <p>Returns a set of all the Claims falsified in all the 
	 * FalsifiedTime nth parents of this Time.</p>
	 * @return a set of all the Claims falsified in all the 
	 * FalsifiedTime nth parents of this Time
	 */
	private static Set<Claim> upFalsified(Time time, boolean skip){
		return skip(time.upTrail().stream(), skip)
				.filter(FalsifiedTime.class::isInstance)
				.map(FalsifiedTime.class::cast)
				.map(FalsifiedTime::falsified)
				.collect(Sledgehammer.massUnionCollector());
	}
	
	/**
	 * <p>{@link Stream#skip(long) Skips} the first element of {@code stream} 
	 * if and only if {@code skip} is true.</p<
	 * @param stream a Stream whose first element may be skipped
	 * @param skip specifies whether {@code stream}'s first element will be 
	 * skipped
	 * @return a Stream consisting of the remaining elements of {@code stream} 
	 * after discarding the first element of {@code stream}.
	 */
	private static Stream<Time> skip(Stream<Time> stream, boolean skip){
		return skip ? stream.skip(1) : stream;
	}
	
	/**
	 * <p>Returns the unmodifiable set of claims set false by the operation 
	 * that this time node represents.</p>
	 * @return the set of claims set false by the operation that 
	 * this time node represents
	 */
	public Set<Claim> falsified(){
		return falsified;
	}
	
	@Override
	public String toString(){
		StringBuilder result = new StringBuilder(toStringStart())
				.append(" falsifying ")
				.append(falsified().size())
				.append(" Claims directly, and ")
				.append(deepFalse())
				.append(" Claims indirectly.")
				.append(System.lineSeparator())
				.append("Direct: ")
				.append(falsified())
				.append(System.lineSeparator());
		
		for(Time t : children()){
			String str = t.toString();
			for(Scanner s = new Scanner(str); s.hasNextLine();){
				result.append("  ").append(s.nextLine()).append(System.lineSeparator());
			}
		}
		
		return result.toString();
	}
	
	/**
	 * <p>A short description of this type of Time. The output of 
	 * {@code toString()} begins with this. A trailing space should 
	 * not be included.</p>
	 * @return a short description of this type of Time
	 */
	protected abstract String toStringStart();
	
	/**
	 * <p>Returns the number of Claims {@link #falsified() falsified} by 
	 * all the FalsifiedTime nth-children of this Time.</p>
	 * @return the number of Claims {@link #falsified() falsified} by 
	 * all the FalsifiedTime nth-children of this Time
	 */
	private int deepFalse(){
		int count = 0;
		
		Set<Time> layer = new HashSet<>(children());
		while(!layer.isEmpty()){
			Set<Time> newLayer = new HashSet<>();
			for(Time t : layer){
				newLayer.addAll(t.children());
				if(t instanceof FalsifiedTime){
					count += ((FalsifiedTime) t).falsified().size();
				}
			}
			layer = newLayer;
		}
		
		return count;
	}
	
	/**
	 * <p>An Exception thrown when a FalsifiedTime is constructed without 
	 * any specified falsified Claims not already {@link #falsified falsified} 
	 * by the constructed FalsifiedTime's FalsifiedTime nth-parents.</p>
	 * @author fiveham
	 *
	 */
	public static class NoUnaccountedClaims extends RuntimeException{
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 7063069284727178843L;
		
		private NoUnaccountedClaims(String s){
			super(s);
		}
	}
}
{'fraction_non_alphanumeric': 0.11559195521459673, 'fraction_numerical': 0.0043541364296081275, 'mean_word_length': 3.9069175991861647, 'pattern_counts': {'":': 0, '<': 58, '<?xml version=': 0, '>': 58, 'https://': 0, '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': '4535036', 'n_tokens_mistral': 3255, 'n_tokens_neox': 2830, 'n_words': 957}