/* ---------------------------------------------------------------------
* Numenta Platform for Intelligent Computing (NuPIC)
* Copyright (C) 2014, Numenta, Inc. Unless you have an agreement
* with Numenta, Inc., for a separate license for this software code, the
* following terms and conditions apply:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero Public License for more details.
*
* You should have received a copy of the GNU Affero Public License
* along with this program. If not, see http://www.gnu.org/licenses.
*
* http://numenta.org/licenses/
* ---------------------------------------------------------------------
*/
package org.numenta.nupic.network.sensor;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Supplier;
import java.util.stream.StreamSupport;
import org.numenta.nupic.network.Layer;
import org.numenta.nupic.network.Network;
import org.numenta.nupic.network.Region;
import rx.Observable;
/**
* Wraps an {@link rx.Observable} or {@link Publisher} event emitter which can be used to input CSV
* strings into a given {@link Layer} of a {@link Region} and {@link Network} by
* either manually calling {@link Publisher#onNext(String)} or by connecting an Observable
* to an existing chain of Observables (operations/transformations) which eventually yield an appropriate CSV
* String input.
*
* @author metaware
*
* @param <T>
*/
public class ObservableSensor<T> implements Sensor<Observable<T>> {
private static final long serialVersionUID = 1L;
private static final int HEADER_SIZE = 3;
private static final int BATCH_SIZE = 20;
private static final boolean DEFAULT_PARALLEL_MODE = false;
private transient BatchedCsvStream<String[]> stream;
private SensorParams params;
/**
* Creates a new {@code ObservableSensor} using the specified
* {@link SensorParams}
*
* @param params
*/
@SuppressWarnings("unchecked")
public ObservableSensor(SensorParams params) {
if(!params.hasKey("ONSUB")) {
throw new IllegalArgumentException("Passed improperly formed Tuple: no key for \"ONSUB\"");
}
this.params = params;
Observable<String> obs = null;
Object publisher = params.get("ONSUB");
if(publisher instanceof Publisher) {
obs = ((Publisher)publisher).observable();
} else if(publisher instanceof Supplier<?>) {
obs = ((Supplier<Publisher>)publisher).get().observable();
} else {
obs = (Observable<String>)publisher;
}
Iterator<String> observerator = obs.toBlocking().getIterator();
Iterator<String> iterator = new Iterator<String>() {
@Override public boolean hasNext() { return observerator.hasNext(); }
@Override public String next() {
return observerator.next();
}
};
int characteristics = Spliterator.SORTED | Spliterator.ORDERED;
Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iterator, characteristics);
this.stream = BatchedCsvStream.batch(
StreamSupport.stream(spliterator, false), BATCH_SIZE, DEFAULT_PARALLEL_MODE, HEADER_SIZE);
}
@SuppressWarnings("unchecked")
public static <T> Sensor<T> create(SensorParams p) {
ObservableSensor<String[]> sensor =
(ObservableSensor<String[]>)new ObservableSensor<String[]>(p);
return (Sensor<T>)sensor;
}
/**
* Returns the {@link SensorParams} object used to configure this
* {@code ObservableSensor}
*
* @return the SensorParams
*/
@Override
public SensorParams getSensorParams() {
return params;
}
/**
* Returns the configured {@link MetaStream}.
*
* @return the MetaStream
*/
@SuppressWarnings("unchecked")
public <K> MetaStream<K> getInputStream() {
return (MetaStream<K>)stream;
}
/**
* Returns the values specifying meta information about the
* underlying stream.
*/
public ValueList getMetaInfo() {
return stream.getMeta();
}
}