<commit_before>package edu.psu.compbio.seqcode.projects.chexmix;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ProteinDNAInteractionModel: defines a collection of composite model components 
 * 
 *   Coordinates are 0-based, but the midpoint of the model is defined by the centerOffset variable. 
 * @author mahony
 *
 */
public class ProteinDNAInteractionModel {

	protected int modelWidth;
	protected int centerOffset;
	protected int numConditions; // number of conditions compositeProfiles are based on
	protected double[][] compositeWatson; //per-condition compositeProfile
	protected double[][] compositeCrick; //per-condition compositeProfile
	protected ChExMixConfig cmConfig;
	protected List<CompositeModelComponent> allComponents;
	protected List<CompositeModelComponent> XLComponents;
	protected Map<CompositeModelComponent, TagProbabilityDensity> XLComponentDensities;
	protected CompositeModelComponent CSComponent;
	protected CompositeModelComponent backgroundComponent;
	protected int numXLComponents; 
	
	/**
	 * Initialize a new ProteinDNAInteractionModel
	 * @param config
	 * @param width
	 * @param initXLdistrib
	 * @param initCSdistrib
	 * @param initBackDistrib
	 * @param noisePi
	 */
	public ProteinDNAInteractionModel(ChExMixConfig config, CompositeTagDistribution composite, TagProbabilityDensity initXLdistrib, TagProbabilityDensity initCSdistrib, 
			TagProbabilityDensity initBackDistrib, double noisePi){
		modelWidth = composite.getWinSize();
		centerOffset = composite.getCenterOffset();
		numConditions = composite.getNumConditions();
		compositeWatson = composite.getCompositeWatson();
		compositeCrick = composite.getCompositeCrick();
		cmConfig = config;
		
		//Background component
		backgroundComponent = new CompositeModelComponent(initBackDistrib, centerOffset, 0, "Back",  false, true);

		//ChIP-seq component
		CSComponent = new CompositeModelComponent(initCSdistrib, centerOffset, 1, "CS", false, true);
				
		//XL components
		XLComponents = new ArrayList<CompositeModelComponent>();
		XLComponentDensities = new HashMap<CompositeModelComponent, TagProbabilityDensity>();
		numXLComponents = (initCSdistrib.getInfluenceRange()/2)/cmConfig.getXLComponentSpacing();
		int xlPos = centerOffset-(numXLComponents*cmConfig.getXLComponentSpacing())/2;
		for(int i=0; i<numXLComponents; i++){
			TagProbabilityDensity XLTagDist = initXLdistrib.clone();
			CompositeModelComponent newComp = new CompositeModelComponent(XLTagDist, xlPos, i+2, "XL", true, true);
			XLComponents.add(newComp);
			XLComponentDensities.put(newComp, XLTagDist);
			xlPos += cmConfig.getXLComponentSpacing(); 
		}
		
		//All components
		allComponents = new ArrayList<CompositeModelComponent>();
		allComponents.add(backgroundComponent);
		allComponents.add(CSComponent);
		allComponents.addAll(XLComponents);
		
		//Set initial pi values
		setInitialPi(noisePi);
	}
	
	/**
	 * Initialize a ProteinDNAInteractionModel using existing components (e.g. when loading saved model)
	 * @param config
	 * @param width
	 * @param CSComp
	 * @param backComp
	 * @param XLComps
	 */
	public ProteinDNAInteractionModel(ChExMixConfig config, int width, int centerOff, int numConds, double[][] compWatson, double[][] compCrick, CompositeModelComponent CSComp, CompositeModelComponent backComp, List<CompositeModelComponent> XLComps){
		modelWidth = width;
		centerOffset = centerOff;
		numConditions = numConds;
		compositeWatson = compWatson;
		compositeCrick = compCrick;
		cmConfig = config;
		backgroundComponent = backComp;
		CSComponent = CSComp;
		XLComponents = XLComps;
		numXLComponents = XLComponents==null ? 0 : XLComponents.size();
		allComponents = new ArrayList<CompositeModelComponent>();
		allComponents.add(backgroundComponent);
		allComponents.add(CSComponent);
		XLComponentDensities = new HashMap<CompositeModelComponent, TagProbabilityDensity>();
		if(numXLComponents>0){
			allComponents.addAll(XLComponents);
			for(CompositeModelComponent xl : XLComponents){
				XLComponentDensities.put(xl, xl.getTagDistribution());
			}
		}
	}
	
