1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.bordeaux.services;
18
19import android.os.IBinder;
20import android.util.Log;
21import java.util.HashMap;
22import java.util.ArrayList;
23import java.util.Map;
24import java.util.HashSet;
25import java.util.Iterator;
26import java.io.Serializable;
27import java.io.*;
28import java.lang.Boolean;
29import android.bordeaux.services.FeatureAssembly;
30import android.bordeaux.learning.predictorHist;
31
32/**
33 * This is interface to implement Prediction based on histogram that
34 * uses predictor_histogram from learnerning section
35 */
36public class Predictor extends IPredictor.Stub
37        implements IBordeauxLearner {
38    private ModelChangeCallback modelChangeCallback = null;
39    private final String TAG = "Predictor";
40    private final String SET_EXPIRE_TIME = "SetExpireTime";
41    private final String USE_HISTORY = "Use History";
42    private final String SET_FEATURE = "Set Feature";
43    private long mExpireTime = 3 * 60;
44    private long mLastSampleTime = 0;
45    private boolean mUseHistoryFlag = false;
46    private final String NEW_START = "New Start";
47
48    static public class Model implements Serializable {
49        public HashMap<String, Integer> countHistogram = new HashMap<String, Integer>();
50        public HashSet<String> usedFeatures = new HashSet<String>();
51        public int sampleCounts;
52        public boolean useHistoryFlag;
53        public long expireTime;
54        public long lastSampleTime;
55    }
56
57    private predictorHist mPredictorHist = new predictorHist();
58    private String mLastSample = NEW_START;
59    public FeatureAssembly mFeatureAssembly = new FeatureAssembly();
60
61    /**
62     * Reset the Predictor
63     */
64    public void ResetPredictor(){
65        printModel(getPredictionModel());
66        mPredictorHist.ResetPredictorHist();
67        mUseHistoryFlag = false;
68        mLastSampleTime = 0;
69        mLastSample = NEW_START;
70        mFeatureAssembly = new FeatureAssembly();
71        printModel(getPredictionModel());
72        if (modelChangeCallback != null) {
73            modelChangeCallback.modelChanged(this);
74        }
75    }
76
77    /**
78     * Augment input string with buildin features such as time, location
79     */
80    private String buildDataPoint(String sampleName) {
81        String fs = mFeatureAssembly.augmentFeatureInputString(sampleName);
82        if (mUseHistoryFlag) {
83             if (((System.currentTimeMillis()- mLastSampleTime)/1000) > mExpireTime) {
84                 mLastSample  = NEW_START;
85             }
86             fs = fs + "+" + mLastSample;
87        }
88        return fs;
89    }
90
91    /**
92     * Input is a sampleName e.g.action name. This input is then augmented with requested build-in
93     * features such as time and location to create sampleFeatures. The sampleFeatures is then
94     * pushed to the histogram
95     */
96    public void pushNewSample(String sampleName) {
97        String sampleFeatures = buildDataPoint(sampleName);
98        mLastSample = sampleName;
99        mLastSampleTime = System.currentTimeMillis();
100        mPredictorHist.pushSample(sampleFeatures);
101        if (modelChangeCallback != null) {
102            modelChangeCallback.modelChanged(this);
103        }
104        //printModel(getPredictionModel());
105    }
106
107    /**
108     * return probabilty of an exmple using the histogram
109     */
110    public float getSampleProbability(String sampleName) {
111        String sampleFeatures = buildDataPoint(sampleName);
112        return mPredictorHist.getProbability(sampleFeatures);
113    }
114
115    /**
116     * Set parameters for 1) using History in probability estimations e.g. consider the last event
117     * and 2) featureAssembly e.g. time and location.
118     */
119    public boolean setPredictorParameter(String s, String f) {
120        boolean res = false;
121        if (s.equals(USE_HISTORY)) {
122            if (f.equals("true")){
123                mUseHistoryFlag = true;
124                res = true;
125            }
126            else if (f.equals("false")) {
127                mUseHistoryFlag = false;
128                res = true;
129            }
130        } else if (s.equals(SET_EXPIRE_TIME)) {
131            mExpireTime = Long.valueOf(f);
132            res = true;
133        } else if (s.equals(SET_FEATURE)) {
134            res = mFeatureAssembly.registerFeature(f);
135        }
136        if (!res)
137            Log.e(TAG,"Setting parameter " + s + " with " + f + " is not valid");
138        return res;
139    }
140
141    public Model getPredictionModel() {
142        Model m = new Model();
143        m.countHistogram.putAll(mPredictorHist.getHist());
144        m.sampleCounts = mPredictorHist.getHistCounts();
145        m.expireTime = mExpireTime;
146        m.usedFeatures = (HashSet) mFeatureAssembly.getUsedFeatures();
147        m.useHistoryFlag = mUseHistoryFlag;
148        m.lastSampleTime = mLastSampleTime;
149        return m;
150    }
151
152    public boolean loadModel(Model m) {
153        //Log.i(TAG,"on loadModel");
154        //printModel(m);
155        mPredictorHist = new predictorHist();
156        mPredictorHist.set(m.countHistogram);
157        mExpireTime = m.expireTime;
158        mUseHistoryFlag = m.useHistoryFlag;
159        mLastSampleTime = m.lastSampleTime;
160        mFeatureAssembly = new FeatureAssembly();
161        boolean res = false;
162        Iterator itr = m.usedFeatures.iterator();
163        while(itr.hasNext()) {
164            res = res & mFeatureAssembly.registerFeature((String) itr.next());
165        }
166        return res;
167    }
168
169    public void printModel(Model m) {
170        Log.i(TAG,"histogram is : " + m.countHistogram.toString());
171        Log.i(TAG,"number of counts in histogram is : " + m.sampleCounts);
172        Log.i(TAG,"ExpireTime time is : " + m.expireTime);
173        Log.i(TAG,"useHistoryFlag is : " + m.useHistoryFlag);
174        Log.i(TAG,"used features are : " + m.usedFeatures.toString());
175    }
176
177    // Beginning of the IBordeauxLearner Interface implementation
178    public byte [] getModel() {
179        Model model = getPredictionModel();
180        //Log.i(TAG,"on getModel");
181        printModel(model);
182        try {
183            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
184            ObjectOutputStream objStream = new ObjectOutputStream(byteStream);
185            objStream.writeObject(model);
186            byte[] bytes = byteStream.toByteArray();
187            //Log.i(TAG, "getModel: " + bytes);
188            return bytes;
189        } catch (IOException e) {
190            throw new RuntimeException("Can't get model");
191        }
192    }
193
194    public boolean setModel(final byte [] modelData) {
195        //Log.i(TAG,"on setModel");
196        try {
197            ByteArrayInputStream input = new ByteArrayInputStream(modelData);
198            ObjectInputStream objStream = new ObjectInputStream(input);
199            Model model = (Model) objStream.readObject();
200            boolean res = loadModel(model);
201            //Log.i(TAG, "LoadModel: " + modelData);
202            return res;
203        } catch (IOException e) {
204            throw new RuntimeException("Can't load model");
205        } catch (ClassNotFoundException e) {
206            throw new RuntimeException("Learning class not found");
207        }
208    }
209
210    public IBinder getBinder() {
211        return this;
212    }
213
214    public void setModelChangeCallback(ModelChangeCallback callback) {
215        modelChangeCallback = callback;
216    }
217    // End of IBordeauxLearner Interface implemenation
218}
219