forked from MrBly/WalnutiQ
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathBigNeocortex.java
More file actions
350 lines (306 loc) · 15.8 KB
/
BigNeocortex.java
File metadata and controls
350 lines (306 loc) · 15.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
package model.MARK_II;
import com.google.gson.Gson;
import model.MARK_II.connectTypes.AbstractRegionToRegionConnect;
import model.MARK_II.region.Layer5Region;
import model.MARK_II.region.Region;
import model.MARK_II.util.*;
import model.MARK_II.util.BigClassUtil;
import model.MARK_II.util.Rectangle;
import java.awt.*;
import java.io.File;
import java.io.IOException;
/**
* NOTE: Refer to Neocortex.java for summary of how a Neocortex is represented.
*
* PROBLEM: When a user wants to create a Neocortex object that is too large for
* the Java Heap. This is usually when you want to build a Neocortex with 0
* .5+ million Neurons for a computer with 4GB of RAM.
*
* SOLUTION: This class provides a easy to use API for creating your
* Neocortex as separately
* saved JSON files.
*
* @author Q Liu (quinnliu@vt.edu)
* @version 6/15/2015.
*/
public class BigNeocortex {
private final double MAX_HEAP_USE_PERCENTAGE;
private String rootRegionName;
private String currentRegionName;
private AbstractRegionToRegionConnect connectType;
private String pathAndFolderNameWithoutEndingBacklash; // BigNeocortex is saved as JSON file
private Gson gson;
private HeapTracker heapTracker;
/**
* @param maxSizeOfARegionInMB
* @param regionParameterListInOrder Every 6 elements in list
* represent a
* list of parameters for 1
* Region. The
* parameters for the root region
* must
* be the first 6 elements in the
* list.
* @param neocortexRegionToNeocortexRegion
* @param connectionParameterListInOrder Every 7 elements in list
* represent a list of parameters
* for
* 1 directed connection between the
* currentRegion and the region
* provided in the list. When changing
* the current region the element
* MUST be in the format
* "change to region REGION_NAME"
* @param pathAndFolderNameWithoutEndingBacklash
*/
public BigNeocortex(int maxSizeOfARegionInMB, String[]
regionParameterListInOrder,
AbstractRegionToRegionConnect
neocortexRegionToNeocortexRegion,
String[] connectionParameterListInOrder, String
pathAndFolderNameWithoutEndingBacklash) throws IOException {
this.rootRegionName = regionParameterListInOrder[0];
this.connectType =
neocortexRegionToNeocortexRegion;
this.createUniqueFolderToSaveBigNeocortex(pathAndFolderNameWithoutEndingBacklash);
this.gson = new Gson();
this.heapTracker = new HeapTracker(false);
this.heapTracker.updateHeapData();
double maxHeapSizeInMB = (double) this.heapTracker
.getHeapMaxSizeInBytes() / 1000000;
this.MAX_HEAP_USE_PERCENTAGE = (double) maxSizeOfARegionInMB * 3 /
maxHeapSizeInMB;
if (this.MAX_HEAP_USE_PERCENTAGE > 1.0) {
throw new IllegalArgumentException("maxSizeOfARegionInMB is too " +
"large making MAX_HEAP_USE_PERCENTAGE > 1.0");
}
this.instantiateAndSaveAllUnconnectedRegions
(regionParameterListInOrder);
this.heapTracker.updateHeapData();
this.connectAllRegions(connectionParameterListInOrder);
this.heapTracker.updateHeapData();
this.heapTracker.printAllHeapDataToFile(this.pathAndFolderNameWithoutEndingBacklash +
"/heapSizeLogData_BigNeocortex.txt");
}
void connectAllRegions(String[] connectionParameterListInOrder) throws IOException {
for (int i = 0; i < connectionParameterListInOrder.length; i = i + 7) {
// NOTE: new connection pattern every 7 elements
// with 1 extra command in the following format: "change to region REGION_NAME"
if (connectionParameterListInOrder[i].toLowerCase().contains("change to region")) {
// extract region name to change currentRegion to
int numberOfCharIn_change_to_region = 17;
String regionName = connectionParameterListInOrder[i].substring(numberOfCharIn_change_to_region);
i++;
this.changeCurrentRegionTo(regionName);
} else {
// the next 7 elements specify a connection pattern between the
// currentRegion and the given region name
model.MARK_II.util.Rectangle rectanglePartOfParentRegionToConnectTo = new Rectangle(
new Point(Integer.valueOf(connectionParameterListInOrder[i]),
Integer.valueOf(connectionParameterListInOrder[i+1])),
new Point(Integer.valueOf(connectionParameterListInOrder[i+2]),
Integer.valueOf(connectionParameterListInOrder[i+3])));
Region childRegion = this.getRegion(connectionParameterListInOrder[i+4]);
this.heapTracker.updateHeapData();
int numberOfColumnsToOverlapAlongNumberOfRows = Integer.valueOf(connectionParameterListInOrder[i+5]);
int numberOfColumnsToOverlapAlongNumberOfColumns = Integer.valueOf(connectionParameterListInOrder[i+6]);
this.addToCurrentRegion(rectanglePartOfParentRegionToConnectTo, childRegion,
numberOfColumnsToOverlapAlongNumberOfRows, numberOfColumnsToOverlapAlongNumberOfColumns);
this.heapTracker.updateHeapData();
}
}
}
/**
* Sets root Region as currentRegion after completion.
*
* @param regionParameterListInOrder
* @throws IOException
*/
void instantiateAndSaveAllUnconnectedRegions(String[]
regionParameterListInOrder) throws IOException {
for (int i = 0; i < regionParameterListInOrder.length; i = i + 6) {
// NOTE: new region every 6 elements
Region region = null;
// convert String parameters into correct type
String biologicalName = regionParameterListInOrder[i];
int numberOfColumnsAlongRowsDimension = Integer.valueOf(
regionParameterListInOrder[i + 1]);
int numberOfColumnsAlongColumnsDimension = Integer.valueOf(
regionParameterListInOrder[i + 2]);
int cellsPerColumn = Integer.valueOf(
regionParameterListInOrder[i + 3]);
double percentMinimumOverlapScore = Double.valueOf(
regionParameterListInOrder[i + 4]);
int desiredLocalActivity = Integer.valueOf(
regionParameterListInOrder[i + 5]);
if (biologicalName.toLowerCase().contains("layer 5")) {
region = new Layer5Region(biologicalName,
numberOfColumnsAlongRowsDimension,
numberOfColumnsAlongColumnsDimension,
cellsPerColumn, percentMinimumOverlapScore,
desiredLocalActivity);
} else {
region = new Region(biologicalName,
numberOfColumnsAlongRowsDimension,
numberOfColumnsAlongColumnsDimension,
cellsPerColumn, percentMinimumOverlapScore,
desiredLocalActivity);
}
// 30% because we want enough room for at least 2 Regions and later
// for each Region to grow in size for all new synapses and
// dendrites created
if (this.heapTracker.isUsedHeapPercentageOver(this
.MAX_HEAP_USE_PERCENTAGE)) {
throw new IllegalArgumentException("your parameters for " +
"Region " + region.getBiologicalName() +
" are using too much of the heap and must be " +
"decreased");
}
// save Region as JSON file
this.saveRegion(region);
if (i == 0) {
// this is the root region's parameters since i == 0
this.currentRegionName = region.getBiologicalName();
}
}
}
/**
* @param pathAndFolderName
* @return The old path and new folder name the BigNeocortex object will
* be saved in.
*/
void createUniqueFolderToSaveBigNeocortex(String pathAndFolderName) {
File file = new File(pathAndFolderName);
File path = new File(BigClassUtil.extractPath(pathAndFolderName));
String newFolderName = BigClassUtil.extractFolderName(pathAndFolderName);
String pathAndNewFolderName = pathAndFolderName;
if (file.mkdir() == false) {
// if there is already a folder/file with the same name add
// a number to the folder name to be created
boolean foundUniqueName = false;
int i = 0;
while (foundUniqueName == false) {
if (BigClassUtil.isFolderInList(newFolderName, path.listFiles())) {
// we need to change newFolderName to something unique
CharSequence twoUnderscores = "__";
if (newFolderName.contains(twoUnderscores)) {
// this is not the first time this folder has been
// created so increment number after 2 underscores
int indexOf2Underscores = newFolderName.indexOf("__");
int indexOfFolderNumber = indexOf2Underscores + 2;
String folderNumber = newFolderName.substring
(indexOfFolderNumber);
int folderNumberPlusOne = Integer.valueOf
(folderNumber) + 1;
String newFolderNumber = String.valueOf
(folderNumberPlusOne);
newFolderName = newFolderName.replace(folderNumber,
newFolderNumber);
} else {
// this is the 2nd time this folder will be created
// with an extra number 0 at the end
newFolderName += "__" + String.valueOf(i);
}
} else {
foundUniqueName = true;
}
}
// now newFolderName is a unique name every time the program is run
// create a new folder to store BigNeocortex object
pathAndNewFolderName = path + "/" + newFolderName;
File whereToSaveBigNeocortex = new File(pathAndNewFolderName);
whereToSaveBigNeocortex.mkdir();
} else {
// file.mkdir() worked so there is no need to create a unique
// folder name
}
this.pathAndFolderNameWithoutEndingBacklash = pathAndNewFolderName;
}
public void changeCurrentRegionTo(String newCurrentRegionBiologicalName)
throws IOException {
this.currentRegionName = newCurrentRegionBiologicalName;
}
public Region getRegion(String regionBiologicalName) throws IOException {
if (regionBiologicalName == null) {
throw new IllegalArgumentException(
"newCurrentRegionBiologicalName in class Neocortex method" +
" getRegion() cannot be null");
}
File path = new File(this.pathAndFolderNameWithoutEndingBacklash);
boolean regionInNeocortex = BigClassUtil.isFileInList(regionBiologicalName + ".json"
, path.listFiles());
if (regionInNeocortex == false) {
return null;
}
String finalPathAndFile = this.pathAndFolderNameWithoutEndingBacklash + "/" +
regionBiologicalName + ".json";
String regionAsJSON = FileInputOutput.openObjectInTextFile
(finalPathAndFile);
Region region;
if (regionAsJSON.toLowerCase().contains("layer 5")) {
region = this.gson.fromJson(regionAsJSON, Layer5Region.class);
} else {
region = this.gson.fromJson(regionAsJSON, Region.class);
}
if (this.heapTracker.isUsedHeapPercentageOver(this
.MAX_HEAP_USE_PERCENTAGE)) {
throw new IllegalStateException("the region you are trying" +
" to get is taking too much space in the Java heap");
}
return region;
}
public void addToCurrentRegion(Rectangle
rectanglePartOfParentRegionToConnectTo,
Region childRegion,
int numberOfColumnsToOverlapAlongNumberOfRows,
int numberOfColumnsToOverlapAlongNumberOfColumns) throws IOException {
if (childRegion == null) {
throw new IllegalArgumentException(
"childRegion in class BigNeocortex method " +
"addToCurrentRegion cannot be null");
}
Region regionAlreadyInNeocortex = this.getRegion(childRegion
.getBiologicalName());
// NOTE: The first if and else if statement ARE necessary and
// it is important to understand why nothing should be done
if (regionAlreadyInNeocortex == null) {
// childRegion is new so we can add given childRegion to current
// region. Note this is not an error.
} else if (regionAlreadyInNeocortex.equals(childRegion)) {
// the user is trying to make a cycle connection within region in
// the Neocortex which is allowed
} else if (regionAlreadyInNeocortex != null) {
throw new IllegalArgumentException(
"childRegion in class BigNeocortex method addToCurrentRegion" +
" already exists within the BigNeocortex as another region " +
"with the same name");
}
Region currentRegion = this.getRegion(this.currentRegionName);
currentRegion.addChildRegion(childRegion);
this.connectType.connect(childRegion.getColumns(),
currentRegion.getColumns
(rectanglePartOfParentRegionToConnectTo),
numberOfColumnsToOverlapAlongNumberOfRows,
numberOfColumnsToOverlapAlongNumberOfColumns);
if (this.heapTracker.isUsedHeapPercentageOver(this
.MAX_HEAP_USE_PERCENTAGE)) {
throw new IllegalArgumentException("The current region and child region" +
"you are adding is taking too much space in the heap");
}
// We just changed currentRegion so resave it
File pathToRegionFile = new File(this.pathAndFolderNameWithoutEndingBacklash + "/" +
this.currentRegionName + ".json");
pathToRegionFile.delete();
this.saveRegion(currentRegion);
}
public Region getCurrentRegion() throws IOException {
return this.getRegion(this.currentRegionName);
}
void saveRegion(Region region) throws IOException {
String regionAsJSON = this.gson.toJson(region);
String finalPathAndFile = this.pathAndFolderNameWithoutEndingBacklash + "/" +
region.getBiologicalName() + ".json";
FileInputOutput.saveObjectToTextFile(regionAsJSON,
finalPathAndFile);
}
}