	//Accessors
	public int getWidth(){return modelWidth;}
	public int getCenterOffset(){return centerOffset;}
	public TagProbabilityDensity getXLTagDistribution(CompositeModelComponent comp){return XLComponentDensities.get(comp);}
	public TagProbabilityDensity getCSTagDistribution(){return CSComponent.getTagDistribution();}
	public TagProbabilityDensity getBackTagDistribution(){return backgroundComponent.getTagDistribution();}
	public int getNumComponents(){return allComponents.size();}
	public List<CompositeModelComponent> getAllComponents(){return allComponents;}
	public List<CompositeModelComponent> getXLComponents(){return XLComponents;}
	public CompositeModelComponent getCSComponent(){return CSComponent;}
	public CompositeModelComponent getBackgroundComponent(){return backgroundComponent;}
	
	/**
	 * Return the non-zero components
	 * @return
	 */
	public List<CompositeModelComponent> getNonZeroComponents(){
		List<CompositeModelComponent> comps = new ArrayList<CompositeModelComponent>();
		for(CompositeModelComponent c : allComponents)
			if(c.isNonZero())
				comps.add(c);
		return comps;
	}
	
	/**
	 * Set the initial pi values for all components. 
	 * Assumes model is initialized. 
	 */
	protected void setInitialPi(double noisePi){
		backgroundComponent.setPi(noisePi);
		double bindingPi = 1-noisePi;
		double initCS = Math.max(bindingPi*cmConfig.INIT_CS_TO_XL_RATIO, cmConfig.MIN_CS_PI);
		CSComponent.setPi(initCS);
		for(CompositeModelComponent xl : XLComponents){
			double xlPi = cmConfig.noXL() ? 0.0 : bindingPi*(1-initCS)/(double)numXLComponents;
			xl.setPi(xlPi);
		}
	}
	
	
	/**<commit_msg>bug fix on noxl pi initialization<commit_after>package edu.psu.compbio.seqcode.projects.chexmix;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ProteinDNAInteractionModel: defines a collection of composite model components 
 * 
 *   Coordinates are 0-based, but the midpoint of the model is defined by the centerOffset variable. 
 * @author mahony
 *
 */
public class ProteinDNAInteractionModel {

	protected int modelWidth;
	protected int centerOffset;
	protected int numConditions; // number of conditions compositeProfiles are based on
	protected double[][] compositeWatson; //per-condition compositeProfile
	protected double[][] compositeCrick; //per-condition compositeProfile
	protected ChExMixConfig cmConfig;
	protected List<CompositeModelComponent> allComponents;
	protected List<CompositeModelComponent> XLComponents;
	protected Map<CompositeModelComponent, TagProbabilityDensity> XLComponentDensities;
	protected CompositeModelComponent CSComponent;
	protected CompositeModelComponent backgroundComponent;
	protected int numXLComponents; 
	
	/**
	 * Initialize a new ProteinDNAInteractionModel
	 * @param config
	 * @param width
	 * @param initXLdistrib
	 * @param initCSdistrib
	 * @param initBackDistrib
	 * @param noisePi
	 */
	public ProteinDNAInteractionModel(ChExMixConfig config, CompositeTagDistribution composite, TagProbabilityDensity initXLdistrib, TagProbabilityDensity initCSdistrib, 
			TagProbabilityDensity initBackDistrib, double noisePi){
		modelWidth = composite.getWinSize();
		centerOffset = composite.getCenterOffset();
		numConditions = composite.getNumConditions();
		compositeWatson = composite.getCompositeWatson();
		compositeCrick = composite.getCompositeCrick();
		cmConfig = config;
		
		//Background component
		backgroundComponent = new CompositeModelComponent(initBackDistrib, centerOffset, 0, "Back",  false, true);

		//ChIP-seq component
		CSComponent = new CompositeModelComponent(initCSdistrib, centerOffset, 1, "CS", false, true);
				
		//XL components
		XLComponents = new ArrayList<CompositeModelComponent>();
		XLComponentDensities = new HashMap<CompositeModelComponent, TagProbabilityDensity>();
		numXLComponents = (initCSdistrib.getInfluenceRange()/2)/cmConfig.getXLComponentSpacing();
		int xlPos = centerOffset-(numXLComponents*cmConfig.getXLComponentSpacing())/2;
		for(int i=0; i<numXLComponents; i++){
			TagProbabilityDensity XLTagDist = initXLdistrib.clone();
			CompositeModelComponent newComp = new CompositeModelComponent(XLTagDist, xlPos, i+2, "XL", true, true);
			XLComponents.add(newComp);
			XLComponentDensities.put(newComp, XLTagDist);
			xlPos += cmConfig.getXLComponentSpacing(); 
		}
		
		//All components
		allComponents = new ArrayList<CompositeModelComponent>();
		allComponents.add(backgroundComponent);
		allComponents.add(CSComponent);
		allComponents.addAll(XLComponents);
		
		//Set initial pi values
		setInitialPi(noisePi);
	}
	
