<commit_before>/**
 * IBM Confidential
 * OCO Source Materials
 * (C) Copyright IBM Corp. 2010, 2015
 * The source code for this program is not published or otherwise divested of its trade secrets, irrespective of what has been deposited with the U.S. Copyright Office.
 */


package com.ibm.bi.dml.runtime.matrix.data;

import java.io.Serializable;
import java.util.Arrays;

import com.ibm.bi.dml.runtime.util.SortUtils;

public class SparseRow implements Serializable 
{
	@SuppressWarnings("unused")
	private static final String _COPYRIGHT = "Licensed Materials - Property of IBM\n(C) Copyright IBM Corp. 2010, 2015\n" +
                                             "US Government Users Restricted Rights - Use, duplication  disclosure restricted by GSA ADP Schedule Contract with IBM Corp.";

	private static final long serialVersionUID = 5806895317005796456L;

	//initial capacity of any created sparse row
	//WARNING: be aware that this affects the core memory estimates (incl. implicit assumptions)! 
	public static final int initialCapacity = 4;
	
	private int estimatedNzs = initialCapacity;
	private int maxNzs = Integer.MAX_VALUE;
	private int size = 0;
	private double[] values = null;
	private int[] indexes = null;
	
	public SparseRow(int capacity)
	{
		estimatedNzs = capacity;
		values = new double[capacity];
		indexes = new int[capacity];
	}
	
	public SparseRow(int estnnz, int maxnnz)
	{
		if( estnnz > initialCapacity )
			estimatedNzs = estnnz;
		maxNzs = maxnnz;
		int capacity = ((estnnz<initialCapacity && estnnz>0) ? 
				         estnnz : initialCapacity);
		values = new double[capacity];
		indexes = new int[capacity];
	}
	
	public SparseRow(SparseRow that)
	{
		size = that.size;
		int cap = Math.max(initialCapacity, that.size);
		
		//allocate arrays and copy new values
		values = Arrays.copyOf(that.values, cap);
		indexes = Arrays.copyOf(that.indexes, cap);
	}
	
	public void truncate(int newsize)
	{
		if( newsize>size || newsize<0 )
			throw new RuntimeException("truncate size: "+newsize+" should <= size: "+size+" and >=0");
		size = newsize;
	}
	
	public int size()
	{
		return size;
	}
	
	public void setSize(int newsize)
	{
		size = newsize;
	}
	
	public boolean isEmpty()
	{
		return (size == 0);
	}
	
	public double[] getValueContainer()
	{
		return values;
	}
	
	public int[] getIndexContainer()
	{
		return indexes;
	}
	
	public void setValueContainer(double[] d) {
		values = d;
	}
	
	public void setIndexContainer(int[] i) {
		indexes = i;
	}
	
	public int capacity()
	{
		return values.length;
	}
	
	/**
	 * 
	 * @param that
	 */
	public void copy(SparseRow that)
	{
		//note: no recap (if required) + copy, in order to prevent unnecessary copy of old values
		//in case we have to reallocate the arrays
		
		if( values.length < that.size ) {
			//reallocate arrays and copy new values
			values = Arrays.copyOf(that.values, that.size);
			indexes = Arrays.copyOf(that.indexes, that.size);
		}
		else {
			//copy new values
			System.arraycopy(that.values, 0, values, 0, that.size);
			System.arraycopy(that.indexes, 0, indexes, 0, that.size);	
		}
		size = that.size;
	}

	/**
	 * 
	 * @param estnns
	 * @param maxnns
	 */
	public void reset(int estnns, int maxnns)
	{
		estimatedNzs = estnns;
		maxNzs = maxnns;
		size = 0;
	}
	
	/**
	 * 
	 * @param newCap
	 */
	public void recap(int newCap) 
	{
		if( newCap<=values.length )
			return;
		
		//reallocate arrays and copy old values
		values = Arrays.copyOf(values, newCap);
		indexes = Arrays.copyOf(indexes, newCap);
	}
	
