001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005
006package com.nativelibs4java.opencl.util;
007
008import com.nativelibs4java.opencl.CLBuffer;
009import com.nativelibs4java.opencl.CLBuildException;
010import com.nativelibs4java.opencl.CLContext;
011import com.nativelibs4java.opencl.CLBuffer;
012import com.nativelibs4java.opencl.CLEvent;
013import com.nativelibs4java.opencl.CLKernel;
014import com.nativelibs4java.opencl.CLPlatform.DeviceFeature;
015import com.nativelibs4java.opencl.CLProgram;
016import com.nativelibs4java.opencl.CLQueue;
017import com.nativelibs4java.opencl.JavaCL;
018import com.nativelibs4java.opencl.util.ReductionUtils;
019import com.nativelibs4java.opencl.util.ReductionUtils.Reductor;
020import com.nativelibs4java.util.IOUtils;
021import com.nativelibs4java.util.Pair;
022import java.io.FileNotFoundException;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.PrintWriter;
026import java.io.StringWriter;
027import java.nio.Buffer;
028import java.nio.DoubleBuffer;
029import java.util.EnumMap;
030import java.util.HashMap;
031import java.util.Map;
032import java.util.logging.Level;
033import java.util.logging.Logger;
034
035/**
036 *
037 * @author ochafik
038 */
039@SuppressWarnings("unused")
040public class LinearAlgebraUtils {
041
042        final LinearAlgebraKernels kernels;
043        final CLQueue queue;
044    public LinearAlgebraUtils(boolean doubleCapable) throws IOException, CLBuildException {
045        this(JavaCL.createBestContext(doubleCapable ? DeviceFeature.DoubleSupport : null).createDefaultQueue());
046    }
047
048    public LinearAlgebraUtils(CLQueue queue) throws IOException, CLBuildException {
049                this.queue = queue;
050        kernels = new LinearAlgebraKernels(queue.getContext());
051    }
052
053    public CLContext getContext() {
054        return getQueue().getContext();
055    }
056
057    public CLQueue getQueue() {
058        return queue;
059    }
060        
061        public synchronized <T> CLEvent multiply(
062            CLBuffer<T> a, int aRows, int aColumns, 
063            CLBuffer<T> b, int bRows, int bColumns, 
064            CLBuffer<T> out, //long outRows, long outColumns,
065            CLEvent... eventsToWaitFor) throws CLBuildException
066    {
067        if (a.getElementClass() == Double.class)
068            return multiplyDoubles((CLBuffer<Double>)a, aRows, aColumns, (CLBuffer<Double>)b, bRows, bColumns, (CLBuffer<Double>)out, eventsToWaitFor);
069        if (a.getElementClass() == Float.class)
070            return multiplyFloats((CLBuffer<Float>)a, aRows, aColumns, (CLBuffer<Float>)b, bRows, bColumns, (CLBuffer<Float>)out, eventsToWaitFor);
071        
072        throw new UnsupportedOperationException();
073    }
074        public synchronized CLEvent multiplyDoubles(
075            CLBuffer<Double> a, int aRows, int aColumns, 
076            CLBuffer<Double> b, int bRows, int bColumns, 
077            CLBuffer<Double> out, //long outRows, long outColumns,
078            CLEvent... eventsToWaitFor) throws CLBuildException
079    {
080                if (a == null || b == null || out == null)
081                        throw new IllegalArgumentException("Null matrix");
082                
083                if (aColumns != bRows || out.getElementCount() != (aRows * bColumns))
084                        throw new IllegalArgumentException("Invalid matrix sizes : multiplying matrices of sizes (A, B) and (B, C) requires output of size (A, C)");
085        
086                long outRows = aRows;
087        long outColumns = bColumns;
088        return kernels.mulMatDouble(queue,
089            a, (int)aColumns,
090            b, (int)bColumns,
091            out,
092            new int[] { (int)outRows, (int)outColumns },
093            null,
094            eventsToWaitFor
095        );
096    }
097    public synchronized CLEvent multiplyFloats(
098            CLBuffer<Float> a, long aRows, long aColumns, 
099            CLBuffer<Float> b, long bRows, long bColumns, 
100            CLBuffer<Float> out, //long outRows, long outColumns,
101            CLEvent... eventsToWaitFor) throws CLBuildException
102    {
103        long outRows = aRows;
104        long outColumns = bColumns;
105        return kernels.mulMatFloat(queue,
106            a, (int)aColumns,
107            b, (int)bColumns,
108            out,
109            new int[] { (int)outRows, (int)outColumns },
110            null,
111            eventsToWaitFor
112        );
113    }
114        Reductor<Double> addReductorDouble;
115        synchronized Reductor<Double> getAddReductorDouble() {
116                if (addReductorDouble == null) {
117                        try {
118                                addReductorDouble = ReductionUtils.createReductor(getContext(), ReductionUtils.Operation.Add, OpenCLType.Double, 1);
119                        } catch (CLBuildException ex) {
120                                Logger.getLogger(LinearAlgebraUtils.class.getName()).log(Level.SEVERE, null, ex);
121                                throw new RuntimeException("Failed to create an addition reductor !", ex);
122                        }
123                }
124                return addReductorDouble;
125        }
126
127    public synchronized CLEvent transposeDouble(CLBuffer<Double> a, int aRows, int aColumns, CLBuffer<Double> out, CLEvent... eventsToWaitFor) throws CLBuildException {
128        return kernels.transposeDouble(queue,
129            a, aRows, aColumns,
130            out,
131            new int[] { (int)aColumns, (int)aRows },
132            null,
133            eventsToWaitFor
134        );
135    }
136        Reductor<Float> addReductorFloat;
137        synchronized Reductor<Float> getAddReductorFloat() {
138                if (addReductorFloat == null) {
139                        try {
140                                addReductorFloat = ReductionUtils.createReductor(getContext(), ReductionUtils.Operation.Add, OpenCLType.Float, 1);
141                        } catch (CLBuildException ex) {
142                                Logger.getLogger(LinearAlgebraUtils.class.getName()).log(Level.SEVERE, null, ex);
143                                throw new RuntimeException("Failed to create an addition reductor !", ex);
144                        }
145                }
146                return addReductorFloat;
147        }
148
149    public synchronized <T> CLEvent transpose(CLBuffer<T> a, int aRows, int aColumns, CLBuffer<T> out, CLEvent... eventsToWaitFor) throws CLBuildException {
150        if (a.getElementClass() == Double.class)
151            return transposeDoubles((CLBuffer<Double>)a, aRows, aColumns, (CLBuffer<Double>)out, eventsToWaitFor);
152        if (a.getElementClass() == Float.class)
153            return transposeFloats((CLBuffer<Float>)a, aRows, aColumns, (CLBuffer<Float>)out, eventsToWaitFor);
154        
155        throw new UnsupportedOperationException();
156    }
157
158    public synchronized CLEvent transposeFloats(CLBuffer<Float> a, int aRows, int aColumns, CLBuffer<Float> out, CLEvent... eventsToWaitFor) throws CLBuildException {
159        return kernels.transposeFloat(queue,
160            a, aRows, aColumns,
161            out,
162            new int[] { (int)aColumns, (int)aRows },
163            null,
164            eventsToWaitFor
165        );
166    }
167
168                
169        public synchronized CLEvent transposeDoubles(CLBuffer<Double> a, int aRows, int aColumns, CLBuffer<Double> out, CLEvent... eventsToWaitFor) throws CLBuildException {
170        return kernels.transposeDouble(queue,
171            a, aRows, aColumns,
172            out,
173            new int[] { (int)aColumns, (int)aRows },
174            null,
175            eventsToWaitFor
176        );
177    }
178    
179
180}