aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rwxr-xr-xapp/src/androidTest/java/org/rssin/neurons/FeedSorterTest.java96
-rwxr-xr-xapp/src/androidTest/java/org/rssin/neurons/NeuralNetworkTest.java10
-rw-r--r--app/src/androidTest/java/org/rssin/rss/FeedLoaderTest.java23
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/FeedSorter.java168
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/Feedback.java23
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java10
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/MultiNeuralNetworkPrediction.java23
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/NeuralNetwork.java44
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/NeuralNetworkPrediction.java10
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/Neuron.java13
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/PredictionInterface.java10
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/SentenceSplitter.java33
-rwxr-xr-xapp/src/main/java/org/rssin/neurons/TrainingCase.java11
-rw-r--r--app/src/main/java/org/rssin/rss/FeedLoader.java56
-rwxr-xr-xapp/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java12
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher.pngbin3418 -> 2791 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher.pngbin2206 -> 1838 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin4842 -> 3976 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin7718 -> 6489 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 9188 bytes
20 files changed, 322 insertions, 220 deletions
diff --git a/app/src/androidTest/java/org/rssin/neurons/FeedSorterTest.java b/app/src/androidTest/java/org/rssin/neurons/FeedSorterTest.java
index a2d59ee..a6e3581 100755
--- a/app/src/androidTest/java/org/rssin/neurons/FeedSorterTest.java
+++ b/app/src/androidTest/java/org/rssin/neurons/FeedSorterTest.java
@@ -20,7 +20,7 @@ public class FeedSorterTest extends TestCase {
Assert.assertTrue(true);
}
- public void testSortItems() throws Exception {
+ public void testSortItemsByCategory() throws Exception {
List<String> gameList = new ArrayList<>();
gameList.add("Games");
List<String> sportList = new ArrayList<>();
@@ -39,28 +39,90 @@ public class FeedSorterTest extends TestCase {
FeedSorter s = new FeedSorter();
//I like games & I hate sports
- for(int i = 0; i < 100; i++)
- {
- for(FeedItem item : likedItems)
- {
- s.feedback(item, Feedback.Like);
- }
-
- for(FeedItem item : dislikedItems)
- {
- s.feedback(item, Feedback.Dislike);
- }
- }
+ trainNetwork(likedItems, dislikedItems, s);
FeedItem sportsItem = new FeedItem("", new Date(2014, 1, 1, 1, 2, 1), "SPORT ARTICLE", "DESCRIPTION", "", "Randy", sportList, "", "", "");
FeedItem gamesItem = new FeedItem("", new Date(2014, 1, 1, 1, 1, 1), "GAME ARTICLE", "DESCRIPTION", "", "Randy", gameList, "", "", "");
+ testSortingOrder(s, sportsItem, gamesItem);
+ }
+
+ public void testSortItemsByTitle() throws Exception {
+ List<String> emptyList = new ArrayList<>();
+
+ FeedItem[] likedItems = new FeedItem[]
+ {
+ new FeedItem("", new Date(), "Video games are cool", "DESCRIPTION", "", "Randy", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "The new video game", "DESCRIPTION", "", "Camil", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "Best games of 2015", "DESCRIPTION", "", "Jos", emptyList, "", "", ""),
+ };
+
+ FeedItem[] dislikedItems = new FeedItem[]
+ {
+ new FeedItem("", new Date(), "Video of a cat", "DESCRIPTION", "", "Randy", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "It's raining", "DESCRIPTION", "", "Joep", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "Shocking video of a cat in the rain.", "DESCRIPTION", "", "Joep", emptyList, "", "", ""),
+ };
+
+ FeedSorter s = new FeedSorter();
+
+ //I like games & I hate sports
+ trainNetwork(likedItems, dislikedItems, s);
+
+ FeedItem dislikedItem = new FeedItem("", new Date(2014, 1, 1, 1, 2, 1), "Another cool video of a cat in the sun.", "DESCRIPTION", "", "Randy", emptyList, "", "", "");
+ FeedItem likedItem = new FeedItem("", new Date(2014, 1, 1, 1, 1, 1), "Coolest retro games", "DESCRIPTION", "", "Jos", emptyList, "", "", "");
+
+ testSortingOrder(s, dislikedItem, likedItem);
+ }
+
+ public void testSortItemsByAuthor() throws Exception {
+ List<String> emptyList = new ArrayList<>();
+
+ FeedItem[] likedItems = new FeedItem[]
+ {
+ new FeedItem("", new Date(), "Best games of 2015", "DESCRIPTION", "", "Jos", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "It's raining cats and dogs!", "DESCRIPTION", "", "Jos", emptyList, "", "", ""),
+ };
+
+ FeedItem[] dislikedItems = new FeedItem[]
+ {
+ new FeedItem("", new Date(), "Video of a cat", "DESCRIPTION", "", "Randy", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "It's raining", "DESCRIPTION", "", "Joep", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "Shocking video of a cat in the rain.", "DESCRIPTION", "", "Joep", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "Video games are cool", "DESCRIPTION", "", "Randy", emptyList, "", "", ""),
+ new FeedItem("", new Date(), "The new video game", "DESCRIPTION", "", "Camil", emptyList, "", "", ""),
+ };
+
+ FeedSorter s = new FeedSorter();
+
+ //I like games & I hate sports
+ trainNetwork(likedItems, dislikedItems, s);
+
+ FeedItem dislikedItem = new FeedItem("", new Date(2014, 1, 1, 1, 2, 1), "Another cool video of a cat in the sun.", "DESCRIPTION", "", "Randy", emptyList, "", "", "");
+ FeedItem likedItem = new FeedItem("", new Date(2014, 1, 1, 1, 1, 1), "Coolest retro games", "DESCRIPTION", "", "Jos", emptyList, "", "", "");
+
+ testSortingOrder(s, dislikedItem, likedItem);
+ }
+
+ private void testSortingOrder(FeedSorter s, FeedItem dislikedItem, FeedItem likedItem) {
List<FeedItem> testItems = new LinkedList<>();
- testItems.add(sportsItem);
- testItems.add(gamesItem);
+ testItems.add(dislikedItem);
+ testItems.add(likedItem);
List<FeedItem> sortedItems = s.sortItems(testItems);
- Assert.assertEquals(sortedItems.get(0), gamesItem);
- Assert.assertEquals(sortedItems.get(1), sportsItem);
+ Assert.assertEquals(sortedItems.get(0), likedItem);
+ Assert.assertEquals(sortedItems.get(1), dislikedItem);
+ }
+
+ private void trainNetwork(FeedItem[] likedItems, FeedItem[] dislikedItems, FeedSorter s) {
+ for(int i = 0; i < 200; i++) {
+ for (FeedItem item : likedItems) {
+ s.feedback(item, Feedback.Like);
+ }
+
+ for (FeedItem item : dislikedItems) {
+ s.feedback(item, Feedback.Dislike);
+ }
+ }
}
} \ No newline at end of file
diff --git a/app/src/androidTest/java/org/rssin/neurons/NeuralNetworkTest.java b/app/src/androidTest/java/org/rssin/neurons/NeuralNetworkTest.java
index b0f6eea..57776f3 100755
--- a/app/src/androidTest/java/org/rssin/neurons/NeuralNetworkTest.java
+++ b/app/src/androidTest/java/org/rssin/neurons/NeuralNetworkTest.java
@@ -7,12 +7,12 @@ public class NeuralNetworkTest extends TestCase {
public void testAnd() throws Exception {
MultiNeuralNetwork nn = new MultiNeuralNetwork(10, 2);
- nn.addInput();
- nn.addInput();
- nn.addInput();
+ nn.addInput();//bias
+ nn.addInput();//inputA
+ nn.addInput();//inputB
//Simple AND
- for (int i = 0; i < 100; i++)
+ for (int i = 0; i < 300; i++)
{
PredictionInterface p1 = nn.computeOutput(new double[] {
1,
@@ -75,7 +75,7 @@ public class NeuralNetworkTest extends TestCase {
nn.addInput();
//Simple AND
- for (int i = 0; i < 100; i++)
+ for (int i = 0; i < 300; i++)
{
PredictionInterface p1 = nn.computeOutput(new double[] {
1,
diff --git a/app/src/androidTest/java/org/rssin/rss/FeedLoaderTest.java b/app/src/androidTest/java/org/rssin/rss/FeedLoaderTest.java
new file mode 100644
index 0000000..f4bbfdd
--- /dev/null
+++ b/app/src/androidTest/java/org/rssin/rss/FeedLoaderTest.java
@@ -0,0 +1,23 @@
+package org.rssin.rss;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.net.URL;
+
+/**
+ * Created by Randy on 21-5-2015.
+ */
+public class FeedLoaderTest extends TestCase {
+
+
+ public void testFetchXML() throws Exception {
+ String urlstring = "http://www.pcworld.com/index.rss";
+ URL url = new URL(urlstring);
+ FeedLoader loader = new FeedLoader(url);
+ loader.fetchXML();
+ FeedItem f = loader.getFeed().getPosts().get(0);
+ Assert.assertEquals(f.getTitle(), "Amazon adds local groceries and meals to one-hour Prime Now delivery service");
+ }
+
+} \ No newline at end of file
diff --git a/app/src/main/java/org/rssin/neurons/FeedSorter.java b/app/src/main/java/org/rssin/neurons/FeedSorter.java
index 157a8f7..8549fcf 100755
--- a/app/src/main/java/org/rssin/neurons/FeedSorter.java
+++ b/app/src/main/java/org/rssin/neurons/FeedSorter.java
@@ -1,55 +1,41 @@
package org.rssin.neurons;
-import android.gesture.Prediction;
-
import org.rssin.rss.FeedItem;
-import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.TimeZone;
/**
- * Created by Jos on 14-5-2015.
+ * @author Jos.
*/
-public class FeedSorter implements Serializable{
+public class FeedSorter implements Serializable {
private static final long serialVersionUID = 0;
- private final int MAX_TRAINING_HISTORY = 250;
- private final int SECONDS_IN_DAY = 24 * 60 * 60;
-
- private MultiNeuralNetwork nn = new MultiNeuralNetwork(25, 50);
+ private final SentenceSplitter splitter = new SentenceSplitter();
+ private final MultiNeuralNetwork nn = new MultiNeuralNetwork(25, 50);
+ private final List<TrainingCase> trainingCases = new ArrayList<>();
- private List<TrainingCase> trainingCases = new ArrayList<>();
-
- private int[] isNthMonthInput = new int[12];
- private int[] isNthWeekDayInput = new int[7];
- private int isMorning, isAfternoon, isEvening, isNight, biasInput;
- private Hashtable<String, Integer> categoryInputs = new Hashtable<String, Integer>();
- //private Hashtable<String, Integer> wordInputs = new Hashtable<String, Integer>();
- //private Hashtable<String, Integer> feedSourceInputs = new Hashtable<String, Integer>();
+ private final int[] isNthMonthInput = new int[12];
+ private final int[] isNthWeekDayInput = new int[7];
+ private final int isMorning, isAfternoon, isEvening, isNight, biasInput;
+ private final Hashtable<String, Integer> categoryInputs = new Hashtable<>();
+ private final Hashtable<String, Integer> wordInputs = new Hashtable<>();
+ private final Hashtable<String, Integer> authorInputs = new Hashtable<>();
public FeedSorter() {
- createNewNetwork();
- }
-
- private void createNewNetwork() {
biasInput = nn.addInput();
- for(int i = 0; i < 12; i++)
- {
+ for (int i = 0; i < 12; i++) {
isNthMonthInput[i] = nn.addInput();
}
- for(int i = 0; i < 7; i++)
- {
+ for (int i = 0; i < 7; i++) {
isNthWeekDayInput[i] = nn.addInput();
}
@@ -60,83 +46,83 @@ public class FeedSorter implements Serializable{
}
private PredictionInterface getPrediction(FeedItem item) {
- //Add new inputs for categories.
- for(String category : item.getCategory())
- {
- category = category.toLowerCase();
- if(!categoryInputs.containsKey(category))
- {
- categoryInputs.put(category, nn.addInput());
- }
- }
+ List<String> words = splitter.splitSentence(item.getTitle());
- double[] inputs = new double[nn.getInputCount()];
+ addNewInputs(item.getCategory(), categoryInputs);
+ addNewInputs(words, wordInputs);
+ addNewInput(item.getAuthor(), authorInputs);
+ double[] inputs = newArrayInitializedToNegativeOne();
inputs[biasInput] = 1;
- //Initialize all inputs to -1 / false
- for(int i = 0; i < inputs.length; i++)
- {
- inputs[i] = -1;
- }
-
- //Set month
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- for(int i = 0; i < isNthMonthInput.length; i++)
- {
- if(cal.get(Calendar.MONTH) - cal.getMinimum(Calendar.MONTH) == i)
- {
- inputs[isNthMonthInput[i]] = 1;
- }
- }
- //Set weekday
- for(int i = 0; i < isNthWeekDayInput.length; i++)
- {
- if(cal.get(Calendar.DAY_OF_WEEK) - cal.getMinimum(Calendar.DAY_OF_WEEK) == i)
- {
- inputs[isNthMonthInput[i]] = 1;
- }
- }
+ //Set month & weekday
+ inputs[isNthMonthInput[cal.get(Calendar.MONTH) - cal.getMinimum(Calendar.MONTH)]] = 1;
+ inputs[isNthWeekDayInput[cal.get(Calendar.DAY_OF_WEEK) - cal.getMinimum(Calendar.DAY_OF_WEEK)]] = 1;
- //Set day
+ //Set time
int hourOfDay = cal.get(Calendar.HOUR_OF_DAY);
- if(hourOfDay > 6 && hourOfDay < 12)
- {
+ if (hourOfDay > 6 && hourOfDay < 12) {
inputs[isMorning] = 1;
- }else if(hourOfDay >= 12 && hourOfDay <= 6)
- {
+ } else if (hourOfDay >= 12 && hourOfDay <= 6) {
inputs[isAfternoon] = 1;
- }else if(hourOfDay >= 6 && hourOfDay < 23)
- {
+ } else if (hourOfDay >= 6 && hourOfDay < 23) {
inputs[isEvening] = 1;
- }else if(hourOfDay >= 23 || hourOfDay <= 6)
- {
+ } else if (hourOfDay >= 23 || hourOfDay <= 6) {
inputs[isNight] = 1;
}
- for(String category : item.getCategory())
- {
+ for (String category : item.getCategory()) {
inputs[categoryInputs.get(category.toLowerCase())] = 1;
}
+ for (String word : words) {
+ inputs[wordInputs.get(word)] = 1;
+ }
+
+ if (item.getAuthor() != null) {
+ inputs[authorInputs.get(item.getAuthor().toLowerCase())] = 1;
+ }
+
return nn.computeOutput(inputs);
}
+ private double[] newArrayInitializedToNegativeOne() {
+ double[] inputs = new double[nn.getInputCount()];
+ Arrays.fill(inputs, 0, inputs.length, -1);
+ return inputs;
+ }
+
+ private void addNewInputs(Iterable<String> words, Hashtable<String, Integer> map) {
+ for (String word : words) {
+ addNewInput(word, map);
+ }
+ }
+
+ private void addNewInput(String word, Hashtable<String, Integer> map) {
+ if (word != null) {
+ word = word.toLowerCase();
+ if (!map.containsKey(word)) {
+ map.put(word, nn.addInput());
+ }
+ }
+ }
+
/**
* Provides feedback to the neural network.
- * @param item The feeditem.
+ *
+ * @param item The feeditem.
* @param feedback The feedback. Like will move these types of items up in the list,
* dislike will move them down.
*/
- public void feedback(FeedItem item, Feedback feedback)
- {
+ public void feedback(FeedItem item, Feedback feedback) {
PredictionInterface prediction = getPrediction(item);
prediction.learn(feedback.toExpectedOutput());
trainingCases.add(new TrainingCase(prediction.getInputs(), feedback));
- while(trainingCases.size() > MAX_TRAINING_HISTORY)
- {
+ final int MAX_TRAINING_HISTORY = 250;
+ while (trainingCases.size() > MAX_TRAINING_HISTORY) {
trainingCases.remove(0);
}
}
@@ -144,13 +130,10 @@ public class FeedSorter implements Serializable{
/**
* Runs an iteration of training, using feedback that was provided previously using FeedSorter.feedback(...).
*/
- public void train()
- {
- for(TrainingCase t : trainingCases)
- {
+ public void train() {
+ for (TrainingCase t : trainingCases) {
double[] inputs = t.getInputs();
- if(inputs.length < nn.getInputCount())
- {
+ if (inputs.length < nn.getInputCount()) {
// Resize array to fit new input size
inputs = Arrays.copyOf(inputs, nn.getInputCount());
}
@@ -162,29 +145,28 @@ public class FeedSorter implements Serializable{
/**
* Returns a sorted list of all the items in the List, according to the neural network.
+ *
* @param items The list of items.
* @return A new, sorted, list of items. The parameter items is not modified.
*/
public List<FeedItem> sortItems(List<FeedItem> items) {
- // Sort list based on something like date + nn.computeOutput() * DAY.
- List<FeedItem> newItems = new ArrayList<FeedItem>(items);
- final Hashtable<FeedItem, PredictionInterface> predictions = new Hashtable<>();
+ final int SECONDS_IN_DAY = 24 * 60 * 60;
+
+ final List<FeedItem> newItems = new ArrayList<>(items);
+ final Hashtable<FeedItem, Long> predictions = new Hashtable<>();
- for(FeedItem feed : newItems)
- {
- predictions.put(feed, getPrediction(feed));
+ for (FeedItem item : newItems) {
+ PredictionInterface prediction = getPrediction(item);
+ predictions.put(item, (long) (prediction.getOutput() * SECONDS_IN_DAY));
}
Collections.sort(newItems, new Comparator<FeedItem>() {
@Override
public int compare(FeedItem lhs, FeedItem rhs) {
- PredictionInterface lPrediction = predictions.get(lhs),
- rPrediction = predictions.get(rhs);
-
- long lhsSeconds = (long)(lhs.getPubDate().getTime() / 1000 + lPrediction.getOutput() * SECONDS_IN_DAY);
- long rhsSeconds = (long)(rhs.getPubDate().getTime() / 1000 + rPrediction.getOutput() * SECONDS_IN_DAY);
+ long lhsScore = lhs.getPubDate().getTime() / 1000 + predictions.get(lhs);
+ long rhsScore = rhs.getPubDate().getTime() / 1000 + predictions.get(rhs);
- return (int)Math.signum(rhsSeconds - lhsSeconds);
+ return (int) Math.signum(rhsScore - lhsScore);
}
});
diff --git a/app/src/main/java/org/rssin/neurons/Feedback.java b/app/src/main/java/org/rssin/neurons/Feedback.java
index 9652b2b..fe59b1b 100755
--- a/app/src/main/java/org/rssin/neurons/Feedback.java
+++ b/app/src/main/java/org/rssin/neurons/Feedback.java
@@ -1,21 +1,18 @@
package org.rssin.neurons;
/**
- * Created by Jos on 19-5-2015.
+ * @author Jos.
*/
public enum Feedback {
- Like, Dislike;
+ Like(1.0d), Dislike(-1.0d);
- double toExpectedOutput()
- {
- switch(this)
- {
- case Like:
- return 1;
- case Dislike:
- return -1;
- default:
- throw new IllegalArgumentException();
- }
+ private final double expectedOutput;
+
+ private Feedback(double expectedOutput) {
+ this.expectedOutput = expectedOutput;
+ }
+
+ double toExpectedOutput() {
+ return expectedOutput;
}
}
diff --git a/app/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java b/app/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java
index a2f06eb..03ad2d1 100755
--- a/app/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java
+++ b/app/src/main/java/org/rssin/neurons/MultiNeuralNetwork.java
@@ -3,11 +3,12 @@ package org.rssin.neurons;
import java.io.Serializable;
/**
- * Created by Jos on 14-5-2015.
+ * @author Jos
+ * Is used to migitate the problem of neural networks ending up in the wrong local minimum.
*/
-class MultiNeuralNetwork implements Serializable{
+class MultiNeuralNetwork implements Serializable {
private static final long serialVersionUID = 0;
- private NeuralNetwork[] networks;
+ private final NeuralNetwork[] networks;
public MultiNeuralNetwork(int numNetworks, int numHiddenNodes) {
networks = new NeuralNetwork[numNetworks];
@@ -27,8 +28,7 @@ class MultiNeuralNetwork implements Serializable{
public PredictionInterface computeOutput(double[] inputs) {
PredictionInterface[] predictions = new PredictionInterface[networks.length];
- for(int i = 0; i < predictions.length; i++)
- {
+ for (int i = 0; i < predictions.length; i++) {
predictions[i] = networks[i].computeOutput(inputs);
}
diff --git a/app/src/main/java/org/rssin/neurons/MultiNeuralNetworkPrediction.java b/app/src/main/java/org/rssin/neurons/MultiNeuralNetworkPrediction.java
index dc85261..f618749 100755
--- a/app/src/main/java/org/rssin/neurons/MultiNeuralNetworkPrediction.java
+++ b/app/src/main/java/org/rssin/neurons/MultiNeuralNetworkPrediction.java
@@ -1,22 +1,20 @@
package org.rssin.neurons;
/**
- * Created by Jos on 14-5-2015.
+ * @author Jos.
*/
class MultiNeuralNetworkPrediction implements PredictionInterface {
- private PredictionInterface[] predictions;
- MultiNeuralNetworkPrediction(PredictionInterface[] predictions)
- {
- if(predictions.length <= 0)
- {
+ private final PredictionInterface[] predictions;
+
+ MultiNeuralNetworkPrediction(PredictionInterface[] predictions) {
+ if (predictions.length <= 0) {
throw new IllegalArgumentException("predictions");
}
this.predictions = predictions;
}
- public double getOutput()
- {
+ public double getOutput() {
double average = 0;
for (PredictionInterface prediction : predictions) {
average += prediction.getOutput();
@@ -25,16 +23,13 @@ class MultiNeuralNetworkPrediction implements PredictionInterface {
return average / (double) predictions.length;
}
- public void learn(double expectedOutput)
- {
- for(PredictionInterface prediction : predictions)
- {
+ public void learn(double expectedOutput) {
+ for (PredictionInterface prediction : predictions) {
prediction.learn(expectedOutput);
}
}
- public double[] getInputs()
- {
+ public double[] getInputs() {
return predictions[0].getInputs();
}
}
diff --git a/app/src/main/java/org/rssin/neurons/NeuralNetwork.java b/app/src/main/java/org/rssin/neurons/NeuralNetwork.java
index 620d5bd..0acfda7 100755
--- a/app/src/main/java/org/rssin/neurons/NeuralNetwork.java
+++ b/app/src/main/java/org/rssin/neurons/NeuralNetwork.java
@@ -1,18 +1,19 @@
package org.rssin.neurons;
+import android.annotation.SuppressLint;
+
import java.io.Serializable;
/**
- * Created by Jos on 14-5-2015.
+ * @author Jos.
*/
-class NeuralNetwork implements Serializable{
+class NeuralNetwork implements Serializable {
private static final long serialVersionUID = 0;
- private Neuron[] hiddenNodes;
- private Neuron outputNode;
+ private final Neuron[] hiddenNodes;
+ private final Neuron outputNode;
- public NeuralNetwork(int numHiddenNodes) {
- if(numHiddenNodes < 1)
- {
+ NeuralNetwork(int numHiddenNodes) {
+ if (numHiddenNodes < 1) {
throw new IllegalArgumentException("numHiddenNodes must be > 0");
}
@@ -25,18 +26,22 @@ class NeuralNetwork implements Serializable{
outputNode = new Neuron(numHiddenNodes + 1);
}
- public int addInput() {
+ @SuppressLint("Assert")
+ int addInput() {
+ assert hiddenNodes.length > 0;
+
int result = 0;
- for (int i = 0; i < hiddenNodes.length; i++) {
- result = hiddenNodes[i].addWeight();
+ for (Neuron hiddenNode : hiddenNodes) {
+ result = hiddenNode.addWeight();
}
return result;
}
- public PredictionInterface computeOutput(double[] inputs) {
+ PredictionInterface computeOutput(double[] inputs) {
double[] intermediateValues = new double[outputNode.getWeightCount()];
+ //Output of hidden neurons
for (int neuronNum = 0; neuronNum < hiddenNodes.length; neuronNum++) {
Neuron n = hiddenNodes[neuronNum];
@@ -57,27 +62,32 @@ class NeuralNetwork implements Serializable{
}
void learn(NeuralNetworkPrediction p, double expectedOutput) {
+ //TODO: See if adding momentum helps avoid local minimum
double actualOutput = p.getOutput();
double[] intermediateValues = p.getIntermediateValues();
double[] inputs = p.getInputs();
- double[] hiddenGradients = new double[hiddenNodes.length];
-
- //Calculate output gradients
+ //Calculate output gradient
double outputDerivative = (1 - actualOutput) * (1 + actualOutput);
//Derivative of HyperTan function
double outputGradient = outputDerivative * (expectedOutput - actualOutput);
- //Calulate hidden gradients
+ //Calculate hidden gradients
+ double[] hiddenGradients = new double[hiddenNodes.length];
for (int i = 0; i < hiddenGradients.length; i++) {
//Derivative of HyperTan function
double hiddenDerivative = (1 - intermediateValues[i]) * (1 + intermediateValues[i]);
hiddenGradients[i] = hiddenDerivative * outputGradient * outputNode.getWeight(i);
}
+ updateWeights(intermediateValues, inputs, hiddenGradients, outputGradient);
+ }
+
+ private void updateWeights(double[] intermediateValues, double[] inputs, double[] hiddenGradients, double outputGradient) {
+ final double learningRate = 0.2;
+
//Update input => hidden weights.
- final double learningRate = 0.3;
for (int neuronNum = 0; neuronNum < hiddenNodes.length; neuronNum++) {
Neuron n = hiddenNodes[neuronNum];
@@ -102,7 +112,7 @@ class NeuralNetwork implements Serializable{
else return Math.tanh(x);
}
- public int getInputCount() {
+ int getInputCount() {
return hiddenNodes[0].getWeightCount();
}
}
diff --git a/app/src/main/java/org/rssin/neurons/NeuralNetworkPrediction.java b/app/src/main/java/org/rssin/neurons/NeuralNetworkPrediction.java
index 9d6fc89..169caee 100755
--- a/app/src/main/java/org/rssin/neurons/NeuralNetworkPrediction.java
+++ b/app/src/main/java/org/rssin/neurons/NeuralNetworkPrediction.java
@@ -1,13 +1,13 @@
package org.rssin.neurons;
/**
- * Created by Jos on 14-5-2015.
+ * @author Jos.
*/
class NeuralNetworkPrediction implements PredictionInterface {
- private double[] inputs;
- private double[] intermediateValues;
- private double output;
- private NeuralNetwork nn;
+ private final double[] inputs;
+ private final double[] intermediateValues;
+ private final double output;
+ private final NeuralNetwork nn;
NeuralNetworkPrediction(NeuralNetwork nn, double[] inputs, double[] intermediateValues, double output) {
this.inputs = inputs;
diff --git a/app/src/main/java/org/rssin/neurons/Neuron.java b/app/src/main/java/org/rssin/neurons/Neuron.java
index 724732d..23f69e1 100755
--- a/app/src/main/java/org/rssin/neurons/Neuron.java
+++ b/app/src/main/java/org/rssin/neurons/Neuron.java
@@ -1,17 +1,18 @@
package org.rssin.neurons;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
- * Created by Jos on 14-5-2015.
+ * @author Jos.
*/
-class Neuron {
+class Neuron implements Serializable {
private static final long serialVersionUID = 0;
- private static Random r = new Random();
+ private static final Random r = new Random();
- private List<Double> weights = new ArrayList<Double>();
+ private final List<Double> weights = new ArrayList<>();
public Neuron() {
}
@@ -23,7 +24,9 @@ class Neuron {
}
public int addWeight() {
- weights.add(r.nextDouble() * 2 - 1);
+ // Initial values range from -.5 to .5. The exact value does not matter,
+ // as long as they aren't all 0.
+ weights.add(r.nextDouble() - .5);
return weights.size() - 1;
}
diff --git a/app/src/main/java/org/rssin/neurons/PredictionInterface.java b/app/src/main/java/org/rssin/neurons/PredictionInterface.java
index 27a214f..ff46992 100755
--- a/app/src/main/java/org/rssin/neurons/PredictionInterface.java
+++ b/app/src/main/java/org/rssin/neurons/PredictionInterface.java
@@ -1,10 +1,12 @@
package org.rssin.neurons;
/**
- * Created by Jos on 14-5-2015.
+ * @author Jos.
*/
interface PredictionInterface {
- public double getOutput();
- public void learn(double expectedOutput);
- public double[] getInputs();
+ double getOutput();
+
+ void learn(double expectedOutput);
+
+ double[] getInputs();
}
diff --git a/app/src/main/java/org/rssin/neurons/SentenceSplitter.java b/app/src/main/java/org/rssin/neurons/SentenceSplitter.java
new file mode 100755
index 0000000..887439d
--- /dev/null
+++ b/app/src/main/java/org/rssin/neurons/SentenceSplitter.java
@@ -0,0 +1,33 @@
+package org.rssin.neurons;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Jos.
+ */
+public class SentenceSplitter {
+ private final Pattern wordMatch = Pattern.compile("[\\w-]+");//For unicode support, add the Pattern.UNICODE_CHARACTER_CLASS flag. Works only in Java 7+.
+
+ public SentenceSplitter() {
+ }
+
+ /**
+ * Returns all the words in a sentence.
+ *
+ * @param sentence The sentence.
+ * @return The list of words in a sentence.
+ */
+ public List<String> splitSentence(String sentence) {
+ List<String> allMatches = new ArrayList<>();
+ Matcher m = wordMatch.matcher(sentence);
+
+ while (m.find()) {
+ allMatches.add(m.group().toLowerCase());
+ }
+
+ return allMatches;
+ }
+}
diff --git a/app/src/main/java/org/rssin/neurons/TrainingCase.java b/app/src/main/java/org/rssin/neurons/TrainingCase.java
index 77162be..69f72cb 100755
--- a/app/src/main/java/org/rssin/neurons/TrainingCase.java
+++ b/app/src/main/java/org/rssin/neurons/TrainingCase.java
@@ -3,15 +3,14 @@ package org.rssin.neurons;
import java.io.Serializable;
/**
- * Created by Jos on 20-5-2015.
+ * @author Jos.
*/
class TrainingCase implements Serializable {
- private static long serialVersionID;
- private double[] inputs;
- private Feedback feedback;
+ private static final long serialVersionUID = 0;
+ private final double[] inputs;
+ private final Feedback feedback;
- public TrainingCase(double[] inputs, Feedback feedback)
- {
+ public TrainingCase(double[] inputs, Feedback feedback) {
this.inputs = inputs;
this.feedback = feedback;
}
diff --git a/app/src/main/java/org/rssin/rss/FeedLoader.java b/app/src/main/java/org/rssin/rss/FeedLoader.java
index 726cbac..eabfebd 100644
--- a/app/src/main/java/org/rssin/rss/FeedLoader.java
+++ b/app/src/main/java/org/rssin/rss/FeedLoader.java
@@ -25,7 +25,7 @@ public class FeedLoader {
private String text;
public FeedLoader(URL url){
- this.urlString = url;
+ this.setUrlString(url);
}
/**
@@ -48,15 +48,15 @@ public class FeedLoader {
case "item":
post = new FeedItem(null, null, null, null, null,
null, new LinkedList<String>(), null, null, null);
- chan = false; //this starts collection information for the
+ chan = false; //this starts collecting information for the
//separate items.
break;
case "image":
imageTagParse(myParser);
case "channel":
feed = new Feed(new LinkedList<String>(), null, null, null, null,
- null, null, null, null, null, null, null, null, null, null,
- null, null, null, null);
+ null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null);
chan = true;
break;
}
@@ -214,31 +214,25 @@ public class FeedLoader {
/**
* Retrieves the XML and parses it.
*/
- public void fetchXML(){
- Thread thread = new Thread(new Runnable(){
- @Override
- public void run() {
- try {
- URL url = urlString;
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setReadTimeout(10000 /* milliseconds */);
- conn.setConnectTimeout(15000 /* milliseconds */);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- // Starts the query
- conn.connect();
- InputStream stream = conn.getInputStream();
- xmlFactoryObject = XmlPullParserFactory.newInstance();
- XmlPullParser myparser = xmlFactoryObject.newPullParser();
- myparser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
- myparser.setInput(stream, null);
- parseXMLAndStoreIt(myparser);
- stream.close();
- } catch (Exception ignored) {
- }
- }
- });
- thread.start();
+ public void fetchXML() {
+ try {
+ URL url = urlString;
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setReadTimeout(10000 /* milliseconds */);
+ conn.setConnectTimeout(15000 /* milliseconds */);
+ conn.setRequestMethod("GET");
+ conn.setDoInput(true);
+ // Starts the query
+ conn.connect();
+ InputStream stream = conn.getInputStream();
+ xmlFactoryObject = XmlPullParserFactory.newInstance();
+ XmlPullParser myparser = xmlFactoryObject.newPullParser();
+ myparser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+ myparser.setInput(stream, null);
+ parseXMLAndStoreIt(myparser);
+ stream.close();
+ } catch (Exception ignored) {
+ }
}
public void setFeed(Feed feed) {
@@ -248,4 +242,8 @@ public class FeedLoader {
public Feed getFeed() {
return feed;
}
+
+ public void setUrlString(URL urlString) {
+ this.urlString = urlString;
+ }
}
diff --git a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
index eda0526..e9d3e5d 100755
--- a/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
+++ b/app/src/main/java/org/rssin/rssin/FeedLoaderAndSorter.java
@@ -28,8 +28,7 @@ public class FeedLoaderAndSorter {
{
FeedLoader loader = new FeedLoader(feed.getURL());
loader.fetchXML();
- org.rssin.rss.Feed loadedFeed = loader.getFeed();
- for(FeedItem item : loadedFeed.getPosts())
+ for(FeedItem item : loader.getFeed().getPosts())
{
if(matchesKeyword(item))
{
@@ -55,10 +54,9 @@ public class FeedLoaderAndSorter {
return filter.getKeywords().size() == 0;
}
- private static boolean contains( String haystack, String needle ) {
- haystack = haystack == null ? "" : haystack;
- needle = needle == null ? "" : needle;
-
- return haystack.toLowerCase().contains(needle.toLowerCase());
+ private static boolean contains(String haystack, String needle) {
+ return haystack != null
+ && needle != null
+ && haystack.toLowerCase().contains(needle.toLowerCase());
}
}
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
index cde69bc..2e7f377 100644
--- a/app/src/main/res/mipmap-hdpi/ic_launcher.png
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
index c133a0c..c7d5ca5 100644
--- a/app/src/main/res/mipmap-mdpi/ic_launcher.png
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index bfa42f0..8d1bf3a 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_launcher.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 324e72c..9e7e711 100644
--- a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..63c5a0d
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