source: src/main/java/agents/anac/y2019/harddealer/math3/ml/neuralnet/Neuron.java

Last change on this file was 204, checked in by Katsuhide Fujita, 5 years ago

Fixed errors of ANAC2019 agents

  • Property svn:executable set to *
File size: 9.2 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package agents.anac.y2019.harddealer.math3.ml.neuralnet;
19
20import java.io.Serializable;
21import java.io.ObjectInputStream;
22import java.util.concurrent.atomic.AtomicReference;
23import java.util.concurrent.atomic.AtomicLong;
24
25import agents.anac.y2019.harddealer.math3.exception.DimensionMismatchException;
26import agents.anac.y2019.harddealer.math3.util.Precision;
27
28
29/**
30 * Describes a neuron element of a neural network.
31 *
32 * This class aims to be thread-safe.
33 *
34 * @since 3.3
35 */
36public class Neuron implements Serializable {
37 /** Serializable. */
38 private static final long serialVersionUID = 20130207L;
39 /** Identifier. */
40 private final long identifier;
41 /** Length of the feature set. */
42 private final int size;
43 /** Neuron data. */
44 private final AtomicReference<double[]> features;
45 /** Number of attempts to update a neuron. */
46 private final AtomicLong numberOfAttemptedUpdates = new AtomicLong(0);
47 /** Number of successful updates of a neuron. */
48 private final AtomicLong numberOfSuccessfulUpdates = new AtomicLong(0);
49
50 /**
51 * Creates a neuron.
52 * The size of the feature set is fixed to the length of the given
53 * argument.
54 * <br/>
55 * Constructor is package-private: Neurons must be
56 * {@link Network#createNeuron(double[]) created} by the network
57 * instance to which they will belong.
58 *
59 * @param identifier Identifier (assigned by the {@link Network}).
60 * @param features Initial values of the feature set.
61 */
62 Neuron(long identifier,
63 double[] features) {
64 this.identifier = identifier;
65 this.size = features.length;
66 this.features = new AtomicReference<double[]>(features.clone());
67 }
68
69 /**
70 * Performs a deep copy of this instance.
71 * Upon return, the copied and original instances will be independent:
72 * Updating one will not affect the other.
73 *
74 * @return a new instance with the same state as this instance.
75 * @since 3.6
76 */
77 public synchronized Neuron copy() {
78 final Neuron copy = new Neuron(getIdentifier(),
79 getFeatures());
80 copy.numberOfAttemptedUpdates.set(numberOfAttemptedUpdates.get());
81 copy.numberOfSuccessfulUpdates.set(numberOfSuccessfulUpdates.get());
82
83 return copy;
84 }
85
86 /**
87 * Gets the neuron's identifier.
88 *
89 * @return the identifier.
90 */
91 public long getIdentifier() {
92 return identifier;
93 }
94
95 /**
96 * Gets the length of the feature set.
97 *
98 * @return the number of features.
99 */
100 public int getSize() {
101 return size;
102 }
103
104 /**
105 * Gets the neuron's features.
106 *
107 * @return a copy of the neuron's features.
108 */
109 public double[] getFeatures() {
110 return features.get().clone();
111 }
112
113 /**
114 * Tries to atomically update the neuron's features.
115 * Update will be performed only if the expected values match the
116 * current values.<br/>
117 * In effect, when concurrent threads call this method, the state
118 * could be modified by one, so that it does not correspond to the
119 * the state assumed by another.
120 * Typically, a caller {@link #getFeatures() retrieves the current state},
121 * and uses it to compute the new state.
122 * During this computation, another thread might have done the same
123 * thing, and updated the state: If the current thread were to proceed
124 * with its own update, it would overwrite the new state (which might
125 * already have been used by yet other threads).
126 * To prevent this, the method does not perform the update when a
127 * concurrent modification has been detected, and returns {@code false}.
128 * When this happens, the caller should fetch the new current state,
129 * redo its computation, and call this method again.
130 *
131 * @param expect Current values of the features, as assumed by the caller.
132 * Update will never succeed if the contents of this array does not match
133 * the values returned by {@link #getFeatures()}.
134 * @param update Features's new values.
135 * @return {@code true} if the update was successful, {@code false}
136 * otherwise.
137 * @throws DimensionMismatchException if the length of {@code update} is
138 * not the same as specified in the {@link #Neuron(long,double[])
139 * constructor}.
140 */
141 public boolean compareAndSetFeatures(double[] expect,
142 double[] update) {
143 if (update.length != size) {
144 throw new DimensionMismatchException(update.length, size);
145 }
146
147 // Get the internal reference. Note that this must not be a copy;
148 // otherwise the "compareAndSet" below will always fail.
149 final double[] current = features.get();
150 if (!containSameValues(current, expect)) {
151 // Some other thread already modified the state.
152 return false;
153 }
154
155 // Increment attempt counter.
156 numberOfAttemptedUpdates.incrementAndGet();
157
158 if (features.compareAndSet(current, update.clone())) {
159 // The current thread could atomically update the state (attempt succeeded).
160 numberOfSuccessfulUpdates.incrementAndGet();
161 return true;
162 } else {
163 // Some other thread came first (attempt failed).
164 return false;
165 }
166 }
167
168 /**
169 * Retrieves the number of calls to the
170 * {@link #compareAndSetFeatures(double[],double[]) compareAndSetFeatures}
171 * method.
172 * Note that if the caller wants to use this method in combination with
173 * {@link #getNumberOfSuccessfulUpdates()}, additional synchronization
174 * may be required to ensure consistency.
175 *
176 * @return the number of update attempts.
177 * @since 3.6
178 */
179 public long getNumberOfAttemptedUpdates() {
180 return numberOfAttemptedUpdates.get();
181 }
182
183 /**
184 * Retrieves the number of successful calls to the
185 * {@link #compareAndSetFeatures(double[],double[]) compareAndSetFeatures}
186 * method.
187 * Note that if the caller wants to use this method in combination with
188 * {@link #getNumberOfAttemptedUpdates()}, additional synchronization
189 * may be required to ensure consistency.
190 *
191 * @return the number of successful updates.
192 * @since 3.6
193 */
194 public long getNumberOfSuccessfulUpdates() {
195 return numberOfSuccessfulUpdates.get();
196 }
197
198 /**
199 * Checks whether the contents of both arrays is the same.
200 *
201 * @param current Current values.
202 * @param expect Expected values.
203 * @throws DimensionMismatchException if the length of {@code expected}
204 * is not the same as specified in the {@link #Neuron(long,double[])
205 * constructor}.
206 * @return {@code true} if the arrays contain the same values.
207 */
208 private boolean containSameValues(double[] current,
209 double[] expect) {
210 if (expect.length != size) {
211 throw new DimensionMismatchException(expect.length, size);
212 }
213
214 for (int i = 0; i < size; i++) {
215 if (!Precision.equals(current[i], expect[i])) {
216 return false;
217 }
218 }
219 return true;
220 }
221
222 /**
223 * Prevents proxy bypass.
224 *
225 * @param in Input stream.
226 */
227 private void readObject(ObjectInputStream in) {
228 throw new IllegalStateException();
229 }
230
231 /**
232 * Custom serialization.
233 *
234 * @return the proxy instance that will be actually serialized.
235 */
236 private Object writeReplace() {
237 return new SerializationProxy(identifier,
238 features.get());
239 }
240
241 /**
242 * Serialization.
243 */
244 private static class SerializationProxy implements Serializable {
245 /** Serializable. */
246 private static final long serialVersionUID = 20130207L;
247 /** Features. */
248 private final double[] features;
249 /** Identifier. */
250 private final long identifier;
251
252 /**
253 * @param identifier Identifier.
254 * @param features Features.
255 */
256 SerializationProxy(long identifier,
257 double[] features) {
258 this.identifier = identifier;
259 this.features = features;
260 }
261
262 /**
263 * Custom serialization.
264 *
265 * @return the {@link Neuron} for which this instance is the proxy.
266 */
267 private Object readResolve() {
268 return new Neuron(identifier,
269 features);
270 }
271 }
272}
Note: See TracBrowser for help on using the repository browser.