All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src-lib.atlas.lib.ColumnMap Maven / Gradle / Ivy

There is a newer version: 0.8.10
Show newest version
/*
 * (c) Copyright 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 * [See end of file]
 */

package atlas.lib;

import static java.lang.String.format;

import java.util.Arrays;
import java.util.List;



/** General descriptor of a reorderring (mapping) of columns in tuples to columns in indexes, 
 * for example, from triples to triple index order. 
 * @author Andy Seaborne
 */
public class ColumnMap
{
    // Map from tuple order to index order
    // So SPO->POS is (0->2, 1->0, 2->1)
    // i.e. the location of the element after mapping.  
    private int[] insertOrder ;            
    
    // The mapping from index to tuple order
    // For POS->SPO, is (0->1, 1->2, 2->0)
    // i.e. the location to fetch the mapped element from. 
    private int[] fetchOrder ;

    private String label ;

    /** Construct a column mapping that maps the input (one col, one char) to the output */  
    public ColumnMap(String input, String output)
    {
        this(input+"->"+output, compileMapping(input, output)) ;
    }
    
    public  ColumnMap(String label, List input, List output)
    {
        this(label, compileMapping(input, output)) ;
    }
    
    public  ColumnMap(String label, T[] input, T[] output)
    {
        this(label, compileMapping(input, output)) ;
    }
    
    /** Construct a column map - the elements are the 
     * mappings of a tuple originally in the order 0,1,2,...
     * so SPO->POS is 2,0,1 (SPO->POS so S->2, P->0, O->1)   
     * and not 1,2,0 (which is the extraction mapping).
     * The label is just a lable and is not interpretted.
     */
    public ColumnMap(String label, int...elements)
    {
        this.label = label ;

        this.insertOrder = new int[elements.length] ;
        System.arraycopy(elements, 0, elements, 0, elements.length) ;
        Arrays.fill(insertOrder, -1) ;
        
        this.fetchOrder = new int[elements.length] ;
        Arrays.fill(fetchOrder, -1) ;
    
        for ( int i = 0 ; i < elements.length ; i++ )
        {
            int x = elements[i] ;
            if ( x < 0 || x >= elements.length)
                throw new IllegalArgumentException("Out of range: "+x) ;
            // Checking
            if ( insertOrder[i] != -1 || fetchOrder[x] != -1 )
                throw new IllegalArgumentException("Inconsistent: "+ListUtils.str(elements)) ;
            
            insertOrder[i] = x ;
            fetchOrder[x] = i ;
        }
    }
    
    /** Length of mapping */
    
    public int length() { return fetchOrder.length ; }
    
    /** Apply to an unmapped tuple to get the i'th slot after mapping : SPO->POS : 0'th slot is P from SPO */
    public  T fetchSlot(int idx, Tuple tuple)
    { 
        idx = fetchOrder[idx] ;     // Apply the reverse mapping as we are doing zero is P, so it's an unmap.
        return tuple.get(idx) ;
    }

    /** Apply to an unmapped tuple to get the i'th slot after mapping : SPO->POS : 0'th slot is P from SPO */
    public  T fetchSlot(int idx, T[] tuple)
    { 
        idx = fetchOrder[idx] ;     // Apply the reverse mapping as we are doing zero is P, so it's an unmap.
        return tuple[idx] ;
    }
    
    /** Apply to a mapped tuple to get the i'th slot as it appears after mapping : SPO->POS : 0'th slot is S from POS */
    public  T mapSlot(int idx, Tuple tuple)
    { 
        idx = insertOrder[idx] ;
        return tuple.get(idx) ;
    }
    
    /** Apply to a mapped tuple to get the i'th slot as it appears after mapping : SPO->POS : 0'th slot is S from POS */
    public  T mapSlot(int idx, T[] tuple)
    { 
        idx = insertOrder[idx] ;        // Yes - it's the insert location we want to access 
        return tuple[idx] ;
    }
    
    /** Get the index of the i'th slot as it appears after mapping : SPO->POS : 0'th slot is S from POS so 2->0 */
    public int mapSlotIdx(int idx)
    { 
        return insertOrder[idx] ;        // Yes - it's the insert location we want to access 
    }

    /** Get the index of the i'th slot as it appears from a mapping : for SPO->POS : 0'th slot is P so 1->0 */
    public int fetchSlotIdx(int idx)
    { 
        return fetchOrder[idx] ;        // Yes - it's the insert location we want to access 
    }

    /** Apply to an unmapped tuple to get a tuple with the column mapping applied */
    public  Tuple map(Tuple src)
    {
        return map(src, insertOrder) ;
    }

    /** Apply to a mapped tuple to get a tuple with the column mapping reverse-applied */
    public  Tuple unmap(Tuple src)
    {
        return map(src, fetchOrder) ;
    }

    private  Tuple map(Tuple src, int[] map)
    {
        @SuppressWarnings("unchecked")
        T[] elts = (T[])new Object[src.size()] ;
        
        for ( int i = 0 ; i < src.size() ; i++ )
        {
            int j = map[i] ;
            elts[j] = src.get(i) ;
        }
        return Tuple.create(elts) ;
    }
    
    /** Compile a mapping encoded as single charcaters e.g. "SPO", "POS" */
    static int[] compileMapping(String domain, String range)
    {
        List input = StrUtils.toCharList(domain) ;
        List output = StrUtils.toCharList(range) ;
        return compileMapping(input, output) ;
    }

    /** Compile a mapping, encoded two list, the domain and range of the mapping function  */
    static  int[] compileMapping(T[] domain, T[] range)
    {
        return compileMapping(Arrays.asList(domain), Arrays.asList(range)) ;
    }
    
    /** Compile a mapping */
    static  int[] compileMapping(List domain, Listrange)
    {
        if ( domain.size() != range.size() )
            throw new AtlasException("Bad mapping: lengths not the same: "+domain+" -> "+range) ; 
        
        int[] cols = new int[domain.size()] ;
        boolean[] mapped = new boolean[domain.size()] ;
        //Arrays.fill(mapped, false) ;
        
        for ( int i = 0 ; i < domain.size() ; i++ )
        {
            T input = domain.get(i) ;
            int j = range.indexOf(input) ;
            if ( j < 0 )
                throw new AtlasException("Bad mapping: missing mapping: "+domain+" -> "+range) ;
            if ( mapped[j] )
                throw new AtlasException("Bad mapping: duplicate: "+domain+" -> "+range) ;
            cols[i] = j ;
            mapped[j] = true ;
        }
        return cols ;
    }
    
    @Override
    public String toString()
    {
        //return label ; 
        return format("%s:%s%s", label, mapStr(insertOrder), mapStr(fetchOrder)) ;
    }

    private Object mapStr(int[] map)
    {
        StringBuilder buff = new StringBuilder() ;
        String sep = "{" ;
        
        for ( int i = 0 ; i < map.length ; i++ )
        {
            buff.append(sep) ;
            sep = ", " ; 
            buff.append(format("%d->%d", i, map[i])) ;
        }
        buff.append("}") ;
        
        return buff.toString() ;
    }

    public String getLabel()
    {
        return label ;
    }
    
}

/*
 * (c) Copyright 2008, 2009 Hewlett-Packard Development Company, LP
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */




© 2015 - 2025 Weber Informatics LLC | Privacy Policy