	/**
	 * Initialize a ProteinDNAInteractionModel using existing components (e.g. when loading saved model)
	 * @param config
	 * @param width
	 * @param CSComp
	 * @param backComp
	 * @param XLComps
	 */
	public ProteinDNAInteractionModel(ChExMixConfig config, int width, int centerOff, int numConds, double[][] compWatson, double[][] compCrick, CompositeModelComponent CSComp, CompositeModelComponent backComp, List<CompositeModelComponent> XLComps){
		modelWidth = width;
		centerOffset = centerOff;
		numConditions = numConds;
		compositeWatson = compWatson;
		compositeCrick = compCrick;
		cmConfig = config;
		backgroundComponent = backComp;
		CSComponent = CSComp;
		XLComponents = XLComps;
		numXLComponents = XLComponents==null ? 0 : XLComponents.size();
		allComponents = new ArrayList<CompositeModelComponent>();
		allComponents.add(backgroundComponent);
		allComponents.add(CSComponent);
		XLComponentDensities = new HashMap<CompositeModelComponent, TagProbabilityDensity>();
		if(numXLComponents>0){
			allComponents.addAll(XLComponents);
			for(CompositeModelComponent xl : XLComponents){
				XLComponentDensities.put(xl, xl.getTagDistribution());
			}
		}
	}
	
	//Accessors
	public int getWidth(){return modelWidth;}
	public int getCenterOffset(){return centerOffset;}
	public TagProbabilityDensity getXLTagDistribution(CompositeModelComponent comp){return XLComponentDensities.get(comp);}
	public TagProbabilityDensity getCSTagDistribution(){return CSComponent.getTagDistribution();}
	public TagProbabilityDensity getBackTagDistribution(){return backgroundComponent.getTagDistribution();}
	public int getNumComponents(){return allComponents.size();}
	public List<CompositeModelComponent> getAllComponents(){return allComponents;}
	public List<CompositeModelComponent> getXLComponents(){return XLComponents;}
	public CompositeModelComponent getCSComponent(){return CSComponent;}
	public CompositeModelComponent getBackgroundComponent(){return backgroundComponent;}
	
	/**
	 * Return the non-zero components
	 * @return
	 */
	public List<CompositeModelComponent> getNonZeroComponents(){
		List<CompositeModelComponent> comps = new ArrayList<CompositeModelComponent>();
		for(CompositeModelComponent c : allComponents)
			if(c.isNonZero())
				comps.add(c);
		return comps;
	}
	
	/**
	 * Set the initial pi values for all components. 
	 * Assumes model is initialized. 
	 */
	protected void setInitialPi(double noisePi){
		backgroundComponent.setPi(noisePi);
		double bindingPi = 1-noisePi;
		double initCS = cmConfig.noXL() ? bindingPi : Math.max(bindingPi*cmConfig.INIT_CS_TO_XL_RATIO, cmConfig.MIN_CS_PI);
		CSComponent.setPi(initCS);
		for(CompositeModelComponent xl : XLComponents){
			double xlPi = cmConfig.noXL() ? 0.0 : bindingPi*(1-initCS)/(double)numXLComponents;
			xl.setPi(xlPi);
		}
	}
	
	
	/**
{'fraction_non_alphanumeric': 0.09313807531380754, 'fraction_numerical': 0.0021757322175732217, 'mean_word_length': 6.067415730337078, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, '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': '1466434', 'n_tokens_mistral': 3776, 'n_tokens_neox': 3330, 'n_words': 771}