	/**
	 * Heuristic for resizing:
	 *   doubling before capacity reaches estimated nonzeros, then 1.1x after that for default behavior: always 1.1x
	 *   (both with exponential size increase for log N steps of reallocation and shifting)
	 * 
	 * @return
	 */
	private int newCapacity()
	{
		if( values.length < estimatedNzs )
			return Math.min(estimatedNzs, values.length*2);
		else
			return (int) Math.min(maxNzs, Math.ceil((double)(values.length)*1.1));
	}

	/**
	 * In-place compaction of non-zero-entries; removes zero entries and
	 * shifts non-zero entries to the left if necessary.
	 */
	public void compact() 
	{
		int nnz = 0;
		for( int i=0; i<size; i++ ) 
			if( values[i] != 0 ){
				values[nnz] = values[i];
				indexes[nnz] = indexes[i];
				nnz++;
			}
		size = nnz; //adjust row size
	}
	
	/**
	 * 
	 * @param col
	 * @param v
	 * @return
	 */
	public boolean set(int col, double v)
	{
		//search for existing col index
		int index = Arrays.binarySearch(indexes, 0, size, col);
		if( index >= 0 ) {
			values[index] = v;
			return false; //overwritten
		}
		
		//insert new index-value pair
		index = Math.abs( index+1 );
		if( size==values.length )
			resizeAndInsert(index, col, v);
		else
			shiftRightAndInsert(index, col, v);
		return true;
	}
	
	/**
	 * 
	 * @param col
	 * @param v
	 */
	public void append(int col, double v)
	{
		//early abort on zero 
		if( v==0.0 ) {
			return;
		}
		
		//resize if required
		if( size==values.length )
			recap(newCapacity());<commit_msg>89826: SystemML Engine - Fix incorrect maintenance of nnz on sparserow set value (early abort on zero), incl performance<commit_after>/**
 * IBM Confidential
 * OCO Source Materials
 * (C) Copyright IBM Corp. 2010, 2015
 * The source code for this program is not published or otherwise divested of its trade secrets, irrespective of what has been deposited with the U.S. Copyright Office.
 */


package com.ibm.bi.dml.runtime.matrix.data;

import java.io.Serializable;
import java.util.Arrays;

import com.ibm.bi.dml.runtime.util.SortUtils;

public class SparseRow implements Serializable 
{
	@SuppressWarnings("unused")
	private static final String _COPYRIGHT = "Licensed Materials - Property of IBM\n(C) Copyright IBM Corp. 2010, 2015\n" +
                                             "US Government Users Restricted Rights - Use, duplication  disclosure restricted by GSA ADP Schedule Contract with IBM Corp.";

	private static final long serialVersionUID = 5806895317005796456L;

	//initial capacity of any created sparse row
	//WARNING: be aware that this affects the core memory estimates (incl. implicit assumptions)! 
	public static final int initialCapacity = 4;
	
	private int estimatedNzs = initialCapacity;
	private int maxNzs = Integer.MAX_VALUE;
	private int size = 0;
	private double[] values = null;
	private int[] indexes = null;
	
	public SparseRow(int capacity)
	{
		estimatedNzs = capacity;
		values = new double[capacity];
		indexes = new int[capacity];
	}
	
	public SparseRow(int estnnz, int maxnnz)
	{
		if( estnnz > initialCapacity )
			estimatedNzs = estnnz;
		maxNzs = maxnnz;
		int capacity = ((estnnz<initialCapacity && estnnz>0) ? 
				         estnnz : initialCapacity);
		values = new double[capacity];
		indexes = new int[capacity];
	}
	
	public SparseRow(SparseRow that)
	{
		size = that.size;
		int cap = Math.max(initialCapacity, that.size);
		
		//allocate arrays and copy new values
		values = Arrays.copyOf(that.values, cap);
		indexes = Arrays.copyOf(that.indexes, cap);
	}
	
	public void truncate(int newsize)
	{
		if( newsize>size || newsize<0 )
			throw new RuntimeException("truncate size: "+newsize+" should <= size: "+size+" and >=0");
		size = newsize;
	}
	
	public int size()
	{
		return size;
	}
	
	public void setSize(int newsize)
	{
		size = newsize;
	}
	
	public boolean isEmpty()
	{
		return (size == 0);
	}
	
	public double[] getValueContainer()
	{
		return values;
	}
	
	public int[] getIndexContainer()
	{
		return indexes;
	}
	
	public void setValueContainer(double[] d) {
		values = d;
	}
	
	public void setIndexContainer(int[] i) {
		indexes = i;
	}
	
	public int capacity()
	{
		return values.length;
	}
	
	/**
	 * 
	 * @param that
	 */
	public void copy(SparseRow that)
	{
		//note: no recap (if required) + copy, in order to prevent unnecessary copy of old values
		//in case we have to reallocate the arrays
		
		if( values.length < that.size ) {
			//reallocate arrays and copy new values
			values = Arrays.copyOf(that.values, that.size);
			indexes = Arrays.copyOf(that.indexes, that.size);
		}
		else {
			//copy new values
			System.arraycopy(that.values, 0, values, 0, that.size);
			System.arraycopy(that.indexes, 0, indexes, 0, that.size);	
		}
		size = that.size;
	}

	/**
	 * 
	 * @param estnns
	 * @param maxnns
	 */
	public void reset(int estnns, int maxnns)
	{
		estimatedNzs = estnns;
		maxNzs = maxnns;
		size = 0;
	}
	
	/**
	 * 
	 * @param newCap
	 */
	public void recap(int newCap) 
	{
		if( newCap<=values.length )
			return;
		
		//reallocate arrays and copy old values
		values = Arrays.copyOf(values, newCap);
		indexes = Arrays.copyOf(indexes, newCap);
	}
	
	/**
	 * Heuristic for resizing:
	 *   doubling before capacity reaches estimated nonzeros, then 1.1x after that for default behavior: always 1.1x
	 *   (both with exponential size increase for log N steps of reallocation and shifting)
	 * 
	 * @return
	 */
	private int newCapacity()
	{
		if( values.length < estimatedNzs )
			return Math.min(estimatedNzs, values.length*2);
		else
			return (int) Math.min(maxNzs, Math.ceil((double)(values.length)*1.1));
	}

	/**
	 * In-place compaction of non-zero-entries; removes zero entries and
	 * shifts non-zero entries to the left if necessary.
	 */
	public void compact() 
	{
		int nnz = 0;
		for( int i=0; i<size; i++ ) 
			if( values[i] != 0 ){
				values[nnz] = values[i];
				indexes[nnz] = indexes[i];
				nnz++;
			}
		size = nnz; //adjust row size
	}
	
	/**
	 * 
	 * @param col
	 * @param v
	 * @return
	 */
	public boolean set(int col, double v)
	{
		//search for existing col index
		int index = Arrays.binarySearch(indexes, 0, size, col);
		if( index >= 0 ) {
			values[index] = v;
			return false; //overwritten
		}

		//early abort on zero (if no overwrite)
		if( v==0.0 ) {
			return false;
		}
		
		//insert new index-value pair
		index = Math.abs( index+1 );
		if( size==values.length )
			resizeAndInsert(index, col, v);
		else
			shiftRightAndInsert(index, col, v);
		return true;
	}
	
	/**
	 * 
	 * @param col
	 * @param v
	 */
	public void append(int col, double v)
	{
		//early abort on zero 
		if( v==0.0 ) {
			return;
		}
		
		//resize if required
		if( size==values.length )
			recap(newCapacity());
{'fraction_non_alphanumeric': 0.1159859292554231, 'fraction_numerical': 0.012605042016806723, 'mean_word_length': 3.0793144679155042, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6652269', 'n_tokens_mistral': 3911, 'n_tokens_neox': 3381, 'n_words': 1047}