diff --git a/Samples/Audio/Fourier (FFT)/MainForm.Designer.cs b/Samples/Audio/Fourier (FFT)/MainForm.Designer.cs
index 3ed6559da..8ddb9abb5 100644
--- a/Samples/Audio/Fourier (FFT)/MainForm.Designer.cs
+++ b/Samples/Audio/Fourier (FFT)/MainForm.Designer.cs
@@ -206,8 +206,6 @@ private void InitializeComponent()
this.chart1.BackColor = System.Drawing.Color.White;
this.chart1.Location = new System.Drawing.Point(12, 27);
this.chart1.Name = "chart1";
- this.chart1.RangeX = ((AForge.DoubleRange)(resources.GetObject("chart1.RangeX")));
- this.chart1.RangeY = ((AForge.DoubleRange)(resources.GetObject("chart1.RangeY")));
this.chart1.SimpleMode = false;
this.chart1.Size = new System.Drawing.Size(684, 367);
this.chart1.TabIndex = 6;
diff --git a/Samples/Audio/Fourier (FFT)/MainForm.cs b/Samples/Audio/Fourier (FFT)/MainForm.cs
index ea77cbbdd..a11de531e 100644
--- a/Samples/Audio/Fourier (FFT)/MainForm.cs
+++ b/Samples/Audio/Fourier (FFT)/MainForm.cs
@@ -80,7 +80,6 @@ void btnStart_Click(object sender, EventArgs e)
source.NewFrame += source_NewFrame;
source.AudioSourceError += source_AudioSourceError;
-
// Start it!
source.Start();
}
diff --git a/Samples/Imaging/Hough Transform/MainForm.cs b/Samples/Imaging/Hough Transform/MainForm.cs
index e555a3ec6..13893370b 100644
--- a/Samples/Imaging/Hough Transform/MainForm.cs
+++ b/Samples/Imaging/Hough Transform/MainForm.cs
@@ -60,9 +60,6 @@ private void openToolStripMenuItem_Click(object sender, EventArgs e)
Bitmap image = AForge.Imaging.Image.Clone(tempImage, PixelFormat.Format24bppRgb);
tempImage.Dispose();
- // format image
- AForge.Imaging.Image.FormatImage(ref image);
-
// lock the source image
BitmapData sourceData = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
diff --git a/Samples/Video/Two Cameras/MainForm.cs b/Samples/Video/Two Cameras/MainForm.cs
index 879a466d4..cc97f85eb 100644
--- a/Samples/Video/Two Cameras/MainForm.cs
+++ b/Samples/Video/Two Cameras/MainForm.cs
@@ -115,8 +115,8 @@ private void stopButton_Click(object sender, EventArgs e)
private void StartCameras()
{
// create first video source
- VideoCaptureDevice videoSource1 = new VideoCaptureDevice(videoDevices[camera1Combo.SelectedIndex].MonikerString);
- videoSource1.DesiredFrameRate = 10;
+ var videoSource1 = new VideoCaptureDevice(videoDevices[camera1Combo.SelectedIndex].MonikerString);
+ // videoSource1.DesiredFrameRate = 10;
videoSourcePlayer1.VideoSource = videoSource1;
videoSourcePlayer1.Start();
@@ -126,8 +126,8 @@ private void StartCameras()
{
System.Threading.Thread.Sleep(500);
- VideoCaptureDevice videoSource2 = new VideoCaptureDevice(videoDevices[camera2Combo.SelectedIndex].MonikerString);
- videoSource2.DesiredFrameRate = 10;
+ var videoSource2 = new VideoCaptureDevice(videoDevices[camera2Combo.SelectedIndex].MonikerString);
+ // videoSource2.DesiredFrameRate = 10;
videoSourcePlayer2.VideoSource = videoSource2;
videoSourcePlayer2.Start();
diff --git a/Sources/Accord.Audio.DirectSound/AudioCaptureDevice.cs b/Sources/Accord.Audio.DirectSound/AudioCaptureDevice.cs
index f28e1ff2d..f7ca7b2d2 100644
--- a/Sources/Accord.Audio.DirectSound/AudioCaptureDevice.cs
+++ b/Sources/Accord.Audio.DirectSound/AudioCaptureDevice.cs
@@ -1,26 +1,26 @@
-// Accord Audio Library
-// The Accord.NET Framework
-// http://accord-framework.net
-//
-// Copyright © César Souza, 2009-2015
-// cesarsouza at gmail.com
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library 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
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-//
-
-namespace Accord.DirectSound
+// Accord Audio Library
+// The Accord.NET Framework
+// http://accord-framework.net
+//
+// Copyright © César Souza, 2009-2015
+// cesarsouza at gmail.com
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+namespace Accord.DirectSound
{
using Accord.Audio;
using SharpDX.DirectSound;
@@ -28,554 +28,550 @@ namespace Accord.DirectSound
using System;
using System.Threading;
- ///
- /// Audio source for local audio capture device (i.e. a microphone).
- ///
- ///
- ///
- /// This audio source captures audio data
- /// obtained from a local audio capture device such as the microphone. The audio
- /// is captured using DirectSound through SlimDX.
- ///
- /// For instructions on how to list capture devices, please see
- /// the documentation page.
- ///
- ///
- ///
- /// Sample usage:
- ///
- ///
- /// // Create default capture device
- /// AudioCaptureDevice source = new AudioCaptureDevice();
- ///
- /// // Specify capturing options
- /// source.DesiredFrameSize = 4096;
- /// source.SampleRate = 22050;
- ///
- /// // Specify the callback function which will be
- /// // called once a sample is completely available
- /// source.NewFrame += source_NewFrame;
- ///
- /// // Start capturing
- /// source.Start();
- ///
- /// // ...
- ///
- /// // The callback function should determine what
- /// // should be done with the samples being caught
- /// private void source_NewFrame(object sender, NewFrameEventArgs eventArgs)
- /// {
- /// // Read current frame...
- /// Signal s = eventArgs.Signal;
- ///
- /// // Process/play/record it
- /// // ...
- /// }
- ///
- ///
- /// For more details regarding usage, please check one of
- /// the Audio sample applications accompanying the framework.
- ///
- ///
- ///
- ///
- ///
- public class AudioCaptureDevice : IAudioSource, IDisposable
- {
-
- // moniker string of audio capture device
- private Guid device = Guid.Empty;
- private string sourceName;
-
- // user data associated with the audio source
- private object userData = null;
-
- // received frames count
- private int framesReceived;
-
- // received byte count
- private int bytesReceived;
-
- // specifies desired capture frame size
- private int desiredCaptureSize = 4096;
-
- // specifies the sample rate used in the source
- private int sampleRate = 44100;
-
- private Thread thread = null;
- private ManualResetEvent stopEvent = null;
-
- private SampleFormat sampleFormat = SampleFormat.Format32BitIeeeFloat;
-
- ///
- /// New frame event.
- ///
- ///
- /// Notifies clients about new available frame from audio source.
- ///
- /// Since audio source may have multiple clients, each client is responsible for
- /// making a copy (cloning) of the passed audio frame, because the audio source disposes its
- /// own original copy after notifying of clients.
- ///
- ///
- public event EventHandler NewFrame;
-
-
- ///
- /// Audio source error event.
- ///
- ///
- /// This event is used to notify clients about any type of errors occurred in
- /// audio source object, for example internal exceptions.
- ///
- public event EventHandler AudioSourceError;
-
- ///
- /// Audio source.
- ///
- ///
- /// Audio source is represented by Guid of audio capture device.
- ///
- public virtual string Source
- {
- get { return sourceName; }
- set { sourceName = value; }
- }
-
- ///
- /// Gets or sets the sample format used by the device.
- ///
- ///
- public SampleFormat Format
- {
- get { return sampleFormat; }
- set { sampleFormat = value; }
- }
-
- ///
- /// Gets or sets the desired frame size.
- ///
- public int DesiredFrameSize
- {
- get { return desiredCaptureSize; }
- set { desiredCaptureSize = value; }
- }
-
- ///
- /// Gets the number of audio channels captured by
- /// the device. Currently, only a single channel
- /// is supported.
- ///
- ///
- public int Channels
- {
- get { return 1; }
- set { }
- }
-
- ///
- /// Received frames count.
- ///
- ///
- /// Number of frames the audio source provided from the moment of the last
- /// access to the property.
- ///
- ///
- public int FramesReceived
- {
- get
- {
- int frames = framesReceived;
- framesReceived = 0;
- return frames;
- }
- }
-
- ///
- /// Received bytes count.
- ///
- ///
- /// Number of bytes the audio source provided from the moment of the last
- /// access to the property.
- ///
- ///
- public int BytesReceived
- {
- get
- {
- int bytes = bytesReceived;
- bytesReceived = 0;
- return bytes;
- }
- }
-
- ///
- /// User data.
- ///
- ///
- /// The property allows to associate user data with audio source object.
- ///
- public object UserData
- {
- get { return userData; }
- set { userData = value; }
- }
-
- ///
- /// State of the audio source.
- ///
- ///
- /// Current state of audio source object - running or not.
- ///
- public bool IsRunning
- {
- get
- {
- if (thread != null)
- {
- // check thread status
- if (thread.Join(0) == false)
- return true;
-
- // the thread is not running, free resources
- Free();
- }
- return false;
- }
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- public AudioCaptureDevice()
- {
- this.device = Guid.Empty;
- this.sourceName = "Default capture device";
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- public AudioCaptureDevice(AudioDeviceInfo device)
- {
- this.device = device.Guid;
- this.sourceName = device.Description;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// Global identifier of the audio capture device.
- ///
- public AudioCaptureDevice(Guid device)
- {
- this.device = device;
- this.sourceName = device.ToString();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// Global identifier of the audio capture device.
- /// The device name or description string.
- ///
- public AudioCaptureDevice(Guid device, string name)
- {
- this.device = device;
- this.sourceName = name;
- }
-
- ///
- /// Start audio source.
- ///
- ///
- /// Starts audio source and return execution to caller. audio source
- /// object creates background thread and notifies about new frames with the
- /// help of event.
- ///
- public void Start()
- {
- if (thread == null)
- {
- // check source
- if (device == Guid.Empty)
- throw new ArgumentException("Audio source is not specified");
-
- framesReceived = 0;
- bytesReceived = 0;
-
- // create events
- stopEvent = new ManualResetEvent(false);
-
- // create and start new thread
- thread = new Thread(WorkerThread);
- thread.Name = device.ToString();
- thread.Start();
- }
- }
-
- ///
- /// Signals audio source to stop its work.
- ///
- ///
- /// Signals audio source to stop its background thread, stop to
- /// provide new frames and free resources.
- ///
- public void SignalToStop()
- {
- // stop thread
- if (thread != null)
- {
- // signal to stop
- stopEvent.Set();
- }
- }
-
- ///
- /// Wait for audio source has stopped.
- ///
- ///
- /// Waits for source stopping after it was signaled to stop using
- /// method.
- ///
- public void WaitForStop()
- {
- if (thread != null)
- {
- // wait for thread stop
- thread.Join();
-
- Free();
- }
- }
-
- ///
- /// Stop audio source.
- ///
- ///
- /// Stops audio source aborting its thread.
- ///
- /// Since the method aborts background thread, its usage is highly not preferred
- /// and should be done only if there are no other options. The correct way of stopping camera
- /// is signaling it stop and then
- /// waiting for background thread's completion.
- ///
- ///
- public void Stop()
- {
- if (this.IsRunning)
- {
- thread.Abort();
- WaitForStop();
- }
- }
-
- ///
- /// Free resource.
- ///
- ///
- private void Free()
- {
- thread = null;
-
- // release events
- stopEvent.Close();
- stopEvent = null;
- }
-
-
-
- ///
- /// Worker thread.
- ///
- ///
- private void WorkerThread()
- {
- // Get the selected capture device
- DirectSoundCapture captureDevice = new DirectSoundCapture(device);
-
-
- // Set the capture format
- var bitsPerSample = Signal.GetSampleSize(sampleFormat);
- WaveFormat format = WaveFormat.CreateCustomFormat(sampleFormat.ToWaveFormat(), sampleRate, 1,
- sampleRate * bitsPerSample / 8, bitsPerSample / 8, bitsPerSample);
-
- // Setup the capture buffer
- CaptureBufferDescription captureBufferDescription = new CaptureBufferDescription();
- captureBufferDescription.Format = format;
- captureBufferDescription.BufferBytes = 2 * desiredCaptureSize * format.BlockAlign;
- captureBufferDescription.Flags |= CaptureBufferCapabilitiesFlags.WaveMapped;
- captureBufferDescription.Flags &= ~CaptureBufferCapabilitiesFlags.ControlEffects;
-
- CaptureBuffer captureBuffer = null;
- NotificationPosition[] notifications = new NotificationPosition[2];
-
- try
- {
- captureBuffer = new CaptureBuffer(captureDevice, captureBufferDescription);
-
- // Setup the notification positions
- int bufferPortionSize = captureBuffer.Capabilities.BufferBytes / 2;
- notifications[0] = new NotificationPosition();
- notifications[0].Offset = bufferPortionSize - 1;
- notifications[0].WaitHandle = new AutoResetEvent(false);
- notifications[1] = new NotificationPosition();
- notifications[1].Offset = bufferPortionSize - 1 + bufferPortionSize;
- notifications[1].WaitHandle = new AutoResetEvent(false);
- captureBuffer.SetNotificationPositions(notifications);
-
- // Make a copy of the wait handles
- WaitHandle[] waitHandles = new WaitHandle[notifications.Length];
- for (int i = 0; i < notifications.Length; i++)
- waitHandles[i] = notifications[i].WaitHandle;
-
-
-
- // Start capturing
- captureBuffer.Start(true);
-
-
- if (sampleFormat == SampleFormat.Format32BitIeeeFloat)
- {
- float[] currentSample = new float[desiredCaptureSize];
-
- while (!stopEvent.WaitOne(0, true))
- {
- int bufferPortionIndex = WaitHandle.WaitAny(waitHandles);
- captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex, LockFlags.None);
- OnNewFrame(currentSample);
- }
- }
- else if (sampleFormat == SampleFormat.Format16Bit)
- {
- short[] currentSample = new short[desiredCaptureSize];
-
- while (!stopEvent.WaitOne(0, true))
- {
- int bufferPortionIndex = WaitHandle.WaitAny(waitHandles);
- captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex, LockFlags.None);
- OnNewFrame(currentSample);
- }
- }
- }
- catch (Exception ex)
- {
- if (AudioSourceError != null)
- AudioSourceError(this, new AudioSourceErrorEventArgs(ex.Message));
- else throw;
- }
- finally
- {
- if (captureBuffer != null)
- {
- captureBuffer.Stop();
- captureBuffer.Dispose();
- }
-
- if (captureDevice != null)
- captureDevice.Dispose();
-
- for (int i = 0; i < notifications.Length; i++)
- if (notifications[i].WaitHandle != null)
- notifications[i].WaitHandle.Close();
- }
- }
-
-
-
- ///
- /// Notifies client about new block of frames.
- ///
- ///
- /// New frame's audio.
- ///
- protected void OnNewFrame(Array frame)
- {
- framesReceived++;
-
- if ((!stopEvent.WaitOne(0, true)) && (NewFrame != null))
- {
- NewFrame(this, new NewFrameEventArgs(Signal.FromArray(frame, sampleRate, sampleFormat)));
- }
- }
-
-
- ///
- /// Gets whether this audio source supports seeking.
- ///
- ///
- public bool CanSeek
- {
- get { return false; }
- }
-
- ///
- /// This source does not support seeking.
- ///
- ///
- public void Seek(int frameIndex)
- {
- throw new NotSupportedException();
- }
-
- ///
- /// Gets or sets the desired sample rate for this capturing device.
- ///
- ///
- public int SampleRate
- {
- get { return this.sampleRate; }
- set { this.sampleRate = value; }
- }
-
-
- #region IDisposable members
- ///
- /// Releases unmanaged resources and performs other cleanup operations before the
- /// is reclaimed by garbage collection.
- ///
- ///
- ~AudioCaptureDevice()
- {
- Dispose(false);
- }
-
- ///
- /// Performs application-defined tasks associated with
- /// freeing, releasing, or resetting unmanaged resources.
- ///
- ///
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Releases unmanaged and - optionally - managed resources
- ///
- ///
- ///
- /// true to release both managed and unmanaged resources;
- /// false to release only unmanaged resources.
- ///
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- // free managed resources
- if (stopEvent != null)
- {
- stopEvent.Close();
- stopEvent = null;
- }
- }
- }
- #endregion
-
- }
+ ///
+ /// Audio source for local audio capture device (i.e. a microphone).
+ ///
+ ///
+ ///
+ /// This audio source captures audio data
+ /// obtained from a local audio capture device such as the microphone. The audio
+ /// is captured using DirectSound through SlimDX.
+ ///
+ /// For instructions on how to list capture devices, please see
+ /// the documentation page.
+ ///
+ ///
+ ///
+ /// Sample usage:
+ ///
+ ///
+ /// // Create default capture device
+ /// AudioCaptureDevice source = new AudioCaptureDevice();
+ ///
+ /// // Specify capturing options
+ /// source.DesiredFrameSize = 4096;
+ /// source.SampleRate = 22050;
+ ///
+ /// // Specify the callback function which will be
+ /// // called once a sample is completely available
+ /// source.NewFrame += source_NewFrame;
+ ///
+ /// // Start capturing
+ /// source.Start();
+ ///
+ /// // ...
+ ///
+ /// // The callback function should determine what
+ /// // should be done with the samples being caught
+ /// private void source_NewFrame(object sender, NewFrameEventArgs eventArgs)
+ /// {
+ /// // Read current frame...
+ /// Signal s = eventArgs.Signal;
+ ///
+ /// // Process/play/record it
+ /// // ...
+ /// }
+ ///
+ ///
+ /// For more details regarding usage, please check one of
+ /// the Audio sample applications accompanying the framework.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public class AudioCaptureDevice : IAudioSource, IDisposable
+ {
+
+ // moniker string of audio capture device
+ private Guid device = Guid.Empty;
+ private string sourceName;
+
+ // user data associated with the audio source
+ private object userData = null;
+
+ // received frames count
+ private int framesReceived;
+
+ // received byte count
+ private int bytesReceived;
+
+ // specifies desired capture frame size
+ private int desiredCaptureSize = 4096;
+
+ // specifies the sample rate used in the source
+ private int sampleRate = 44100;
+
+ private Thread thread = null;
+ private ManualResetEvent stopEvent = null;
+
+ private SampleFormat sampleFormat = SampleFormat.Format32BitIeeeFloat;
+
+ ///
+ /// New frame event.
+ ///
+ ///
+ /// Notifies clients about new available frame from audio source.
+ ///
+ /// Since audio source may have multiple clients, each client is responsible for
+ /// making a copy (cloning) of the passed audio frame, because the audio source disposes its
+ /// own original copy after notifying of clients.
+ ///
+ ///
+ public event EventHandler NewFrame;
+
+
+ ///
+ /// Audio source error event.
+ ///
+ ///
+ /// This event is used to notify clients about any type of errors occurred in
+ /// audio source object, for example internal exceptions.
+ ///
+ public event EventHandler AudioSourceError;
+
+ ///
+ /// Audio source.
+ ///
+ ///
+ /// Audio source is represented by Guid of audio capture device.
+ ///
+ public virtual string Source
+ {
+ get { return sourceName; }
+ set { sourceName = value; }
+ }
+
+ ///
+ /// Gets or sets the sample format used by the device.
+ ///
+ ///
+ public SampleFormat Format
+ {
+ get { return sampleFormat; }
+ set { sampleFormat = value; }
+ }
+
+ ///
+ /// Gets or sets the desired frame size.
+ ///
+ public int DesiredFrameSize
+ {
+ get { return desiredCaptureSize; }
+ set { desiredCaptureSize = value; }
+ }
+
+ ///
+ /// Gets the number of audio channels captured by
+ /// the device. Currently, only a single channel
+ /// is supported.
+ ///
+ ///
+ public int Channels
+ {
+ get { return 1; }
+ set { }
+ }
+
+ ///
+ /// Received frames count.
+ ///
+ ///
+ /// Number of frames the audio source provided from the moment of the last
+ /// access to the property.
+ ///
+ ///
+ public int FramesReceived
+ {
+ get
+ {
+ int frames = framesReceived;
+ framesReceived = 0;
+ return frames;
+ }
+ }
+
+ ///
+ /// Received bytes count.
+ ///
+ ///
+ /// Number of bytes the audio source provided from the moment of the last
+ /// access to the property.
+ ///
+ ///
+ public int BytesReceived
+ {
+ get
+ {
+ int bytes = bytesReceived;
+ bytesReceived = 0;
+ return bytes;
+ }
+ }
+
+ ///
+ /// User data.
+ ///
+ ///
+ /// The property allows to associate user data with audio source object.
+ ///
+ public object UserData
+ {
+ get { return userData; }
+ set { userData = value; }
+ }
+
+ ///
+ /// State of the audio source.
+ ///
+ ///
+ /// Current state of audio source object - running or not.
+ ///
+ public bool IsRunning
+ {
+ get
+ {
+ if (thread != null)
+ {
+ // check thread status
+ if (thread.Join(0) == false)
+ return true;
+
+ // the thread is not running, free resources
+ Free();
+ }
+ return false;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ public AudioCaptureDevice()
+ {
+ this.device = Guid.Empty;
+ this.sourceName = "Default capture device";
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ public AudioCaptureDevice(AudioDeviceInfo device)
+ {
+ this.device = device.Guid;
+ this.sourceName = device.Description;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Global identifier of the audio capture device.
+ ///
+ public AudioCaptureDevice(Guid device)
+ {
+ this.device = device;
+ this.sourceName = device.ToString();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Global identifier of the audio capture device.
+ /// The device name or description string.
+ ///
+ public AudioCaptureDevice(Guid device, string name)
+ {
+ this.device = device;
+ this.sourceName = name;
+ }
+
+ ///
+ /// Start audio source.
+ ///
+ ///
+ /// Starts audio source and return execution to caller. audio source
+ /// object creates background thread and notifies about new frames with the
+ /// help of event.
+ ///
+ public void Start()
+ {
+ if (thread == null)
+ {
+ framesReceived = 0;
+ bytesReceived = 0;
+
+ // create events
+ stopEvent = new ManualResetEvent(false);
+
+ // create and start new thread
+ thread = new Thread(WorkerThread);
+ thread.Name = device.ToString();
+ thread.Start();
+ }
+ }
+
+ ///
+ /// Signals audio source to stop its work.
+ ///
+ ///
+ /// Signals audio source to stop its background thread, stop to
+ /// provide new frames and free resources.
+ ///
+ public void SignalToStop()
+ {
+ // stop thread
+ if (thread != null)
+ {
+ // signal to stop
+ stopEvent.Set();
+ }
+ }
+
+ ///
+ /// Wait for audio source has stopped.
+ ///
+ ///
+ /// Waits for source stopping after it was signaled to stop using
+ /// method.
+ ///
+ public void WaitForStop()
+ {
+ if (thread != null)
+ {
+ // wait for thread stop
+ thread.Join();
+
+ Free();
+ }
+ }
+
+ ///
+ /// Stop audio source.
+ ///
+ ///
+ /// Stops audio source aborting its thread.
+ ///
+ /// Since the method aborts background thread, its usage is highly not preferred
+ /// and should be done only if there are no other options. The correct way of stopping camera
+ /// is signaling it stop and then
+ /// waiting for background thread's completion.
+ ///
+ ///
+ public void Stop()
+ {
+ if (this.IsRunning)
+ {
+ thread.Abort();
+ WaitForStop();
+ }
+ }
+
+ ///
+ /// Free resource.
+ ///
+ ///
+ private void Free()
+ {
+ thread = null;
+
+ // release events
+ stopEvent.Close();
+ stopEvent = null;
+ }
+
+
+
+ ///
+ /// Worker thread.
+ ///
+ ///
+ private void WorkerThread()
+ {
+ // Get the selected capture device
+ DirectSoundCapture captureDevice = new DirectSoundCapture(device);
+
+
+ // Set the capture format
+ var bitsPerSample = Signal.GetSampleSize(sampleFormat);
+ WaveFormat format = WaveFormat.CreateCustomFormat(sampleFormat.ToWaveFormat(), sampleRate, 1,
+ sampleRate * bitsPerSample / 8, bitsPerSample / 8, bitsPerSample);
+
+ // Setup the capture buffer
+ CaptureBufferDescription captureBufferDescription = new CaptureBufferDescription();
+ captureBufferDescription.Format = format;
+ captureBufferDescription.BufferBytes = 2 * desiredCaptureSize * format.BlockAlign;
+ captureBufferDescription.Flags |= CaptureBufferCapabilitiesFlags.WaveMapped;
+ captureBufferDescription.Flags &= ~CaptureBufferCapabilitiesFlags.ControlEffects;
+
+ CaptureBuffer captureBuffer = null;
+ NotificationPosition[] notifications = new NotificationPosition[2];
+
+ try
+ {
+ captureBuffer = new CaptureBuffer(captureDevice, captureBufferDescription);
+
+ // Setup the notification positions
+ int bufferPortionSize = captureBuffer.Capabilities.BufferBytes / 2;
+ notifications[0] = new NotificationPosition();
+ notifications[0].Offset = bufferPortionSize - 1;
+ notifications[0].WaitHandle = new AutoResetEvent(false);
+ notifications[1] = new NotificationPosition();
+ notifications[1].Offset = bufferPortionSize - 1 + bufferPortionSize;
+ notifications[1].WaitHandle = new AutoResetEvent(false);
+ captureBuffer.SetNotificationPositions(notifications);
+
+ // Make a copy of the wait handles
+ WaitHandle[] waitHandles = new WaitHandle[notifications.Length];
+ for (int i = 0; i < notifications.Length; i++)
+ waitHandles[i] = notifications[i].WaitHandle;
+
+
+
+ // Start capturing
+ captureBuffer.Start(true);
+
+
+ if (sampleFormat == SampleFormat.Format32BitIeeeFloat)
+ {
+ float[] currentSample = new float[desiredCaptureSize];
+
+ while (!stopEvent.WaitOne(0, true))
+ {
+ int bufferPortionIndex = WaitHandle.WaitAny(waitHandles);
+ captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex, LockFlags.None);
+ OnNewFrame(currentSample);
+ }
+ }
+ else if (sampleFormat == SampleFormat.Format16Bit)
+ {
+ short[] currentSample = new short[desiredCaptureSize];
+
+ while (!stopEvent.WaitOne(0, true))
+ {
+ int bufferPortionIndex = WaitHandle.WaitAny(waitHandles);
+ captureBuffer.Read(currentSample, 0, currentSample.Length, bufferPortionSize * bufferPortionIndex, LockFlags.None);
+ OnNewFrame(currentSample);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (AudioSourceError != null)
+ AudioSourceError(this, new AudioSourceErrorEventArgs(ex.Message));
+ else throw;
+ }
+ finally
+ {
+ if (captureBuffer != null)
+ {
+ captureBuffer.Stop();
+ captureBuffer.Dispose();
+ }
+
+ if (captureDevice != null)
+ captureDevice.Dispose();
+
+ for (int i = 0; i < notifications.Length; i++)
+ if (notifications[i].WaitHandle != null)
+ notifications[i].WaitHandle.Close();
+ }
+ }
+
+
+
+ ///
+ /// Notifies client about new block of frames.
+ ///
+ ///
+ /// New frame's audio.
+ ///
+ protected void OnNewFrame(Array frame)
+ {
+ framesReceived++;
+
+ if ((!stopEvent.WaitOne(0, true)) && (NewFrame != null))
+ {
+ NewFrame(this, new NewFrameEventArgs(Signal.FromArray(frame, sampleRate, sampleFormat)));
+ }
+ }
+
+
+ ///
+ /// Gets whether this audio source supports seeking.
+ ///
+ ///
+ public bool CanSeek
+ {
+ get { return false; }
+ }
+
+ ///
+ /// This source does not support seeking.
+ ///
+ ///
+ public void Seek(int frameIndex)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// Gets or sets the desired sample rate for this capturing device.
+ ///
+ ///
+ public int SampleRate
+ {
+ get { return this.sampleRate; }
+ set { this.sampleRate = value; }
+ }
+
+
+ #region IDisposable members
+ ///
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// is reclaimed by garbage collection.
+ ///
+ ///
+ ~AudioCaptureDevice()
+ {
+ Dispose(false);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with
+ /// freeing, releasing, or resetting unmanaged resources.
+ ///
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources
+ ///
+ ///
+ ///
+ /// true to release both managed and unmanaged resources;
+ /// false to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ // free managed resources
+ if (stopEvent != null)
+ {
+ stopEvent.Close();
+ stopEvent = null;
+ }
+ }
+ }
+ #endregion
+
+ }
}
\ No newline at end of file
diff --git a/Sources/Accord.Audio.DirectSound/AudioOutputDevice.cs b/Sources/Accord.Audio.DirectSound/AudioOutputDevice.cs
index fd757784b..6587b9ca0 100644
--- a/Sources/Accord.Audio.DirectSound/AudioOutputDevice.cs
+++ b/Sources/Accord.Audio.DirectSound/AudioOutputDevice.cs
@@ -299,10 +299,6 @@ public void Play()
{
if (thread == null)
{
- // check source
- if (device == Guid.Empty)
- throw new ArgumentException("Audio output is not specified");
-
isPlaying = true;
// create events
diff --git a/Sources/Accord.Core/ExtensionMethods.cs b/Sources/Accord.Core/ExtensionMethods.cs
index 82592a8cd..1a6bcbfec 100644
--- a/Sources/Accord.Core/ExtensionMethods.cs
+++ b/Sources/Accord.Core/ExtensionMethods.cs
@@ -23,6 +23,7 @@
namespace Accord
{
using System;
+ using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Globalization;
@@ -38,6 +39,24 @@ namespace Accord
public static class ExtensionMethods
{
+ ///
+ /// Copies a collection by calling the ICloneable.Clone method for each element inside it.
+ ///
+ ///
+ ///
+ /// The collection to be cloned.
+ ///
+ /// A copy of the collection where each element has also been copied.
+ ///
+ public static T DeepClone(this T list)
+ where T : IList, ICloneable
+ {
+ T clone = (T)list.Clone();
+ for (int i = 0; i < clone.Count; i++)
+ clone[i] = (ICloneable)list[i].Clone();
+ return clone;
+ }
+
///
/// Creates and adds multiple
/// objects with the given names at once.
diff --git a/Sources/Accord.Docs/Accord.Documentation/Accord.Documentation.shfbproj b/Sources/Accord.Docs/Accord.Documentation/Accord.Documentation.shfbproj
index 8344d5c64..49a98c83c 100644
--- a/Sources/Accord.Docs/Accord.Documentation/Accord.Documentation.shfbproj
+++ b/Sources/Accord.Docs/Accord.Documentation/Accord.Documentation.shfbproj
@@ -284,7 +284,7 @@
VS2013
C#, Visual Basic
MemberName
- 2.15.0.0
+ 3.0.0.0
.NET Framework 4.5
Attributes, ExplicitInterfaceImplementations, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected
ms.vsipcc+, ms.vsexpresscc+
diff --git a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.IO.png b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.IO.png
index 276771d2a..62229f946 100644
Binary files a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.IO.png and b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.IO.png differ
diff --git a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.Comparers.png b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.Comparers.png
index 49d445e9d..3f08f426d 100644
Binary files a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.Comparers.png and b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.Comparers.png differ
diff --git a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.Optimization.png b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.Optimization.png
index d1bdcec78..6229df73d 100644
Binary files a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.Optimization.png and b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.Optimization.png differ
diff --git a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.png b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.png
index 594df8e41..9f85753a2 100644
Binary files a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.png and b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Math.png differ
diff --git a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Distributions.Univariate.png b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Distributions.Univariate.png
index 76bd4a667..f9b64cc81 100644
Binary files a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Distributions.Univariate.png and b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Distributions.Univariate.png differ
diff --git a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Kernels.png b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Kernels.png
index 0fcf10e1c..faf70efd8 100644
Binary files a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Kernels.png and b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Kernels.png differ
diff --git a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Models.png b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Models.png
index fcdefca27..bc07f6574 100644
Binary files a/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Models.png and b/Sources/Accord.Docs/Accord.Documentation/Diagrams/Classes/Accord.Statistics.Models.png differ
diff --git a/Sources/Accord.Imaging/AForge/IntegralImage.cs b/Sources/Accord.Imaging/AForge/IntegralImage.cs
index 871ebda38..a30ded860 100644
--- a/Sources/Accord.Imaging/AForge/IntegralImage.cs
+++ b/Sources/Accord.Imaging/AForge/IntegralImage.cs
@@ -1,455 +1,455 @@
-// AForge Image Processing Library
-// AForge.NET framework
-// http://www.aforgenet.com/framework/
-//
-// Copyright © AForge.NET, 2005-2010
-// contacts@aforgenet.com
-//
-
-namespace AForge.Imaging
-{
- using System;
- using System.Drawing;
- using System.Drawing.Imaging;
-
- ///
- /// Integral image.
- ///
- ///
- /// The class implements integral image concept, which is described by
- /// Viola and Jones in: P. Viola and M. J. Jones, "Robust real-time face detection",
- /// Int. Journal of Computer Vision 57(2), pp. 137–154, 2004.
- ///
- /// "An integral image I of an input image G is defined as the image in which the
- /// intensity at a pixel position is equal to the sum of the intensities of all the pixels
- /// above and to the left of that position in the original image."
- ///
- /// The intensity at position (x, y) can be written as:
- ///
- /// x y
- /// I(x,y) = SUM( SUM( G(i,j) ) )
- /// i=0 j=0
- ///
- ///
- /// The class uses 32-bit integers to represent integral image.
- ///
- /// The class processes only grayscale (8 bpp indexed) images.
- ///
- /// This class contains two versions of each method: safe and unsafe. Safe methods do
- /// checks of provided coordinates and ensure that these coordinates belong to the image, what makes
- /// these methods slower. Unsafe methods do not do coordinates' checks and rely that these
- /// coordinates belong to the image, what makes these methods faster.
- ///
- /// Sample usage:
- ///
- /// // create integral image
- /// IntegralImage im = IntegralImage.FromBitmap( image );
- /// // get pixels' mean value in the specified rectangle
- /// float mean = im.GetRectangleMean( 10, 10, 20, 30 )
- ///
- ///
- ///
- public class IntegralImage
- {
- ///
- /// Intergral image's array.
- ///
- ///
- /// See remarks to property.
- ///
- protected uint[,] integralImage = null;
-
- // image's width and height
- private int width;
- private int height;
-
- ///
- /// Width of the source image the integral image was constructed for.
- ///
- public int Width
- {
- get { return width; }
- }
-
- ///
- /// Height of the source image the integral image was constructed for.
- ///
- public int Height
- {
- get { return height; }
- }
-
- ///
- /// Provides access to internal array keeping integral image data.
- ///
- ///
- ///
- /// The array should be accessed by [y, x] indexing.
- ///
- /// The array's size is [+1, +1]. The first
- /// row and column are filled with zeros, what is done for more efficient calculation of
- /// rectangles' sums.
- ///
- ///
- public uint[,] InternalData
- {
- get { return integralImage; }
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// Image width.
- /// Image height.
- ///
- /// The constractor is protected, what makes it imposible to instantiate this
- /// class directly. To create an instance of this class or
- /// method should be used.
- ///
- protected IntegralImage( int width, int height )
- {
- this.width = width;
- this.height = height;
- integralImage = new uint[height + 1, width + 1];
- }
-
- ///
- /// Construct integral image from source grayscale image.
- ///
- ///
- /// Source grayscale image.
- ///
- /// Returns integral image.
- ///
- /// The source image has incorrect pixel format.
- ///
- public static IntegralImage FromBitmap( Bitmap image )
- {
- // check image format
- if ( image.PixelFormat != PixelFormat.Format8bppIndexed )
- {
- throw new UnsupportedImageFormatException( "Source image can be graysclae (8 bpp indexed) image only." );
- }
-
- // lock source image
- BitmapData imageData = image.LockBits(
- new Rectangle( 0, 0, image.Width, image.Height ),
- ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed );
-
- // process the image
- IntegralImage im = FromBitmap( imageData );
-
- // unlock image
- image.UnlockBits( imageData );
-
- return im;
- }
-
- ///
- /// Construct integral image from source grayscale image.
- ///
- ///
- /// Source image data.
- ///
- /// Returns integral image.
- ///
- /// The source image has incorrect pixel format.
- ///
- public static IntegralImage FromBitmap( BitmapData imageData )
- {
- return FromBitmap( new UnmanagedImage( imageData ) );
- }
-
- ///
- /// Construct integral image from source grayscale image.
- ///
- ///
- /// Source unmanaged image.
- ///
- /// Returns integral image.
- ///
- /// The source image has incorrect pixel format.
- ///
- public static IntegralImage FromBitmap( UnmanagedImage image )
- {
- // check image format
- if ( image.PixelFormat != PixelFormat.Format8bppIndexed )
- {
- throw new ArgumentException( "Source image can be graysclae (8 bpp indexed) image only." );
- }
-
- // get source image size
- int width = image.Width;
- int height = image.Height;
- int offset = image.Stride - width;
-
- // create integral image
- IntegralImage im = new IntegralImage( width, height );
- uint[,] integralImage = im.integralImage;
-
- // do the job
- unsafe
- {
- byte* src = (byte*) image.ImageData.ToPointer( );
-
- // for each line
- for ( int y = 1; y <= height; y++ )
- {
- uint rowSum = 0;
-
- // for each pixel
- for ( int x = 1; x <= width; x++, src++ )
- {
- rowSum += *src;
-
- integralImage[y, x] = rowSum + integralImage[y - 1, x];
- }
- src += offset;
- }
- }
-
- return im;
- }
-
- ///
- /// Calculate sum of pixels in the specified rectangle.
- ///
- ///
- /// X coordinate of left-top rectangle's corner.
- /// Y coordinate of left-top rectangle's corner.
- /// X coordinate of right-bottom rectangle's corner.
- /// Y coordinate of right-bottom rectangle's corner.
- ///
- /// Returns sum of pixels in the specified rectangle.
- ///
- /// Both specified points are included into the calculation rectangle.
- ///
- public uint GetRectangleSum( int x1, int y1, int x2, int y2 )
- {
- // check if requested rectangle is out of the image
- if ( ( x2 < 0 ) || ( y2 < 0 ) || ( x1 >= width ) || ( y1 >= height ) )
- return 0;
-
- if ( x1 < 0 ) x1 = 0;
- if ( y1 < 0 ) y1 = 0;
-
- x2++;
- y2++;
-
- if ( x2 > width ) x2 = width;
- if ( y2 > height ) y2 = height;
-
- return integralImage[y2, x2] + integralImage[y1, x1] - integralImage[y2, x1] - integralImage[y1, x2];
- }
-
- ///
- /// Calculate horizontal (X) haar wavelet at the specified point.
- ///
- ///
- /// X coordinate of the point to calculate wavelet at.
- /// Y coordinate of the point to calculate wavelet at.
- /// Wavelet size to calculate.
- ///
- /// Returns value of the horizontal wavelet at the specified point.
- ///
- /// The method calculates horizontal wavelet, which is a difference
- /// of two horizontally adjacent boxes' sums, i.e. A-B. A is the sum of rectangle with coordinates
- /// (x, y-radius, x+radius-1, y+radius-1). B is the sum of rectangle with coordinates
- /// (x-radius, y-radius, x-1, y+radiys-1).
- ///
- public int GetHaarXWavelet( int x, int y, int radius )
- {
- int y1 = y - radius;
- int y2 = y + radius - 1;
-
- long a = GetRectangleSum( x, y1, x + radius - 1, y2 );
- long b = GetRectangleSum( x - radius, y1, x - 1, y2 );
-
- return (int) ( a - b );
- }
-
- ///
- /// Calculate vertical (Y) haar wavelet at the specified point.
- ///
- ///
- /// X coordinate of the point to calculate wavelet at.
- /// Y coordinate of the point to calculate wavelet at.
- /// Wavelet size to calculate.
- ///
- /// Returns value of the vertical wavelet at the specified point.
- ///
- /// The method calculates vertical wavelet, which is a difference
- /// of two vertical adjacent boxes' sums, i.e. A-B. A is the sum of rectangle with coordinates
- /// (x-radius, y, x+radius-1, y+radius-1). B is the sum of rectangle with coordinates
- /// (x-radius, y-radius, x+radius-1, y-1).
- ///
- public int GetHaarYWavelet( int x, int y, int radius )
- {
- int x1 = x - radius;
- int x2 = x + radius - 1;
-
- float a = GetRectangleSum( x1, y, x2, y + radius - 1 );
- float b = GetRectangleSum( x1, y - radius, x2, y - 1 );
-
- return (int) ( a - b );
- }
-
- ///
- /// Calculate sum of pixels in the specified rectangle without checking it's coordinates.
- ///
- ///
- /// X coordinate of left-top rectangle's corner.
- /// Y coordinate of left-top rectangle's corner.
- /// X coordinate of right-bottom rectangle's corner.
- /// Y coordinate of right-bottom rectangle's corner.
- ///
- /// Returns sum of pixels in the specified rectangle.
- ///
- /// Both specified points are included into the calculation rectangle.
- ///
- public uint GetRectangleSumUnsafe( int x1, int y1, int x2, int y2 )
- {
- x2++;
- y2++;
-
- return integralImage[y2, x2] + integralImage[y1, x1] - integralImage[y2, x1] - integralImage[y1, x2];
- }
-
- ///
- /// Calculate sum of pixels in the specified rectangle.
- ///
- ///
- /// X coordinate of central point of the rectangle.
- /// Y coordinate of central point of the rectangle.
- /// Radius of the rectangle.
- ///
- /// Returns sum of pixels in the specified rectangle.
- ///
- /// The method calculates sum of pixels in square rectangle with
- /// odd width and height. In the case if it is required to calculate sum of
- /// 3x3 rectangle, then it is required to specify its center and radius equal to 1.
- ///
- ///
- public uint GetRectangleSum( int x, int y, int radius )
- {
- return GetRectangleSum( x - radius, y - radius, x + radius, y + radius );
- }
-
- ///
- /// Calculate sum of pixels in the specified rectangle without checking it's coordinates.
- ///
- ///
- /// X coordinate of central point of the rectangle.
- /// Y coordinate of central point of the rectangle.
- /// Radius of the rectangle.
- ///
- /// Returns sum of pixels in the specified rectangle.
- ///
- /// The method calculates sum of pixels in square rectangle with
- /// odd width and height. In the case if it is required to calculate sum of
- /// 3x3 rectangle, then it is required to specify its center and radius equal to 1.
- ///
- ///
- public uint GetRectangleSumUnsafe( int x, int y, int radius )
- {
- return GetRectangleSumUnsafe( x - radius, y - radius, x + radius, y + radius );
- }
-
- ///
- /// Calculate mean value of pixels in the specified rectangle.
- ///
- ///
- /// X coordinate of left-top rectangle's corner.
- /// Y coordinate of left-top rectangle's corner.
- /// X coordinate of right-bottom rectangle's corner.
- /// Y coordinate of right-bottom rectangle's corner.
- ///
- /// Returns mean value of pixels in the specified rectangle.
- ///
- /// Both specified points are included into the calculation rectangle.
- ///
- public float GetRectangleMean( int x1, int y1, int x2, int y2 )
- {
- // check if requested rectangle is out of the image
- if ( ( x2 < 0 ) || ( y2 < 0 ) || ( x1 >= width ) || ( y1 >= height ) )
- return 0;
-
- if ( x1 < 0 ) x1 = 0;
- if ( y1 < 0 ) y1 = 0;
-
- x2++;
- y2++;
-
- if ( x2 > width ) x2 = width;
- if ( y2 > height ) y2 = height;
-
- // return sum divided by actual rectangles size
- return (float) ( (double) ( integralImage[y2, x2] + integralImage[y1, x1] - integralImage[y2, x1] - integralImage[y1, x2] ) /
- (double) ( ( x2 - x1 ) * ( y2 - y1 ) ) );
- }
-
- ///
- /// Calculate mean value of pixels in the specified rectangle without checking it's coordinates.
- ///
- ///
- /// X coordinate of left-top rectangle's corner.
- /// Y coordinate of left-top rectangle's corner.
- /// X coordinate of right-bottom rectangle's corner.
- /// Y coordinate of right-bottom rectangle's corner.
- ///
- /// Returns mean value of pixels in the specified rectangle.
- ///
- /// Both specified points are included into the calculation rectangle.
- ///
- public float GetRectangleMeanUnsafe( int x1, int y1, int x2, int y2 )
- {
- x2++;
- y2++;
-
- // return sum divided by actual rectangles size
- return (float) ( (double) ( integralImage[y2, x2] + integralImage[y1, x1] - integralImage[y2, x1] - integralImage[y1, x2] ) /
- (double) ( ( x2 - x1 ) * ( y2 - y1 ) ) );
- }
-
- ///
- /// Calculate mean value of pixels in the specified rectangle.
- ///
- ///
- /// X coordinate of central point of the rectangle.
- /// Y coordinate of central point of the rectangle.
- /// Radius of the rectangle.
- ///
- /// Returns mean value of pixels in the specified rectangle.
- ///
- /// The method calculates mean value of pixels in square rectangle with
- /// odd width and height. In the case if it is required to calculate mean value of
- /// 3x3 rectangle, then it is required to specify its center and radius equal to 1.
- ///
- ///
- public float GetRectangleMean( int x, int y, int radius )
- {
- return GetRectangleMean( x - radius, y - radius, x + radius, y + radius );
- }
-
- ///
- /// Calculate mean value of pixels in the specified rectangle without checking it's coordinates.
- ///
- ///
- /// X coordinate of central point of the rectangle.
- /// Y coordinate of central point of the rectangle.
- /// Radius of the rectangle.
- ///
- /// Returns mean value of pixels in the specified rectangle.
- ///
- /// The method calculates mean value of pixels in square rectangle with
- /// odd width and height. In the case if it is required to calculate mean value of
- /// 3x3 rectangle, then it is required to specify its center and radius equal to 1.
- ///
- ///
- public float GetRectangleMeanUnsafe( int x, int y, int radius )
- {
- return GetRectangleMeanUnsafe( x - radius, y - radius, x + radius, y + radius );
- }
- }
-}
+// AForge Image Processing Library
+// AForge.NET framework
+// http://www.aforgenet.com/framework/
+//
+// Copyright © AForge.NET, 2005-2010
+// contacts@aforgenet.com
+//
+
+namespace AForge.Imaging
+{
+ using System;
+ using System.Drawing;
+ using System.Drawing.Imaging;
+
+ ///
+ /// Integral image.
+ ///
+ ///
+ /// The class implements integral image concept, which is described by
+ /// Viola and Jones in: P. Viola and M. J. Jones, "Robust real-time face detection",
+ /// Int. Journal of Computer Vision 57(2), pp. 137–154, 2004.
+ ///
+ /// "An integral image I of an input image G is defined as the image in which the
+ /// intensity at a pixel position is equal to the sum of the intensities of all the pixels
+ /// above and to the left of that position in the original image."
+ ///
+ /// The intensity at position (x, y) can be written as:
+ ///
+ /// x y
+ /// I(x,y) = SUM( SUM( G(i,j) ) )
+ /// i=0 j=0
+ ///
+ ///
+ /// The class uses 32-bit integers to represent integral image.
+ ///
+ /// The class processes only grayscale (8 bpp indexed) images.
+ ///
+ /// This class contains two versions of each method: safe and unsafe. Safe methods do
+ /// checks of provided coordinates and ensure that these coordinates belong to the image, what makes
+ /// these methods slower. Unsafe methods do not do coordinates' checks and rely that these
+ /// coordinates belong to the image, what makes these methods faster.
+ ///
+ /// Sample usage:
+ ///
+ /// // create integral image
+ /// IntegralImage im = IntegralImage.FromBitmap( image );
+ /// // get pixels' mean value in the specified rectangle
+ /// float mean = im.GetRectangleMean( 10, 10, 20, 30 )
+ ///
+ ///
+ ///
+ public class IntegralImage
+ {
+ ///
+ /// Intergral image's array.
+ ///
+ ///
+ /// See remarks to property.
+ ///
+ protected uint[,] integralImage = null;
+
+ // image's width and height
+ private int width;
+ private int height;
+
+ ///
+ /// Width of the source image the integral image was constructed for.
+ ///
+ public int Width
+ {
+ get { return width; }
+ }
+
+ ///
+ /// Height of the source image the integral image was constructed for.
+ ///
+ public int Height
+ {
+ get { return height; }
+ }
+
+ ///
+ /// Provides access to internal array keeping integral image data.
+ ///
+ ///
+ ///
+ /// The array should be accessed by [y, x] indexing.
+ ///
+ /// The array's size is [+1, +1]. The first
+ /// row and column are filled with zeros, what is done for more efficient calculation of
+ /// rectangles' sums.
+ ///
+ ///
+ public uint[,] InternalData
+ {
+ get { return integralImage; }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Image width.
+ /// Image height.
+ ///
+ /// The constractor is protected, what makes it imposible to instantiate this
+ /// class directly. To create an instance of this class or
+ /// method should be used.
+ ///
+ protected IntegralImage(int width, int height)
+ {
+ this.width = width;
+ this.height = height;
+ integralImage = new uint[height + 1, width + 1];
+ }
+
+ ///
+ /// Construct integral image from source grayscale image.
+ ///
+ ///
+ /// Source grayscale image.
+ ///
+ /// Returns integral image.
+ ///
+ /// The source image has incorrect pixel format.
+ ///
+ public static IntegralImage FromBitmap(Bitmap image)
+ {
+ // check image format
+ if (image.PixelFormat != PixelFormat.Format8bppIndexed)
+ {
+ throw new UnsupportedImageFormatException("Source image can be graysclae (8 bpp indexed) image only.");
+ }
+
+ // lock source image
+ BitmapData imageData = image.LockBits(
+ new Rectangle(0, 0, image.Width, image.Height),
+ ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
+
+ // process the image
+ IntegralImage im = FromBitmap(imageData);
+
+ // unlock image
+ image.UnlockBits(imageData);
+
+ return im;
+ }
+
+ ///
+ /// Construct integral image from source grayscale image.
+ ///
+ ///
+ /// Source image data.
+ ///
+ /// Returns integral image.
+ ///
+ /// The source image has incorrect pixel format.
+ ///
+ public static IntegralImage FromBitmap(BitmapData imageData)
+ {
+ return FromBitmap(new UnmanagedImage(imageData));
+ }
+
+ ///
+ /// Construct integral image from source grayscale image.
+ ///
+ ///
+ /// Source unmanaged image.
+ ///
+ /// Returns integral image.
+ ///
+ /// The source image has incorrect pixel format.
+ ///
+ public static IntegralImage FromBitmap(UnmanagedImage image)
+ {
+ // check image format
+ if (image.PixelFormat != PixelFormat.Format8bppIndexed)
+ {
+ throw new ArgumentException("Source image can be graysclae (8 bpp indexed) image only.");
+ }
+
+ // get source image size
+ int width = image.Width;
+ int height = image.Height;
+ int offset = image.Stride - width;
+
+ // create integral image
+ var im = new IntegralImage(width, height);
+ uint[,] integralImage = im.integralImage;
+
+ // do the job
+ unsafe
+ {
+ byte* src = (byte*)image.ImageData.ToPointer();
+
+ // for each line
+ for (int y = 1; y <= height; y++)
+ {
+ uint rowSum = 0;
+
+ // for each pixel
+ for (int x = 1; x <= width; x++, src++)
+ {
+ rowSum += *src;
+
+ integralImage[y, x] = rowSum + integralImage[y - 1, x];
+ }
+ src += offset;
+ }
+ }
+
+ return im;
+ }
+
+ ///
+ /// Calculate sum of pixels in the specified rectangle.
+ ///
+ ///
+ /// X coordinate of left-top rectangle's corner.
+ /// Y coordinate of left-top rectangle's corner.
+ /// X coordinate of right-bottom rectangle's corner.
+ /// Y coordinate of right-bottom rectangle's corner.
+ ///
+ /// Returns sum of pixels in the specified rectangle.
+ ///
+ /// Both specified points are included into the calculation rectangle.
+ ///
+ public uint GetRectangleSum(int x1, int y1, int x2, int y2)
+ {
+ // check if requested rectangle is out of the image
+ if ((x2 < 0) || (y2 < 0) || (x1 >= width) || (y1 >= height))
+ return 0;
+
+ if (x1 < 0) x1 = 0;
+ if (y1 < 0) y1 = 0;
+
+ x2++;
+ y2++;
+
+ if (x2 > width) x2 = width;
+ if (y2 > height) y2 = height;
+
+ return integralImage[y2, x2] + integralImage[y1, x1] - integralImage[y2, x1] - integralImage[y1, x2];
+ }
+
+ ///
+ /// Calculate horizontal (X) haar wavelet at the specified point.
+ ///
+ ///
+ /// X coordinate of the point to calculate wavelet at.
+ /// Y coordinate of the point to calculate wavelet at.
+ /// Wavelet size to calculate.
+ ///
+ /// Returns value of the horizontal wavelet at the specified point.
+ ///
+ /// The method calculates horizontal wavelet, which is a difference
+ /// of two horizontally adjacent boxes' sums, i.e. A-B. A is the sum of rectangle with coordinates
+ /// (x, y-radius, x+radius-1, y+radius-1). B is the sum of rectangle with coordinates
+ /// (x-radius, y-radius, x-1, y+radiys-1).
+ ///
+ public int GetHaarXWavelet(int x, int y, int radius)
+ {
+ int y1 = y - radius;
+ int y2 = y + radius - 1;
+
+ long a = GetRectangleSum(x, y1, x + radius - 1, y2);
+ long b = GetRectangleSum(x - radius, y1, x - 1, y2);
+
+ return (int)(a - b);
+ }
+
+ ///
+ /// Calculate vertical (Y) haar wavelet at the specified point.
+ ///
+ ///
+ /// X coordinate of the point to calculate wavelet at.
+ /// Y coordinate of the point to calculate wavelet at.
+ /// Wavelet size to calculate.
+ ///
+ /// Returns value of the vertical wavelet at the specified point.
+ ///
+ /// The method calculates vertical wavelet, which is a difference
+ /// of two vertical adjacent boxes' sums, i.e. A-B. A is the sum of rectangle with coordinates
+ /// (x-radius, y, x+radius-1, y+radius-1). B is the sum of rectangle with coordinates
+ /// (x-radius, y-radius, x+radius-1, y-1).
+ ///
+ public int GetHaarYWavelet(int x, int y, int radius)
+ {
+ int x1 = x - radius;
+ int x2 = x + radius - 1;
+
+ float a = GetRectangleSum(x1, y, x2, y + radius - 1);
+ float b = GetRectangleSum(x1, y - radius, x2, y - 1);
+
+ return (int)(a - b);
+ }
+
+ ///
+ /// Calculate sum of pixels in the specified rectangle without checking it's coordinates.
+ ///
+ ///
+ /// X coordinate of left-top rectangle's corner.
+ /// Y coordinate of left-top rectangle's corner.
+ /// X coordinate of right-bottom rectangle's corner.
+ /// Y coordinate of right-bottom rectangle's corner.
+ ///
+ /// Returns sum of pixels in the specified rectangle.
+ ///
+ /// Both specified points are included into the calculation rectangle.
+ ///
+ public uint GetRectangleSumUnsafe(int x1, int y1, int x2, int y2)
+ {
+ x2++;
+ y2++;
+
+ return integralImage[y2, x2] + integralImage[y1, x1] - integralImage[y2, x1] - integralImage[y1, x2];
+ }
+
+ ///
+ /// Calculate sum of pixels in the specified rectangle.
+ ///
+ ///
+ /// X coordinate of central point of the rectangle.
+ /// Y coordinate of central point of the rectangle.
+ /// Radius of the rectangle.
+ ///
+ /// Returns sum of pixels in the specified rectangle.
+ ///
+ /// The method calculates sum of pixels in square rectangle with
+ /// odd width and height. In the case if it is required to calculate sum of
+ /// 3x3 rectangle, then it is required to specify its center and radius equal to 1.
+ ///
+ ///
+ public uint GetRectangleSum(int x, int y, int radius)
+ {
+ return GetRectangleSum(x - radius, y - radius, x + radius, y + radius);
+ }
+
+ ///
+ /// Calculate sum of pixels in the specified rectangle without checking it's coordinates.
+ ///
+ ///
+ /// X coordinate of central point of the rectangle.
+ /// Y coordinate of central point of the rectangle.
+ /// Radius of the rectangle.
+ ///
+ /// Returns sum of pixels in the specified rectangle.
+ ///
+ /// The method calculates sum of pixels in square rectangle with
+ /// odd width and height. In the case if it is required to calculate sum of
+ /// 3x3 rectangle, then it is required to specify its center and radius equal to 1.
+ ///
+ ///
+ public uint GetRectangleSumUnsafe(int x, int y, int radius)
+ {
+ return GetRectangleSumUnsafe(x - radius, y - radius, x + radius, y + radius);
+ }
+
+ ///
+ /// Calculate mean value of pixels in the specified rectangle.
+ ///
+ ///
+ /// X coordinate of left-top rectangle's corner.
+ /// Y coordinate of left-top rectangle's corner.
+ /// X coordinate of right-bottom rectangle's corner.
+ /// Y coordinate of right-bottom rectangle's corner.
+ ///
+ /// Returns mean value of pixels in the specified rectangle.
+ ///
+ /// Both specified points are included into the calculation rectangle.
+ ///
+ public float GetRectangleMean(int x1, int y1, int x2, int y2)
+ {
+ // check if requested rectangle is out of the image
+ if ((x2 < 0) || (y2 < 0) || (x1 >= width) || (y1 >= height))
+ return 0;
+
+ if (x1 < 0) x1 = 0;
+ if (y1 < 0) y1 = 0;
+
+ x2++;
+ y2++;
+
+ if (x2 > width) x2 = width;
+ if (y2 > height) y2 = height;
+
+ // return sum divided by actual rectangles size
+ return (float)((double)(integralImage[y2, x2] + integralImage[y1, x1] - integralImage[y2, x1] - integralImage[y1, x2]) /
+ (double)((x2 - x1) * (y2 - y1)));
+ }
+
+ ///
+ /// Calculate mean value of pixels in the specified rectangle without checking it's coordinates.
+ ///
+ ///
+ /// X coordinate of left-top rectangle's corner.
+ /// Y coordinate of left-top rectangle's corner.
+ /// X coordinate of right-bottom rectangle's corner.
+ /// Y coordinate of right-bottom rectangle's corner.
+ ///
+ /// Returns mean value of pixels in the specified rectangle.
+ ///
+ /// Both specified points are included into the calculation rectangle.
+ ///
+ public float GetRectangleMeanUnsafe(int x1, int y1, int x2, int y2)
+ {
+ x2++;
+ y2++;
+
+ // return sum divided by actual rectangles size
+ return (float)((double)(integralImage[y2, x2] + integralImage[y1, x1] - integralImage[y2, x1] - integralImage[y1, x2]) /
+ (double)((x2 - x1) * (y2 - y1)));
+ }
+
+ ///
+ /// Calculate mean value of pixels in the specified rectangle.
+ ///
+ ///
+ /// X coordinate of central point of the rectangle.
+ /// Y coordinate of central point of the rectangle.
+ /// Radius of the rectangle.
+ ///
+ /// Returns mean value of pixels in the specified rectangle.
+ ///
+ /// The method calculates mean value of pixels in square rectangle with
+ /// odd width and height. In the case if it is required to calculate mean value of
+ /// 3x3 rectangle, then it is required to specify its center and radius equal to 1.
+ ///
+ ///
+ public float GetRectangleMean(int x, int y, int radius)
+ {
+ return GetRectangleMean(x - radius, y - radius, x + radius, y + radius);
+ }
+
+ ///
+ /// Calculate mean value of pixels in the specified rectangle without checking it's coordinates.
+ ///
+ ///
+ /// X coordinate of central point of the rectangle.
+ /// Y coordinate of central point of the rectangle.
+ /// Radius of the rectangle.
+ ///
+ /// Returns mean value of pixels in the specified rectangle.
+ ///
+ /// The method calculates mean value of pixels in square rectangle with
+ /// odd width and height. In the case if it is required to calculate mean value of
+ /// 3x3 rectangle, then it is required to specify its center and radius equal to 1.
+ ///
+ ///
+ public float GetRectangleMeanUnsafe(int x, int y, int radius)
+ {
+ return GetRectangleMeanUnsafe(x - radius, y - radius, x + radius, y + radius);
+ }
+ }
+}
diff --git a/Sources/Accord.Imaging/ObjectiveFidelity.cs b/Sources/Accord.Imaging/ObjectiveFidelity.cs
index ddbc81c44..a78f5c5fd 100644
--- a/Sources/Accord.Imaging/ObjectiveFidelity.cs
+++ b/Sources/Accord.Imaging/ObjectiveFidelity.cs
@@ -51,7 +51,7 @@ namespace Accord.Imaging
/// Bitmap ori = ... // Original picture
/// Bitmap recon = ... // Reconstructed picture
///
- /// // Create a new Wolf-Joulion threshold:
+ /// // Create a new Objective fidelity comparer:
/// var of = new ObjectiveFidelity(ori, recon);
///
/// // Get the results
diff --git a/Sources/Accord.MachineLearning/VectorMachines/MulticlassSupportVectorMachine.cs b/Sources/Accord.MachineLearning/VectorMachines/MulticlassSupportVectorMachine.cs
index 4228c8c80..6e5d61554 100644
--- a/Sources/Accord.MachineLearning/VectorMachines/MulticlassSupportVectorMachine.cs
+++ b/Sources/Accord.MachineLearning/VectorMachines/MulticlassSupportVectorMachine.cs
@@ -1,26 +1,26 @@
-// Accord Machine Learning Library
-// The Accord.NET Framework
-// http://accord-framework.net
-//
-// Copyright © César Souza, 2009-2015
-// cesarsouza at gmail.com
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-//
-// This library 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
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-//
-
-namespace Accord.MachineLearning.VectorMachines
+// Accord Machine Learning Library
+// The Accord.NET Framework
+// http://accord-framework.net
+//
+// Copyright © César Souza, 2009-2015
+// cesarsouza at gmail.com
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+namespace Accord.MachineLearning.VectorMachines
{
using Accord.Math;
using Accord.Statistics.Kernels;
@@ -30,103 +30,103 @@ namespace Accord.MachineLearning.VectorMachines
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
- using System.Threading.Tasks;
-
- ///
- /// Decision strategies for
- /// Multi-class Support Vector Machines.
- ///
- ///
- public enum MulticlassComputeMethod
- {
- ///
- /// Max-voting method (also known as 1vs1 decision).
- ///
- ///
- Voting,
-
- ///
- /// Elimination method (also known as DAG decision).
- ///
- ///
- Elimination,
- }
-
- ///
- /// One-against-one Multi-class Kernel Support Vector Machine Classifier.
- ///
- ///
- ///
- ///
- /// The Support Vector Machine is by nature a binary classifier. One of the ways
- /// to extend the original SVM algorithm to multiple classes is to build a one-
- /// against-one scheme where multiple SVMs specialize to recognize each of the
- /// available classes. By using a competition scheme, the original multi-class
- /// classification problem is then reduced to n*(n/2) smaller binary problems.
- ///
- /// Currently this class supports only Kernel machines as the underlying classifiers.
- /// If a Linear Support Vector Machine is needed, specify a Linear kernel in the
- /// constructor at the moment of creation.
- ///
- ///
- /// References:
- ///
- /// -
- ///
- /// http://courses.media.mit.edu/2006fall/mas622j/Projects/aisen-project/index.html
- /// -
- ///
- /// http://nlp.stanford.edu/IR-book/html/htmledition/multiclass-svms-1.html
- ///
- ///
- ///
- ///
- ///
- ///
- /// // Sample data
- /// // The following is simple auto association function
- /// // where each input correspond to its own class. This
- /// // problem should be easily solved by a Linear kernel.
- ///
- /// // Sample input data
- /// double[][] inputs =
- /// {
- /// new double[] { 0 },
- /// new double[] { 3 },
- /// new double[] { 1 },
- /// new double[] { 2 },
- /// };
- ///
- /// // Output for each of the inputs
- /// int[] outputs = { 0, 3, 1, 2 };
- ///
- ///
- /// // Create a new Linear kernel
- /// IKernel kernel = new Linear();
- ///
- /// // Create a new Multi-class Support Vector Machine with one input,
- /// // using the linear kernel and for four disjoint classes.
- /// var machine = new MulticlassSupportVectorMachine(1, kernel, 4);
- ///
- /// // Create the Multi-class learning algorithm for the machine
- /// var teacher = new MulticlassSupportVectorLearning(machine, inputs, outputs);
- ///
- /// // Configure the learning algorithm to use SMO to train the
- /// // underlying SVMs in each of the binary class subproblems.
- /// teacher.Algorithm = (svm, classInputs, classOutputs, i, j) =>
- /// new SequentialMinimalOptimization(svm, classInputs, classOutputs);
- ///
+ using System.Threading.Tasks;
+
+ ///
+ /// Decision strategies for
+ /// Multi-class Support Vector Machines.
+ ///
+ ///
+ public enum MulticlassComputeMethod
+ {
+ ///
+ /// Max-voting method (also known as 1vs1 decision).
+ ///
+ ///
+ Voting,
+
+ ///
+ /// Elimination method (also known as DAG decision).
+ ///
+ ///
+ Elimination,
+ }
+
+ ///
+ /// One-against-one Multi-class Kernel Support Vector Machine Classifier.
+ ///
+ ///
+ ///
+ ///
+ /// The Support Vector Machine is by nature a binary classifier. One of the ways
+ /// to extend the original SVM algorithm to multiple classes is to build a one-
+ /// against-one scheme where multiple SVMs specialize to recognize each of the
+ /// available classes. By using a competition scheme, the original multi-class
+ /// classification problem is then reduced to n*(n/2) smaller binary problems.
+ ///
+ /// Currently this class supports only Kernel machines as the underlying classifiers.
+ /// If a Linear Support Vector Machine is needed, specify a Linear kernel in the
+ /// constructor at the moment of creation.
+ ///
+ ///
+ /// References:
+ ///
+ /// -
+ ///
+ /// http://courses.media.mit.edu/2006fall/mas622j/Projects/aisen-project/index.html
+ /// -
+ ///
+ /// http://nlp.stanford.edu/IR-book/html/htmledition/multiclass-svms-1.html
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// // Sample data
+ /// // The following is simple auto association function
+ /// // where each input correspond to its own class. This
+ /// // problem should be easily solved by a Linear kernel.
+ ///
+ /// // Sample input data
+ /// double[][] inputs =
+ /// {
+ /// new double[] { 0 },
+ /// new double[] { 3 },
+ /// new double[] { 1 },
+ /// new double[] { 2 },
+ /// };
+ ///
+ /// // Output for each of the inputs
+ /// int[] outputs = { 0, 3, 1, 2 };
+ ///
+ ///
+ /// // Create a new Linear kernel
+ /// IKernel kernel = new Linear();
+ ///
+ /// // Create a new Multi-class Support Vector Machine with one input,
+ /// // using the linear kernel and for four disjoint classes.
+ /// var machine = new MulticlassSupportVectorMachine(1, kernel, 4);
+ ///
+ /// // Create the Multi-class learning algorithm for the machine
+ /// var teacher = new MulticlassSupportVectorLearning(machine, inputs, outputs);
+ ///
+ /// // Configure the learning algorithm to use SMO to train the
+ /// // underlying SVMs in each of the binary class subproblems.
+ /// teacher.Algorithm = (svm, classInputs, classOutputs, i, j) =>
+ /// new SequentialMinimalOptimization(svm, classInputs, classOutputs);
+ ///
/// // Run the learning algorithm
- /// double error = teacher.Run(); // output should be 0
+ /// double error = teacher.Run(); // output should be 0
///
/// // Compute the decision output for one of the input vectors
- /// int decision = machine.Compute(new double[] { 3 }); // result should be 3
- ///
- ///
- ///
- /// The next example is a simple 3 classes classification problem.
- /// It shows how to use a different kernel function, such as the
- /// polynomial kernel of degree 2.
+ /// int decision = machine.Compute(new double[] { 3 }); // result should be 3
+ ///
+ ///
+ ///
+ /// The next example is a simple 3 classes classification problem.
+ /// It shows how to use a different kernel function, such as the
+ /// polynomial kernel of degree 2.
///
///
/// // Sample input data
@@ -165,1133 +165,1133 @@ public enum MulticlassComputeMethod
///
/// // Compute the decision output for one of the input vectors
/// int decision = machine.Compute( new double[] { -1, 3, 2 });
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- [Serializable]
- public class MulticlassSupportVectorMachine : ISupportVectorMachine,
- IEnumerable, KernelSupportVectorMachine>>, IDisposable
- {
-
- // List of underlying binary classifiers
- private KernelSupportVectorMachine[][] machines;
-
- // Multi-class statistics
- private int? totalVectorsCount;
- private int? uniqueVectorsCount;
- private int? sharedVectorsCount;
-
-
- // Performance optimizations
- [NonSerialized]
- private Lazy sharedVectors;
-
- [NonSerialized]
- private ThreadLocal vectorCache;
-
-
- ///
- /// Constructs a new Multi-class Kernel Support Vector Machine
- ///
- ///
- /// The number of inputs for the machine. If sequences have
- /// varying length, pass zero to this parameter and pass a suitable sequence
- /// kernel to this constructor, such as .
- /// The number of classes in the classification problem.
- ///
- ///
- /// If the number of inputs is zero, this means the machine
- /// accepts a indefinite number of inputs. This is often the
- /// case for kernel vector machines using a sequence kernel.
- ///
- ///
- public MulticlassSupportVectorMachine(int inputs, int classes)
- : this(inputs, new Linear(), classes)
- {
- }
-
- ///
- /// Constructs a new Multi-class Kernel Support Vector Machine
- ///
- ///
- /// The chosen kernel for the machine. Default is to
- /// use the kernel.
- /// The number of inputs for the machine. If sequences have
- /// varying length, pass zero to this parameter and pass a suitable sequence
- /// kernel to this constructor, such as .
- /// The number of classes in the classification problem.
- ///
- ///
- /// If the number of inputs is zero, this means the machine
- /// accepts a indefinite number of inputs. This is often the
- /// case for kernel vector machines using a sequence kernel.
- ///
- ///
- public MulticlassSupportVectorMachine(int inputs, IKernel kernel, int classes)
- {
- if (classes <= 1)
- throw new ArgumentException("The machine must have at least two classes.", "classes");
-
- // Create the kernel machines
- machines = new KernelSupportVectorMachine[classes - 1][];
- for (int i = 0; i < machines.Length; i++)
- {
- machines[i] = new KernelSupportVectorMachine[i + 1];
-
- for (int j = 0; j <= i; j++)
- machines[i][j] = new KernelSupportVectorMachine(kernel, inputs);
- }
-
- this.initialize();
- }
-
- ///
- /// Constructs a new Multi-class Kernel Support Vector Machine
- ///
- ///
- ///
- /// The machines to be used in each of the pair-wise class subproblems.
- ///
- ///
- public MulticlassSupportVectorMachine(KernelSupportVectorMachine[][] machines)
- {
- if (machines == null)
- throw new ArgumentNullException("machines");
-
- this.machines = machines;
- this.initialize();
- }
-
- private void initialize()
- {
- this.vectorCache = new ThreadLocal(() => new Cache());
- this.sharedVectors = new Lazy(computeSharedVectors, true);
- }
-
-
-
-
- #region Properties
- ///
- /// Gets the classifier for against .
- ///
- ///
- ///
- /// If the index of is greater than ,
- /// the classifier for the against
- /// will be returned instead. If both indices are equal, null will be
- /// returned instead.
- ///
- ///
- public KernelSupportVectorMachine this[int class1, int class2]
- {
- get
- {
- if (class1 == class2)
- return null;
- if (class1 > class2)
- return machines[class1 - 1][class2];
- else
- return machines[class2 - 1][class1];
- }
- }
-
- ///
- /// Gets the total number of machines
- /// in this multi-class classifier.
- ///
- ///
- public int MachinesCount
- {
- get { return ((machines.Length + 1) * machines.Length) / 2; }
- }
-
- ///
- /// Gets the total number of support vectors
- /// in the entire multi-class machine.
- ///
- ///
- public int SupportVectorCount
- {
- get
- {
- if (totalVectorsCount == null)
- {
- int count = 0;
- for (int i = 0; i < machines.Length; i++)
- for (int j = 0; j < machines[i].Length; j++)
- if (machines[i][j].SupportVectors != null)
- count += machines[i][j].SupportVectors.Length;
- totalVectorsCount = count;
- }
-
- return totalVectorsCount.Value;
- }
- }
-
- ///
- /// Gets the number of unique support
- /// vectors in the multi-class machine.
- ///
- ///
- public int SupportVectorUniqueCount
- {
- get
- {
- if (uniqueVectorsCount == null)
- {
- HashSet unique = new HashSet();
- for (int i = 0; i < machines.Length; i++)
- {
- for (int j = 0; j < machines[i].Length; j++)
- {
- if (machines[i][j].SupportVectors != null)
- {
- for (int k = 0; k < machines[i][j].SupportVectors.Length; k++)
- unique.Add(machines[i][j].SupportVectors[k]);
- }
- }
- }
-
- uniqueVectorsCount = unique.Count;
- }
-
- return uniqueVectorsCount.Value;
- }
- }
-
- ///
- /// Gets the number of shared support
- /// vectors in the multi-class machine.
- ///
- ///
- public int SupportVectorSharedCount
- {
- get
- {
- if (sharedVectorsCount == null)
- {
- var v = sharedVectors.Value;
- }
- return sharedVectorsCount.Value;
- }
- }
-
- ///
- /// Gets the number of classes.
- ///
- ///
- public int Classes
- {
- get { return machines.Length + 1; }
- }
-
- ///
- /// Gets the number of inputs of the machines.
- ///
- ///
- public int Inputs
- {
- get { return machines[0][0].Inputs; }
- }
-
- ///
- /// Gets a value indicating whether this machine produces probabilistic outputs.
- ///
- ///
- ///
- /// true if this machine produces probabilistic outputs; otherwise, false.
- ///
- ///
- public bool IsProbabilistic
- {
- get { return machines[0][0].IsProbabilistic; }
- }
-
- ///
- /// Gets the subproblems classifiers.
- ///
- ///
- public KernelSupportVectorMachine[][] Machines
- {
- get { return machines; }
- }
- #endregion
-
-
- #region Public Compute Overloads
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- ///
- /// The decision label for the given input.
- ///
- public int Compute(params double[] inputs)
- {
- double output; // Compute using elimination method as default.
- return Compute(inputs, MulticlassComputeMethod.Elimination, out output);
- }
-
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- /// The output of the machine. If this is a
- /// probabilistic machine, the
- /// output is the probability of the positive class. If this is
- /// a standard machine, the output is the distance to the decision
- /// hyperplane in feature space.
- ///
- /// The decision label for the given input.
- ///
- ///
- public int Compute(double[] inputs, out double output)
- {
- // Compute using elimination method as default.
- return Compute(inputs, MulticlassComputeMethod.Elimination, out output);
- }
-
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- /// The output of the machine. If this is a
- /// probabilistic machine, the
- /// output is the probability of the positive class. If this is
- /// a standard machine, the output is the distance to the decision
- /// hyperplane in feature space.
- /// The decision path followed by the Decision
- /// Directed Acyclic Graph used by the
- /// elimination method.
- ///
- /// The decision label for the given input.
- ///
- ///
- public int Compute(double[] inputs, out double output, out Tuple[] decisionPath)
- {
- double[] responses;
- decisionPath = new Tuple[Classes - 1];
- return computeElimination(inputs, out responses, out output, decisionPath);
- }
-
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- /// The model response for each class.
- ///
- /// The decision label for the given input.
- ///
- public int Compute(double[] inputs, out double[] responses)
- {
- double output; // Compute using elimination method as default.
- return Compute(inputs, MulticlassComputeMethod.Elimination, out responses, out output);
- }
-
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- /// The
- /// multi-class classification method to use.
- /// The model response for each class.
- /// The output of the machine. If this is a
- /// probabilistic machine, the
- /// output is the probability of the positive class. If this is
- /// a standard machine, the output is the distance to the decision
- /// hyperplane in feature space.
- ///
- /// The decision label for the given input.
- ///
- public int Compute(double[] inputs, MulticlassComputeMethod method, out double[] responses, out double output)
- {
- if (method == MulticlassComputeMethod.Voting)
- {
- int[] votes;
- int result = computeVoting(inputs, out votes, out output);
-
- responses = new double[votes.Length];
- for (int i = 0; i < responses.Length; i++)
- responses[i] = votes[i] * (2.0 / (Classes * (Classes - 1)));
-
- return result;
- }
- else
- {
- return computeElimination(inputs, out responses, out output, null);
- }
- }
-
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- /// The
- /// multi-class classification method to use.
- /// The model response for each class.
- ///
- /// The class decision for the given input.
- ///
- public int Compute(double[] inputs, MulticlassComputeMethod method, out double[] responses)
- {
- double output;
- return Compute(inputs, method, out responses, out output);
- }
-
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- /// The
- /// multi-class classification method to use.
- /// The output of the machine. If this is a
- /// probabilistic machine, the
- /// output is the probability of the positive class. If this is
- /// a standard machine, the output is the distance to the decision
- /// hyperplane in feature space.
- ///
- /// The class decision for the given input.
- ///
- public int Compute(double[] inputs, MulticlassComputeMethod method, out double output)
- {
- if (method == MulticlassComputeMethod.Voting)
- {
- int[] votes;
- return computeVoting(inputs, out votes, out output);
- }
- else
- {
- double[] responses;
- return computeElimination(inputs, out responses, out output, null);
- }
- }
-
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- /// The
- /// multi-class classification method to use.
- ///
- /// The class decision for the given input.
- ///
- public int Compute(double[] inputs, MulticlassComputeMethod method)
- {
- double output;
- return Compute(inputs, method, out output);
- }
- #endregion
-
-
- #region Private Multi-class Decision
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- /// An input vector.
- /// A vector containing the number of votes for each class.
- /// The output of the machine. If this is a
- /// probabilistic machine, the
- /// output is the probability of the positive class. If this is
- /// a standard machine, the output is the distance to the decision
- /// hyperplane in feature space.
- ///
- /// The decision label for the given input.
- ///
- private int computeVoting(double[] inputs, out int[] votes, out double output)
- {
- // Compute decision by Voting
-
- // Get a list of the shared vectors (lazy)
- int[][][] vectors = this.sharedVectors.Value;
-
- // Get the cache for this thread
- Cache cache = createOrResetCache();
-
- // out variables cannot be passed into delegates,
- // so will be creating a copy for the vote array.
- int[] voting = new int[Classes];
-
- // For each class
- Parallel.For(0, Classes, i =>
- {
- // For each other class
- for (int j = 0; j < i; j++)
- {
- double machineOutput;
-
- // Retrieve and compute the two-class problem for classes i x j
- int answer = computeSequential(i, j, inputs, out machineOutput, cache);
-
- // Determine the winner class
- int y = (answer == -1) ? i : j;
-
- // Increment votes for the winner
- Interlocked.Increment(ref voting[y]);
- }
- });
-
- // Voting finished.
- votes = voting;
-
- // Select class which maximum number of votes
- int imax; output = Matrix.Max(votes, out imax);
-
- // Determine output probability using no. of votes
- output = output * (2.0 / (Classes * (Classes - 1)));
-
- return imax; // Return the winner as the output.
- }
-
- ///
- /// Computes the given input to produce the corresponding output.
- ///
- ///
- ///
- /// This method computes the decision for a one-against-one multiclass
- /// support vector machine using the Directed Acyclic Graph method by
- /// Platt, Cristianini and Shawe-Taylor. Details are given on the
- /// original paper "Large Margin DAGs for Multiclass Classification", 2000.
- ///
- ///
- /// An input vector.
- /// The model response for each class.
- /// The output of the machine. If this is a
- /// probabilistic machine, the
- /// output is the probability of the positive class. If this is
- /// a standard machine, the output is the distance to the decision
- /// hyperplane in feature space.
- /// The decision path followed by the Decision
- /// Directed Acyclic Graph used by the
- /// elimination method.
- ///
- /// The decision label for the given input.
- ///
- private int computeElimination(double[] inputs, out double[] responses,
- out double output, Tuple[] decisionPath)
- {
- // Compute decision by Directed Acyclic Graph
-
- // Get a list of the shared vectors
- int[][][] vectors = this.sharedVectors.Value;
-
- // Get the cache for this thread
- Cache cache = createOrResetCache();
-
- output = 0;
-
- // Initialize metrics
- responses = new double[Classes];
- bool probabilistic = IsProbabilistic;
-
- if (probabilistic)
- {
- for (int i = 0; i < responses.Length; i++)
- responses[i] = 1.0;
- }
-
- // Start with first and last classes
- int classA = Classes - 1, classB = 0;
- int progress = 0;
-
- // Navigate decision path
- while (classA != classB)
- {
-
- // Compute the two-class decision problem to decide for A x B
- int answer = computeParallel(classA, classB, inputs, out output, cache);
-
- if (decisionPath != null)
- decisionPath[progress++] = Tuple.Create(classA, classB);
-
- // Check who won and update
-
- if (answer == -1)
- {
- // The class A has won and class B has lost
-
- if (probabilistic)
- {
- // Decrease loser likelihood
- responses[classB] *= output;
-
- // Increase for all other classes
- for (int i = 0; i < responses.Length; i++)
- if (i != classB) responses[i] *= 1.0 - output;
- }
- else
- {
- // Store the distance to the
- // answer for the loser class
- responses[classB] = -output;
- }
-
- // Advance classB towards
- // the middle of the list
- classB++;
- }
-
- else // answer == +1
- {
- // The class A has lost and class B has won
-
- if (probabilistic)
- {
- // Decrease loser likelihood
- responses[classA] *= 1.0 - output;
-
- // Increase for all other classes
- for (int i = 0; i < responses.Length; i++)
- if (i != classA) responses[i] *= output;
- }
- else
- {
- // Store the distance to the
- // answer for the loser class
- responses[classA] = output;
- }
-
- // Advance classA towards
- // the middle of the list
- classA--;
- }
- }
-
- // At this point, classA = classB is the winner
- if (!probabilistic) responses[classA] = output;
-
-#if DEBUG
- else
- {
- int imax; responses.Max(out imax);
- if (imax != classA) throw new Exception();
- }
-#endif
-
- // Return output for winner class
- output = responses[classA];
-
- return classA;
- }
-
- #endregion
-
-
- #region Private Single machine Decision
- ///
- /// Compute SVM output with support vector sharing.
- ///
- ///
- private int computeSequential(int classA, int classB, double[] input, out double output, Cache cache)
- {
- // Get the machine for this problem
- KernelSupportVectorMachine machine = machines[classA - 1][classB];
-
- // Get the vectors shared among all machines
- int[] vectors = cache.Vectors[classA - 1][classB];
- double[] values = cache.Products;
-
- double sum = machine.Threshold;
-
-
- if (machine.IsCompact)
- {
- // For linear machines, computation is simpler
- for (int i = 0; i < machine.Weights.Length; i++)
- sum += machine.Weights[i] * input[i];
- }
- else
- {
- // For each support vector in the machine
- for (int i = 0; i < vectors.Length; i++)
- {
- double value;
-
- // Check if it is a shared vector
- int j = vectors[i];
-
- if (j >= 0)
- {
- // This is a shared vector. Check
- // if it has already been computed
-
- if (!Double.IsNaN(values[j]))
- {
- // Yes, it has. Retrieve the value from the cache
- value = values[j];
- }
- else
- {
- // No, it has not. Compute and store the computed value in the cache
- value = values[j] = machine.Kernel.Function(machine.SupportVectors[i], input);
- Interlocked.Increment(ref cache.Evaluations);
- }
- }
- else
- {
- // This vector is not shared by any other machine. No need to cache
- value = machine.Kernel.Function(machine.SupportVectors[i], input);
- Interlocked.Increment(ref cache.Evaluations);
- }
-
- sum += machine.Weights[i] * value;
- }
- }
-
-
- // Produce probabilities if required
- if (machine.IsProbabilistic)
- {
- output = machine.Link.Inverse(sum);
- return output >= 0.5 ? +1 : -1;
- }
- else
- {
- output = sum;
- return output >= 0 ? +1 : -1;
- }
- }
-
- ///
- /// Compute SVM output with support vector sharing.
- ///
- ///
- private int computeParallel(int classA, int classB, double[] input, out double output, Cache cache)
- {
- // Get the machine for this problem
- KernelSupportVectorMachine machine = machines[classA - 1][classB];
-
- // Get the vectors shared among all machines
- int[] vectors = cache.Vectors[classA - 1][classB];
-
- double[] values = cache.Products;
-#if !NET35
- SpinLock[] locks = cache.SyncObjects;
-#endif
- double sum = machine.Threshold;
-
-
- if (machine.IsCompact)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Serializable]
+ public class MulticlassSupportVectorMachine : ISupportVectorMachine,
+ IEnumerable, KernelSupportVectorMachine>>, IDisposable
+ {
+
+ // List of underlying binary classifiers
+ private KernelSupportVectorMachine[][] machines;
+
+ // Multi-class statistics
+ private int? totalVectorsCount;
+ private int? uniqueVectorsCount;
+ private int? sharedVectorsCount;
+
+
+ // Performance optimizations
+ [NonSerialized]
+ private Lazy sharedVectors;
+
+ [NonSerialized]
+ private ThreadLocal vectorCache;
+
+
+ ///
+ /// Constructs a new Multi-class Kernel Support Vector Machine
+ ///
+ ///
+ /// The number of inputs for the machine. If sequences have
+ /// varying length, pass zero to this parameter and pass a suitable sequence
+ /// kernel to this constructor, such as .
+ /// The number of classes in the classification problem.
+ ///
+ ///
+ /// If the number of inputs is zero, this means the machine
+ /// accepts a indefinite number of inputs. This is often the
+ /// case for kernel vector machines using a sequence kernel.
+ ///
+ ///
+ public MulticlassSupportVectorMachine(int inputs, int classes)
+ : this(inputs, new Linear(), classes)
+ {
+ }
+
+ ///
+ /// Constructs a new Multi-class Kernel Support Vector Machine
+ ///
+ ///
+ /// The chosen kernel for the machine. Default is to
+ /// use the kernel.
+ /// The number of inputs for the machine. If sequences have
+ /// varying length, pass zero to this parameter and pass a suitable sequence
+ /// kernel to this constructor, such as .
+ /// The number of classes in the classification problem.
+ ///
+ ///
+ /// If the number of inputs is zero, this means the machine
+ /// accepts a indefinite number of inputs. This is often the
+ /// case for kernel vector machines using a sequence kernel.
+ ///
+ ///
+ public MulticlassSupportVectorMachine(int inputs, IKernel kernel, int classes)
+ {
+ if (classes <= 1)
+ throw new ArgumentException("The machine must have at least two classes.", "classes");
+
+ // Create the kernel machines
+ machines = new KernelSupportVectorMachine[classes - 1][];
+ for (int i = 0; i < machines.Length; i++)
+ {
+ machines[i] = new KernelSupportVectorMachine[i + 1];
+
+ for (int j = 0; j <= i; j++)
+ machines[i][j] = new KernelSupportVectorMachine(kernel, inputs);
+ }
+
+ this.initialize();
+ }
+
+ ///
+ /// Constructs a new Multi-class Kernel Support Vector Machine
+ ///
+ ///
+ ///
+ /// The machines to be used in each of the pair-wise class subproblems.
+ ///
+ ///
+ public MulticlassSupportVectorMachine(KernelSupportVectorMachine[][] machines)
+ {
+ if (machines == null)
+ throw new ArgumentNullException("machines");
+
+ this.machines = machines;
+ this.initialize();
+ }
+
+ private void initialize()
+ {
+ this.vectorCache = new ThreadLocal(() => new Cache());
+ this.sharedVectors = new Lazy(computeSharedVectors, true);
+ }
+
+
+
+
+ #region Properties
+ ///
+ /// Gets the classifier for against .
+ ///
+ ///
+ ///
+ /// If the index of is greater than ,
+ /// the classifier for the against
+ /// will be returned instead. If both indices are equal, null will be
+ /// returned instead.
+ ///
+ ///
+ public KernelSupportVectorMachine this[int class1, int class2]
+ {
+ get
+ {
+ if (class1 == class2)
+ return null;
+ if (class1 > class2)
+ return machines[class1 - 1][class2];
+ else
+ return machines[class2 - 1][class1];
+ }
+ }
+
+ ///
+ /// Gets the total number of machines
+ /// in this multi-class classifier.
+ ///
+ ///
+ public int MachinesCount
+ {
+ get { return ((machines.Length + 1) * machines.Length) / 2; }
+ }
+
+ ///
+ /// Gets the total number of support vectors
+ /// in the entire multi-class machine.
+ ///
+ ///
+ public int SupportVectorCount
+ {
+ get
+ {
+ if (totalVectorsCount == null)
+ {
+ int count = 0;
+ for (int i = 0; i < machines.Length; i++)
+ for (int j = 0; j < machines[i].Length; j++)
+ if (machines[i][j].SupportVectors != null)
+ count += machines[i][j].SupportVectors.Length;
+ totalVectorsCount = count;
+ }
+
+ return totalVectorsCount.Value;
+ }
+ }
+
+ ///
+ /// Gets the number of unique support
+ /// vectors in the multi-class machine.
+ ///
+ ///
+ public int SupportVectorUniqueCount
+ {
+ get
+ {
+ if (uniqueVectorsCount == null)
+ {
+ HashSet unique = new HashSet();
+ for (int i = 0; i < machines.Length; i++)
+ {
+ for (int j = 0; j < machines[i].Length; j++)
+ {
+ if (machines[i][j].SupportVectors != null)
+ {
+ for (int k = 0; k < machines[i][j].SupportVectors.Length; k++)
+ unique.Add(machines[i][j].SupportVectors[k]);
+ }
+ }
+ }
+
+ uniqueVectorsCount = unique.Count;
+ }
+
+ return uniqueVectorsCount.Value;
+ }
+ }
+
+ ///
+ /// Gets the number of shared support
+ /// vectors in the multi-class machine.
+ ///
+ ///
+ public int SupportVectorSharedCount
+ {
+ get
+ {
+ if (sharedVectorsCount == null)
+ {
+ var v = sharedVectors.Value;
+ }
+ return sharedVectorsCount.Value;
+ }
+ }
+
+ ///
+ /// Gets the number of classes.
+ ///
+ ///
+ public int Classes
+ {
+ get { return machines.Length + 1; }
+ }
+
+ ///
+ /// Gets the number of inputs of the machines.
+ ///
+ ///
+ public int Inputs
+ {
+ get { return machines[0][0].Inputs; }
+ }
+
+ ///
+ /// Gets a value indicating whether this machine produces probabilistic outputs.
+ ///
+ ///
+ ///
+ /// true if this machine produces probabilistic outputs; otherwise, false.
+ ///
+ ///
+ public bool IsProbabilistic
+ {
+ get { return machines[0][0].IsProbabilistic; }
+ }
+
+ ///
+ /// Gets the subproblems classifiers.
+ ///
+ ///
+ public KernelSupportVectorMachine[][] Machines
+ {
+ get { return machines; }
+ }
+ #endregion
+
+
+ #region Public Compute Overloads
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ ///
+ /// The decision label for the given input.
+ ///
+ public int Compute(params double[] inputs)
+ {
+ double output; // Compute using elimination method as default.
+ return Compute(inputs, MulticlassComputeMethod.Elimination, out output);
+ }
+
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ /// The output of the machine. If this is a
+ /// probabilistic machine, the
+ /// output is the probability of the positive class. If this is
+ /// a standard machine, the output is the distance to the decision
+ /// hyperplane in feature space.
+ ///
+ /// The decision label for the given input.
+ ///
+ ///
+ public int Compute(double[] inputs, out double output)
+ {
+ // Compute using elimination method as default.
+ return Compute(inputs, MulticlassComputeMethod.Elimination, out output);
+ }
+
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ /// The output of the machine. If this is a
+ /// probabilistic machine, the
+ /// output is the probability of the positive class. If this is
+ /// a standard machine, the output is the distance to the decision
+ /// hyperplane in feature space.
+ /// The decision path followed by the Decision
+ /// Directed Acyclic Graph used by the
+ /// elimination method.
+ ///
+ /// The decision label for the given input.
+ ///
+ ///
+ public int Compute(double[] inputs, out double output, out Tuple[] decisionPath)
+ {
+ double[] responses;
+ decisionPath = new Tuple[Classes - 1];
+ return computeElimination(inputs, out responses, out output, decisionPath);
+ }
+
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ /// The model response for each class.
+ ///
+ /// The decision label for the given input.
+ ///
+ public int Compute(double[] inputs, out double[] responses)
+ {
+ double output; // Compute using elimination method as default.
+ return Compute(inputs, MulticlassComputeMethod.Elimination, out responses, out output);
+ }
+
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ /// The
+ /// multi-class classification method to use.
+ /// The model response for each class.
+ /// The output of the machine. If this is a
+ /// probabilistic machine, the
+ /// output is the probability of the positive class. If this is
+ /// a standard machine, the output is the distance to the decision
+ /// hyperplane in feature space.
+ ///
+ /// The decision label for the given input.
+ ///
+ public int Compute(double[] inputs, MulticlassComputeMethod method, out double[] responses, out double output)
+ {
+ if (method == MulticlassComputeMethod.Voting)
+ {
+ int[] votes;
+ int result = computeVoting(inputs, out votes, out output);
+
+ responses = new double[votes.Length];
+ for (int i = 0; i < responses.Length; i++)
+ responses[i] = votes[i] * (2.0 / (Classes * (Classes - 1)));
+
+ return result;
+ }
+ else
+ {
+ return computeElimination(inputs, out responses, out output, null);
+ }
+ }
+
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ /// The
+ /// multi-class classification method to use.
+ /// The model response for each class.
+ ///
+ /// The class decision for the given input.
+ ///
+ public int Compute(double[] inputs, MulticlassComputeMethod method, out double[] responses)
+ {
+ double output;
+ return Compute(inputs, method, out responses, out output);
+ }
+
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ /// The
+ /// multi-class classification method to use.
+ /// The output of the machine. If this is a
+ /// probabilistic machine, the
+ /// output is the probability of the positive class. If this is
+ /// a standard machine, the output is the distance to the decision
+ /// hyperplane in feature space.
+ ///
+ /// The class decision for the given input.
+ ///
+ public int Compute(double[] inputs, MulticlassComputeMethod method, out double output)
+ {
+ if (method == MulticlassComputeMethod.Voting)
+ {
+ int[] votes;
+ return computeVoting(inputs, out votes, out output);
+ }
+ else
+ {
+ double[] responses;
+ return computeElimination(inputs, out responses, out output, null);
+ }
+ }
+
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ /// The
+ /// multi-class classification method to use.
+ ///
+ /// The class decision for the given input.
+ ///
+ public int Compute(double[] inputs, MulticlassComputeMethod method)
+ {
+ double output;
+ return Compute(inputs, method, out output);
+ }
+ #endregion
+
+
+ #region Private Multi-class Decision
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ /// An input vector.
+ /// A vector containing the number of votes for each class.
+ /// The output of the machine. If this is a
+ /// probabilistic machine, the
+ /// output is the probability of the positive class. If this is
+ /// a standard machine, the output is the distance to the decision
+ /// hyperplane in feature space.
+ ///
+ /// The decision label for the given input.
+ ///
+ private int computeVoting(double[] inputs, out int[] votes, out double output)
+ {
+ // Compute decision by Voting
+
+ // Get a list of the shared vectors (lazy)
+ int[][][] vectors = this.sharedVectors.Value;
+
+ // Get the cache for this thread
+ Cache cache = createOrResetCache();
+
+ // out variables cannot be passed into delegates,
+ // so will be creating a copy for the vote array.
+ int[] voting = new int[Classes];
+
+ // For each class
+ Parallel.For(0, Classes, i =>
+ {
+ // For each other class
+ for (int j = 0; j < i; j++)
+ {
+ double machineOutput;
+
+ // Retrieve and compute the two-class problem for classes i x j
+ int answer = computeSequential(i, j, inputs, out machineOutput, cache);
+
+ // Determine the winner class
+ int y = (answer == -1) ? i : j;
+
+ // Increment votes for the winner
+ Interlocked.Increment(ref voting[y]);
+ }
+ });
+
+ // Voting finished.
+ votes = voting;
+
+ // Select class which maximum number of votes
+ int imax; output = Matrix.Max(votes, out imax);
+
+ // Determine output probability using no. of votes
+ output = output * (2.0 / (Classes * (Classes - 1)));
+
+ return imax; // Return the winner as the output.
+ }
+
+ ///
+ /// Computes the given input to produce the corresponding output.
+ ///
+ ///
+ ///
+ /// This method computes the decision for a one-against-one multiclass
+ /// support vector machine using the Directed Acyclic Graph method by
+ /// Platt, Cristianini and Shawe-Taylor. Details are given on the
+ /// original paper "Large Margin DAGs for Multiclass Classification", 2000.
+ ///
+ ///
+ /// An input vector.
+ /// The model response for each class.
+ /// The output of the machine. If this is a
+ /// probabilistic machine, the
+ /// output is the probability of the positive class. If this is
+ /// a standard machine, the output is the distance to the decision
+ /// hyperplane in feature space.
+ /// The decision path followed by the Decision
+ /// Directed Acyclic Graph used by the
+ /// elimination method.
+ ///
+ /// The decision label for the given input.
+ ///
+ private int computeElimination(double[] inputs, out double[] responses,
+ out double output, Tuple[] decisionPath)
+ {
+ // Compute decision by Directed Acyclic Graph
+
+ // Get a list of the shared vectors
+ int[][][] vectors = this.sharedVectors.Value;
+
+ // Get the cache for this thread
+ Cache cache = createOrResetCache();
+
+ output = 0;
+
+ // Initialize metrics
+ responses = new double[Classes];
+ bool probabilistic = IsProbabilistic;
+
+ if (probabilistic)
+ {
+ for (int i = 0; i < responses.Length; i++)
+ responses[i] = 1.0;
+ }
+
+ // Start with first and last classes
+ int classA = Classes - 1, classB = 0;
+ int progress = 0;
+
+ // Navigate decision path
+ while (classA != classB)
+ {
+
+ // Compute the two-class decision problem to decide for A x B
+ int answer = computeParallel(classA, classB, inputs, out output, cache);
+
+ if (decisionPath != null)
+ decisionPath[progress++] = Tuple.Create(classA, classB);
+
+ // Check who won and update
+
+ if (answer == -1)
+ {
+ // The class A has won and class B has lost
+
+ if (probabilistic)
+ {
+ // Decrease loser likelihood
+ responses[classB] *= output;
+
+ // Increase for all other classes
+ for (int i = 0; i < responses.Length; i++)
+ if (i != classB) responses[i] *= 1.0 - output;
+ }
+ else
+ {
+ // Store the distance to the
+ // answer for the loser class
+ responses[classB] = -output;
+ }
+
+ // Advance classB towards
+ // the middle of the list
+ classB++;
+ }
+
+ else // answer == +1
+ {
+ // The class A has lost and class B has won
+
+ if (probabilistic)
+ {
+ // Decrease loser likelihood
+ responses[classA] *= 1.0 - output;
+
+ // Increase for all other classes
+ for (int i = 0; i < responses.Length; i++)
+ if (i != classA) responses[i] *= output;
+ }
+ else
+ {
+ // Store the distance to the
+ // answer for the loser class
+ responses[classA] = output;
+ }
+
+ // Advance classA towards
+ // the middle of the list
+ classA--;
+ }
+ }
+
+ // At this point, classA = classB is the winner
+ if (!probabilistic) responses[classA] = output;
+
+#if DEBUG
+ else
+ {
+ int imax; responses.Max(out imax);
+ if (imax != classA) throw new Exception();
+ }
+#endif
+
+ // Return output for winner class
+ output = responses[classA];
+
+ return classA;
+ }
+
+ #endregion
+
+
+ #region Private Single machine Decision
+ ///
+ /// Compute SVM output with support vector sharing.
+ ///
+ ///
+ private int computeSequential(int classA, int classB, double[] input, out double output, Cache cache)
+ {
+ // Get the machine for this problem
+ KernelSupportVectorMachine machine = machines[classA - 1][classB];
+
+ // Get the vectors shared among all machines
+ int[] vectors = cache.Vectors[classA - 1][classB];
+ double[] values = cache.Products;
+
+ double sum = machine.Threshold;
+
+
+ if (machine.IsCompact)
+ {
+ // For linear machines, computation is simpler
+ for (int i = 0; i < machine.Weights.Length; i++)
+ sum += machine.Weights[i] * input[i];
+ }
+ else
+ {
+ // For each support vector in the machine
+ for (int i = 0; i < vectors.Length; i++)
+ {
+ double value;
+
+ // Check if it is a shared vector
+ int j = vectors[i];
+
+ if (j >= 0)
+ {
+ // This is a shared vector. Check
+ // if it has already been computed
+
+ if (!Double.IsNaN(values[j]))
+ {
+ // Yes, it has. Retrieve the value from the cache
+ value = values[j];
+ }
+ else
+ {
+ // No, it has not. Compute and store the computed value in the cache
+ value = values[j] = machine.Kernel.Function(machine.SupportVectors[i], input);
+ Interlocked.Increment(ref cache.Evaluations);
+ }
+ }
+ else
+ {
+ // This vector is not shared by any other machine. No need to cache
+ value = machine.Kernel.Function(machine.SupportVectors[i], input);
+ Interlocked.Increment(ref cache.Evaluations);
+ }
+
+ sum += machine.Weights[i] * value;
+ }
+ }
+
+
+ // Produce probabilities if required
+ if (machine.IsProbabilistic)
+ {
+ output = machine.Link.Inverse(sum);
+ return output >= 0.5 ? +1 : -1;
+ }
+ else
+ {
+ output = sum;
+ return output >= 0 ? +1 : -1;
+ }
+ }
+
+ ///
+ /// Compute SVM output with support vector sharing.
+ ///
+ ///
+ private int computeParallel(int classA, int classB, double[] input, out double output, Cache cache)
+ {
+ // Get the machine for this problem
+ KernelSupportVectorMachine machine = machines[classA - 1][classB];
+
+ // Get the vectors shared among all machines
+ int[] vectors = cache.Vectors[classA - 1][classB];
+
+ double[] values = cache.Products;
+#if !NET35
+ SpinLock[] locks = cache.SyncObjects;
+#endif
+ double sum = machine.Threshold;
+
+
+ if (machine.IsCompact)
{
if (machine.Weights == null)
- throw new Exception();
-
- // For linear machines, computation is simpler
- for (int i = 0; i < machine.Weights.Length; i++)
- sum += machine.Weights[i] * input[i];
- }
- else
- {
-
-#if NET35
- #region Backward compatibility
- for (int i = 0; i < vectors.Length; i++)
- {
- double value;
-
- // Check if it is a shared vector
- int j = vectors[i];
-
- if (j >= 0)
- {
- // This is a shared vector. Check
- // if it has already been computed
-
- if (!Double.IsNaN(values[j]))
- {
- // Yes, it has. Retrieve the value from the cache
- value = values[j];
- }
- else
- {
- // No, it has not. Compute and store the computed value in the cache
- value = values[j] = machine.Kernel.Function(machine.SupportVectors[i], input);
- Interlocked.Increment(ref cache.Evaluations);
- }
- }
- else
- {
- // This vector is not shared by any other machine. No need to cache
- value = machine.Kernel.Function(machine.SupportVectors[i], input);
- Interlocked.Increment(ref cache.Evaluations);
- }
-
- sum += machine.Weights[i] * value;
- }
- #endregion
-#else
- // For each support vector in the machine
- Parallel.For(0, vectors.Length,
-
- // Init
- () => 0.0,
-
- // Map
- (i, state, partialSum) =>
- {
- double value;
-
- // Check if it is a shared vector
- int j = vectors[i];
-
- if (j >= 0)
- {
- // This is a shared vector. Check
- // if it has already been computed
-
- bool taken = false;
- locks[j].Enter(ref taken);
-
- if (!Double.IsNaN(values[j]))
- {
- // Yes, it has. Retrieve the value from the cache
- value = values[j];
- }
- else
- {
- // No, it has not. Compute and store the computed value in the cache
- value = values[j] = machine.Kernel.Function(machine.SupportVectors[i], input);
- Interlocked.Increment(ref cache.Evaluations);
- }
-
- locks[j].Exit();
- }
- else
- {
- // This vector is not shared by any other machine. No need to cache
- value = machine.Kernel.Function(machine.SupportVectors[i], input);
- Interlocked.Increment(ref cache.Evaluations);
- }
-
- return partialSum + machine.Weights[i] * value;
- },
-
- // Reduce
- (partialSum) => { lock (locks) sum += partialSum; }
- );
-#endif
- }
-
- // Produce probabilities if required
- if (machine.IsProbabilistic)
- {
- output = machine.Link.Inverse(sum);
- return output >= 0.5 ? +1 : -1;
- }
- else
- {
- output = sum;
- return output >= 0 ? +1 : -1;
- }
- }
- #endregion
-
-
-
-
-
- ///
- /// Resets the cache and machine statistics
- /// so they can be recomputed on next evaluation.
- ///
- ///
- public void Reset()
- {
- if (this.vectorCache != null)
- this.vectorCache.Dispose();
-
- this.sharedVectors = null;
- this.totalVectorsCount = null;
- this.uniqueVectorsCount = null;
- this.sharedVectorsCount = null;
-
- this.initialize();
- }
-
- ///
- /// Gets the total kernel evaluations performed
- /// in the last call to any of the
- /// functions in the current thread.
- ///
- ///
- /// The number of total kernel evaluations.
- ///
- public int GetLastKernelEvaluations()
- {
- return vectorCache.Value.Evaluations;
- }
-
-
- #region Loading & Saving
-
- ///
- /// Saves the machine to a stream.
- ///
- ///
- /// The stream to which the machine is to be serialized.
- ///
- public void Save(Stream stream)
- {
- BinaryFormatter b = new BinaryFormatter();
- b.Serialize(stream, this);
- }
-
- ///
- /// Saves the machine to a file.
- ///
- ///
- /// The path to the file to which the machine is to be serialized.
- ///
- public void Save(string path)
- {
- using (FileStream fs = new FileStream(path, FileMode.Create))
- {
- Save(fs);
- }
- }
-
- ///
- /// Loads a machine from a stream.
- ///
- ///
- /// The stream from which the machine is to be deserialized.
- ///
- /// The deserialized machine.
- ///
- public static MulticlassSupportVectorMachine Load(Stream stream)
- {
- BinaryFormatter b = new BinaryFormatter();
- return (MulticlassSupportVectorMachine)b.Deserialize(stream);
- }
-
- ///
- /// Loads a machine from a file.
- ///
- ///
- /// The path to the file from which the machine is to be deserialized.
- ///
- /// The deserialized machine.
- ///
- public static MulticlassSupportVectorMachine Load(string path)
- {
- using (FileStream fs = new FileStream(path, FileMode.Open))
- {
- return Load(fs);
- }
- }
-
- [OnDeserialized]
- private void onDeserialized(StreamingContext context)
- {
- initialize();
- }
- #endregion
-
- #region IEnumerable members
- ///
- /// Returns an enumerator that iterates through all machines
- /// contained inside this multi-class support vector machine.
- ///
- ///
- public IEnumerator, KernelSupportVectorMachine>> GetEnumerator()
- {
- for (int i = 0; i < machines.Length; i++)
- {
- for (int j = 0; j < machines[i].Length; j++)
- {
- yield return new KeyValuePair, KernelSupportVectorMachine>(
- Tuple.Create(i + 1, j), machines[i][j]);
- }
- }
- }
-
- ///
- /// Returns an enumerator that iterates through all machines
- /// contained inside this multi-class support vector machine.
- ///
- ///
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- #endregion
-
- #region IDisposable members
- ///
- /// Performs application-defined tasks associated with
- /// freeing, releasing, or resetting unmanaged resources.
- ///
- ///
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Releases unmanaged and - optionally - managed resources
- ///
- ///
- ///
- /// true to release both managed and unmanaged resources;
- /// false to release only unmanaged resources.
- ///
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- // free managed resources
- if (vectorCache != null)
- {
- vectorCache.Dispose();
- vectorCache = null;
- }
- }
- }
- #endregion
-
-
-
- #region Cache
- private Cache createOrResetCache()
- {
- Cache cache = vectorCache.Value;
-
- // First of all, check if the shared vectors in this machine
- // already have been identified. If they don't, identify them.
-
- cache.Vectors = sharedVectors.Value; // use lazy instantiation
- int vectorCount = SupportVectorSharedCount;
-
- // Now, check if a cache has already been created for this
- // thread and has adequate size. If it has not, create it.
-
- if (cache.Products == null || cache.Products.Length < vectorCount)
- {
- // The cache has not been created
- cache.Products = new double[vectorCount];
-
-#if !NET35 // Create synchronization objects
- cache.SyncObjects = new SpinLock[vectorCount];
- for (int i = 0; i < cache.SyncObjects.Length; i++)
- cache.SyncObjects[i] = new SpinLock();
-#endif
- }
-
- // Initialize (or reset) the cache. A value of Not-a-Number
- // indicates that the value of corresponding vector has not
- // been computed yet.
- for (int i = 0; i < cache.Products.Length; i++)
- cache.Products[i] = Double.NaN;
-
-
- cache.Evaluations = 0;
-
- return cache;
- }
-
-
- private int[][][] computeSharedVectors()
- {
- // This method should only be called once after the machine has
- // been learned. If the inner machines or they Support Vectors
- // change, this method will need to be recomputed.
-
- // Detect all vectors which are being shared along the machines
- var shared = new Dictionary>>();
-
- // for all machines
- for (int i = 0; i < machines.Length; i++)
- {
- for (int j = 0; j < machines[i].Length; j++)
- {
- // if the machine is not in compact form
- if (machines[i][j].SupportVectors != null)
- {
- // register the support vector on the shared cache collection
- for (int k = 0; k < machines[i][j].SupportVectors.Length; k++)
- {
- double[] sv = machines[i][j].SupportVectors[k];
-
- List> count;
- bool success = shared.TryGetValue(sv, out count);
-
- if (success)
- {
- // Value is already in the dictionary
- count.Add(Tuple.Create(i, j, k));
- }
- else
- {
- count = new List>();
- count.Add(Tuple.Create(i, j, k));
- shared[sv] = count;
- }
- }
- }
- }
- }
-
- // Create a table of indices for shared vectors
- int idx = 0;
-
- var indices = new Dictionary();
- foreach (double[] sv in shared.Keys)
- indices[sv] = idx++;
-
- // Create a lookup table for the machines
- int[][][] sharedVectors = new int[machines.Length][][];
- for (int i = 0; i < sharedVectors.Length; i++)
- {
- sharedVectors[i] = new int[machines[i].Length][];
- for (int j = 0; j < sharedVectors[i].Length; j++)
- {
- if (machines[i][j].SupportVectors != null)
- {
- sharedVectors[i][j] = new int[machines[i][j].SupportVectors.Length];
-
- for (int k = 0; k < machines[i][j].SupportVectors.Length; k++)
- {
- double[] sv = machines[i][j].SupportVectors[k];
- if (shared.ContainsKey(sv))
- sharedVectors[i][j][k] = indices[sv];
- else
- sharedVectors[i][j][k] = -1;
- }
- }
- }
- }
-
- sharedVectorsCount = shared.Count;
- return sharedVectors;
- }
-
- private class Cache
- {
- public int Evaluations;
- public double[] Products;
- public int[][][] Vectors;
-#if !NET35
- public SpinLock[] SyncObjects;
-#endif
- }
-
- #endregion
-
- }
-}
+ throw new Exception();
+
+ // For linear machines, computation is simpler
+ for (int i = 0; i < machine.Weights.Length; i++)
+ sum += machine.Weights[i] * input[i];
+ }
+ else
+ {
+
+#if NET35
+ #region Backward compatibility
+ for (int i = 0; i < vectors.Length; i++)
+ {
+ double value;
+
+ // Check if it is a shared vector
+ int j = vectors[i];
+
+ if (j >= 0)
+ {
+ // This is a shared vector. Check
+ // if it has already been computed
+
+ if (!Double.IsNaN(values[j]))
+ {
+ // Yes, it has. Retrieve the value from the cache
+ value = values[j];
+ }
+ else
+ {
+ // No, it has not. Compute and store the computed value in the cache
+ value = values[j] = machine.Kernel.Function(machine.SupportVectors[i], input);
+ Interlocked.Increment(ref cache.Evaluations);
+ }
+ }
+ else
+ {
+ // This vector is not shared by any other machine. No need to cache
+ value = machine.Kernel.Function(machine.SupportVectors[i], input);
+ Interlocked.Increment(ref cache.Evaluations);
+ }
+
+ sum += machine.Weights[i] * value;
+ }
+ #endregion
+#else
+ // For each support vector in the machine
+ Parallel.For(0, vectors.Length,
+
+ // Init
+ () => 0.0,
+
+ // Map
+ (i, state, partialSum) =>
+ {
+ double value;
+
+ // Check if it is a shared vector
+ int j = vectors[i];
+
+ if (j >= 0)
+ {
+ // This is a shared vector. Check
+ // if it has already been computed
+
+ bool taken = false;
+ locks[j].Enter(ref taken);
+
+ if (!Double.IsNaN(values[j]))
+ {
+ // Yes, it has. Retrieve the value from the cache
+ value = values[j];
+ }
+ else
+ {
+ // No, it has not. Compute and store the computed value in the cache
+ value = values[j] = machine.Kernel.Function(machine.SupportVectors[i], input);
+ Interlocked.Increment(ref cache.Evaluations);
+ }
+
+ locks[j].Exit();
+ }
+ else
+ {
+ // This vector is not shared by any other machine. No need to cache
+ value = machine.Kernel.Function(machine.SupportVectors[i], input);
+ Interlocked.Increment(ref cache.Evaluations);
+ }
+
+ return partialSum + machine.Weights[i] * value;
+ },
+
+ // Reduce
+ (partialSum) => { lock (locks) sum += partialSum; }
+ );
+#endif
+ }
+
+ // Produce probabilities if required
+ if (machine.IsProbabilistic)
+ {
+ output = machine.Link.Inverse(sum);
+ return output >= 0.5 ? +1 : -1;
+ }
+ else
+ {
+ output = sum;
+ return output >= 0 ? +1 : -1;
+ }
+ }
+ #endregion
+
+
+
+
+
+ ///
+ /// Resets the cache and machine statistics
+ /// so they can be recomputed on next evaluation.
+ ///
+ ///
+ public void Reset()
+ {
+ if (this.vectorCache != null)
+ this.vectorCache.Dispose();
+
+ this.sharedVectors = null;
+ this.totalVectorsCount = null;
+ this.uniqueVectorsCount = null;
+ this.sharedVectorsCount = null;
+
+ this.initialize();
+ }
+
+ ///
+ /// Gets the total kernel evaluations performed
+ /// in the last call to any of the
+ /// functions in the current thread.
+ ///
+ ///
+ /// The number of total kernel evaluations.
+ ///
+ public int GetLastKernelEvaluations()
+ {
+ return vectorCache.Value.Evaluations;
+ }
+
+
+ #region Loading & Saving
+
+ ///
+ /// Saves the machine to a stream.
+ ///
+ ///
+ /// The stream to which the machine is to be serialized.
+ ///
+ public void Save(Stream stream)
+ {
+ BinaryFormatter b = new BinaryFormatter();
+ b.Serialize(stream, this);
+ }
+
+ ///
+ /// Saves the machine to a file.
+ ///
+ ///
+ /// The path to the file to which the machine is to be serialized.
+ ///
+ public void Save(string path)
+ {
+ using (FileStream fs = new FileStream(path, FileMode.Create))
+ {
+ Save(fs);
+ }
+ }
+
+ ///
+ /// Loads a machine from a stream.
+ ///
+ ///
+ /// The stream from which the machine is to be deserialized.
+ ///
+ /// The deserialized machine.
+ ///
+ public static MulticlassSupportVectorMachine Load(Stream stream)
+ {
+ BinaryFormatter b = new BinaryFormatter();
+ return (MulticlassSupportVectorMachine)b.Deserialize(stream);
+ }
+
+ ///
+ /// Loads a machine from a file.
+ ///
+ ///
+ /// The path to the file from which the machine is to be deserialized.
+ ///
+ /// The deserialized machine.
+ ///
+ public static MulticlassSupportVectorMachine Load(string path)
+ {
+ using (FileStream fs = new FileStream(path, FileMode.Open))
+ {
+ return Load(fs);
+ }
+ }
+
+ [OnDeserialized]
+ private void onDeserialized(StreamingContext context)
+ {
+ initialize();
+ }
+ #endregion
+
+ #region IEnumerable members
+ ///
+ /// Returns an enumerator that iterates through all machines
+ /// contained inside this multi-class support vector machine.
+ ///
+ ///
+ public IEnumerator, KernelSupportVectorMachine>> GetEnumerator()
+ {
+ for (int i = 0; i < machines.Length; i++)
+ {
+ for (int j = 0; j < machines[i].Length; j++)
+ {
+ yield return new KeyValuePair, KernelSupportVectorMachine>(
+ Tuple.Create(i + 1, j), machines[i][j]);
+ }
+ }
+ }
+
+ ///
+ /// Returns an enumerator that iterates through all machines
+ /// contained inside this multi-class support vector machine.
+ ///
+ ///
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ #endregion
+
+ #region IDisposable members
+ ///
+ /// Performs application-defined tasks associated with
+ /// freeing, releasing, or resetting unmanaged resources.
+ ///
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources
+ ///
+ ///
+ ///
+ /// true to release both managed and unmanaged resources;
+ /// false to release only unmanaged resources.
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ // free managed resources
+ if (vectorCache != null)
+ {
+ vectorCache.Dispose();
+ vectorCache = null;
+ }
+ }
+ }
+ #endregion
+
+
+
+ #region Cache
+ private Cache createOrResetCache()
+ {
+ Cache cache = vectorCache.Value;
+
+ // First of all, check if the shared vectors in this machine
+ // already have been identified. If they don't, identify them.
+
+ cache.Vectors = sharedVectors.Value; // use lazy instantiation
+ int vectorCount = SupportVectorSharedCount;
+
+ // Now, check if a cache has already been created for this
+ // thread and has adequate size. If it has not, create it.
+
+ if (cache.Products == null || cache.Products.Length < vectorCount)
+ {
+ // The cache has not been created
+ cache.Products = new double[vectorCount];
+
+#if !NET35 // Create synchronization objects
+ cache.SyncObjects = new SpinLock[vectorCount];
+ for (int i = 0; i < cache.SyncObjects.Length; i++)
+ cache.SyncObjects[i] = new SpinLock();
+#endif
+ }
+
+ // Initialize (or reset) the cache. A value of Not-a-Number
+ // indicates that the value of corresponding vector has not
+ // been computed yet.
+ for (int i = 0; i < cache.Products.Length; i++)
+ cache.Products[i] = Double.NaN;
+
+
+ cache.Evaluations = 0;
+
+ return cache;
+ }
+
+
+ private int[][][] computeSharedVectors()
+ {
+ // This method should only be called once after the machine has
+ // been learned. If the inner machines or they Support Vectors
+ // change, this method will need to be recomputed.
+
+ // Detect all vectors which are being shared along the machines
+ var shared = new Dictionary>>();
+
+ // for all machines
+ for (int i = 0; i < machines.Length; i++)
+ {
+ for (int j = 0; j < machines[i].Length; j++)
+ {
+ // if the machine is not in compact form
+ if (machines[i][j].SupportVectors != null)
+ {
+ // register the support vector on the shared cache collection
+ for (int k = 0; k < machines[i][j].SupportVectors.Length; k++)
+ {
+ double[] sv = machines[i][j].SupportVectors[k];
+
+ List> count;
+ bool success = shared.TryGetValue(sv, out count);
+
+ if (success)
+ {
+ // Value is already in the dictionary
+ count.Add(Tuple.Create(i, j, k));
+ }
+ else
+ {
+ count = new List>();
+ count.Add(Tuple.Create(i, j, k));
+ shared[sv] = count;
+ }
+ }
+ }
+ }
+ }
+
+ // Create a table of indices for shared vectors
+ int idx = 0;
+
+ var indices = new Dictionary();
+ foreach (double[] sv in shared.Keys)
+ indices[sv] = idx++;
+
+ // Create a lookup table for the machines
+ int[][][] sharedVectors = new int[machines.Length][][];
+ for (int i = 0; i < sharedVectors.Length; i++)
+ {
+ sharedVectors[i] = new int[machines[i].Length][];
+ for (int j = 0; j < sharedVectors[i].Length; j++)
+ {
+ if (machines[i][j].SupportVectors != null)
+ {
+ sharedVectors[i][j] = new int[machines[i][j].SupportVectors.Length];
+
+ for (int k = 0; k < machines[i][j].SupportVectors.Length; k++)
+ {
+ double[] sv = machines[i][j].SupportVectors[k];
+ if (shared.ContainsKey(sv))
+ sharedVectors[i][j][k] = indices[sv];
+ else
+ sharedVectors[i][j][k] = -1;
+ }
+ }
+ }
+ }
+
+ sharedVectorsCount = shared.Count;
+ return sharedVectors;
+ }
+
+ private class Cache
+ {
+ public int Evaluations;
+ public double[] Products;
+ public int[][][] Vectors;
+#if !NET35
+ public SpinLock[] SyncObjects;
+#endif
+ }
+
+ #endregion
+
+ }
+}
diff --git a/Sources/Accord.Statistics/Models/Accord.Statistics.Models.cd b/Sources/Accord.Statistics/Models/Accord.Statistics.Models.cd
index 46a6f4a32..5b6760a40 100644
--- a/Sources/Accord.Statistics/Models/Accord.Statistics.Models.cd
+++ b/Sources/Accord.Statistics/Models/Accord.Statistics.Models.cd
@@ -1,227 +1,228 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- BEAAAAAAAAAAgAAAIAAAQAAAEEAAEDAAAAAAAAAAAAA=
- Models\Regression\Linear\MultivariateLinearRegression.cs
- Models\Regression\Linear\MultipleLinearRegression.cs
-
-
-
-
-
-
-
-
-
- AEAQAAAAAAAAgAAEAAAAAAAQAEAAEDAAAAAAAAAAAAA=
- Models\Regression\Linear\PolynomialRegression.cs
-
-
-
-
-
-
-
-
-
-
-
-
- AEAQAAAAAAAAgAAEAAAAAAAAAAAAEDAAAAAAAgAAAEA=
- Models\Regression\Linear\SimpleLinearRegression.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- AEAAAACAAAAAgAAEAAAAQABAEEAAEDAAAAAQAAAAAAA=
- Models\Regression\Linear\MultipleLinearRegression.cs
-
-
-
-
-
-
- AAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAIAAAAAAAAAA=
- Models\Regression\Nonlinear\LogisticRegression.cs
-
-
-
-
-
-
-
-
-
-
-
- BEAIAAAAAoAjCAYJBACIAAQAEAEAACAAAAQgABAAAAA=
- Analysis\StepwiseLogisticRegressionAnalysis.cs
-
-
-
-
-
-
-
-
-
- AQAAgIAAAgAAAAAAAAAAAAAAUEAAAAAARAQABAAAEAA=
- Analysis\StepwiseLogisticRegressionAnalysis.cs
-
-
-
-
-
-
-
-
-
-
-
- AEAAAAAAAAAAAAAQAAACQIAYEEAAEBAAYAAABEAAABA=
- Models\Regression\Nonlinear\MultinomialLogisticRegression.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- AACQABAAAAByQgAAVAIAAAoAkAAIAAAAAYAAAAEAgII=
- Models\Survival\Fitting\PartialNewtonRaphson.cs
-
-
-
-
-
-
- IEAAAAAAAAAABAAAAAACAIAIEEAAAQAAQAAAhAAAAFA=
- Models\Survival\ProportionalHazards.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- QASQABAAAABAQgAAQAIAAAgAAAAIAAAAAYAAAAAAgAI=
- Models\Regression\Nonlinear\Fitting\IterativeReweightedLeastSquares.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- AECQAhEAAAFQQgAAQAMAAAEACAAAQABAAYAAAMJAgAI=
- Models\Regression\Nonlinear\Fitting\LowerBoundNewtonRaphson.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- AAQQAFAAAABAAgAEQAIABAAAAAAAAAAAAYAAAGAAAAI=
- Models\Regression\Nonlinear\Fitting\LogisticGradientDescent.cs
-
-
-
-
-
-
- AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
- Models\Regression\Linear\ILinearRegression.cs
-
-
-
-
-
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI=
- Models\Survival\Fitting\ISurvivalFitting.cs
-
-
-
-
-
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI=
- Models\Regression\Nonlinear\Fitting\Base\IMultipleRegressionFitting.cs
-
-
-
-
-
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI=
- Models\Regression\Nonlinear\Fitting\Base\IRegressionFitting.cs
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BEAAAAAAAAAAgAAAIAAAQAAAEEAAEDAAAAAAAAAAAAA=
+ Models\Regression\Linear\MultivariateLinearRegression.cs
+ Models\Regression\Linear\MultipleLinearRegression.cs
+
+
+
+
+
+
+
+
+
+ AEAQAAAAAAAAgAAEAAAAAAAQAEAAEDAAAAAAAAAAAAA=
+ Models\Regression\Linear\PolynomialRegression.cs
+
+
+
+
+
+
+
+
+
+
+
+
+ AEAQAAAAAAAAgAAEAAAAAAAAAAAAEDAAAAAAAgAAAEA=
+ Models\Regression\Linear\SimpleLinearRegression.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AEAAAACAAAAAgAAEAAAAQABAEEAAEDAAAAAQAAAAAAA=
+ Models\Regression\Linear\MultipleLinearRegression.cs
+
+
+
+
+
+
+ AAIAAAAAAAAAAAAAAAAAAAAAAEAAAAAAIAAAAAAAAAA=
+ Models\Regression\Nonlinear\LogisticRegression.cs
+
+
+
+
+
+
+
+
+
+
+
+ BEAIAAIAAoAjCAYJBgCIAAYAEAAAACAAAAQgABAAAAA=
+ Analysis\StepwiseLogisticRegressionAnalysis.cs
+
+
+
+
+
+
+
+
+
+ AQAAgIAAAgAAAAAAAAAAAAAAUEAAAAAARAQABAAAEAA=
+ Analysis\StepwiseLogisticRegressionAnalysis.cs
+
+
+
+
+
+
+
+
+
+
+
+ AEAAAAAAAAAAAAAQAAACQIAYEEAAEBAAYAAABEAAABA=
+ Models\Regression\Nonlinear\MultinomialLogisticRegression.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AAiQABAAAAByQgAAVAIAAAoAgIAIAAAAAYAAQAEAgII=
+ Models\Survival\Fitting\ProportionalHazardsNewtonRaphson.cs
+
+
+
+
+
+
+ IEQAAAAAAAAABAAAAAACAIAIEEAAAQAAQAAAhAAAAFA=
+ Models\Survival\ProportionalHazards.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ QASQABAIAABAQgAAQAIAAggAAAAIAAAAAYAAAAAAgAI=
+ Models\Regression\Nonlinear\Fitting\IterativeReweightedLeastSquares.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AECQAhEAAAFQQgAAQAMAAAEACAAAQABAAYAAAMJAgAI=
+ Models\Regression\Nonlinear\Fitting\LowerBoundNewtonRaphson.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AAQQAFAAAABAAgAEQAIABAAAAAAAAAAAAYAAAGAAAAI=
+ Models\Regression\Nonlinear\Fitting\LogisticGradientDescent.cs
+
+
+
+
+
+
+ AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ Models\Regression\Linear\ILinearRegression.cs
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI=
+ Models\Survival\Fitting\ISurvivalFitting.cs
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI=
+ Models\Regression\Nonlinear\Fitting\Base\IMultipleRegressionFitting.cs
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI=
+ Models\Regression\Nonlinear\Fitting\Base\IRegressionFitting.cs
+
+
+
\ No newline at end of file
diff --git a/Sources/Accord.Statistics/Models/Markov/Learning/BaumWelchLearning`1.cs b/Sources/Accord.Statistics/Models/Markov/Learning/BaumWelchLearning`1.cs
index 3c07c6764..5529ac1fc 100644
--- a/Sources/Accord.Statistics/Models/Markov/Learning/BaumWelchLearning`1.cs
+++ b/Sources/Accord.Statistics/Models/Markov/Learning/BaumWelchLearning`1.cs
@@ -205,7 +205,7 @@ namespace Accord.Statistics.Models.Markov.Learning
/// new double[] { 9, 8 }, // observation 2 of sequence 2
/// new double[] { 1, 0 }, // observation 3 of sequence 2
/// },
- /// new double[][] // sequence 3
+ /// new double[][] // sequence 3
/// {
/// new double[] { 1, 3 }, // observation 1 of sequence 3
/// new double[] { 8, 9 }, // observation 2 of sequence 3
diff --git a/Unit Tests/Accord.Tests.Imaging/BagOfVisualWordsTest.cs b/Unit Tests/Accord.Tests.Imaging/BagOfVisualWordsTest.cs
index e326f27ea..e201288fd 100644
--- a/Unit Tests/Accord.Tests.Imaging/BagOfVisualWordsTest.cs
+++ b/Unit Tests/Accord.Tests.Imaging/BagOfVisualWordsTest.cs
@@ -22,6 +22,7 @@
namespace Accord.Tests.Imaging
{
+ using Accord;
using Accord.Imaging;
using Accord.MachineLearning;
using Accord.Math;
@@ -178,6 +179,8 @@ public void GetFeatureVectorTest()
[Test]
public void SerializeTest()
{
+ var images = BagOfVisualWordsTest.images.DeepClone();
+
Accord.Math.Tools.SetupGenerator(0);
BagOfVisualWords bow = new BagOfVisualWords(10);
@@ -205,6 +208,8 @@ public void SerializeTest()
[Test]
public void SerializeTest2()
{
+ var images = BagOfVisualWordsTest.images.DeepClone();
+
Accord.Math.Tools.SetupGenerator(0);
FastCornersDetector fast = new FastCornersDetector();
diff --git a/Unit Tests/Accord.Tests.MachineLearning/DecisionTrees/C45LearningTest.cs b/Unit Tests/Accord.Tests.MachineLearning/DecisionTrees/C45LearningTest.cs
index 43fbddba3..3b010db82 100644
--- a/Unit Tests/Accord.Tests.MachineLearning/DecisionTrees/C45LearningTest.cs
+++ b/Unit Tests/Accord.Tests.MachineLearning/DecisionTrees/C45LearningTest.cs
@@ -488,7 +488,7 @@ public void IrisDatasetTest()
double[][] inputs = new double[text.Length][];
for (int i = 0; i < inputs.Length; i++)
- inputs[i] = text[i].Submatrix(4).Convert(Double.Parse);
+ inputs[i] = text[i].Submatrix(4).Convert(s => Double.Parse(s, System.Globalization.CultureInfo.InvariantCulture));
string[] labels = text.GetColumn(4);
@@ -535,7 +535,7 @@ public void AttributeReuseTest1()
double[][] inputs = new double[text.Length][];
for (int i = 0; i < inputs.Length; i++)
- inputs[i] = text[i].Submatrix(4).Convert(Double.Parse);
+ inputs[i] = text[i].Submatrix(4).Convert(s => Double.Parse(s, System.Globalization.CultureInfo.InvariantCulture));
string[] labels = text.GetColumn(4);
diff --git a/Unit Tests/Accord.Tests.Neuro/LevenbergMarquardtLearningTest.cs b/Unit Tests/Accord.Tests.Neuro/LevenbergMarquardtLearningTest.cs
index f97736eda..c9c29e61e 100644
--- a/Unit Tests/Accord.Tests.Neuro/LevenbergMarquardtLearningTest.cs
+++ b/Unit Tests/Accord.Tests.Neuro/LevenbergMarquardtLearningTest.cs
@@ -685,7 +685,7 @@ public void ZeroLambdaTest()
using (TextReader stream = new StringReader(Properties.Resources.ZeroLambda))
using (CsvReader reader = new CsvReader(stream, false))
{
- data = reader.ToTable().ToMatrix();
+ data = reader.ToTable().ToMatrix(System.Globalization.CultureInfo.InvariantCulture);
}
// number of learning samples
@@ -720,12 +720,12 @@ public void ZeroLambdaTest()
Neuron.RandGenerator = new ThreadSafeRandom(0);
// create multi-layer neural network
- ActivationNetwork network = new ActivationNetwork(
+ var network = new ActivationNetwork(
new BipolarSigmoidFunction(5),
1, 12, 1);
// create teacher
- LevenbergMarquardtLearning teacher = new LevenbergMarquardtLearning(network, true);
+ var teacher = new LevenbergMarquardtLearning(network, true);
teacher.LearningRate = 1;
diff --git a/Unit Tests/Accord.Tests.Statistics/Distributions/Multivariate/IndependentTest.cs b/Unit Tests/Accord.Tests.Statistics/Distributions/Multivariate/IndependentTest.cs
index 4ba92e5b9..775eed9a0 100644
--- a/Unit Tests/Accord.Tests.Statistics/Distributions/Multivariate/IndependentTest.cs
+++ b/Unit Tests/Accord.Tests.Statistics/Distributions/Multivariate/IndependentTest.cs
@@ -56,7 +56,7 @@ public void ConstructorTest()
Assert.AreEqual(0, target.Covariance[0, 1]);
Assert.AreEqual(0, target.Covariance[1, 0]);
- var text = target.ToString("N2");
+ var text = target.ToString("N2", System.Globalization.CultureInfo.InvariantCulture);
Assert.AreEqual("Independent(x0, x1; N(x0; μ = 4.20, σ² = 1.00) + N(x1; μ = 7.00, σ² = 4.00))", text);
}
diff --git a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/BetaPrimeDistributionTest.cs b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/BetaPrimeDistributionTest.cs
index e46b10833..b96d61682 100644
--- a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/BetaPrimeDistributionTest.cs
+++ b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/BetaPrimeDistributionTest.cs
@@ -23,28 +23,12 @@
namespace Accord.Tests.Statistics.Distributions.Univariate.Continuous
{
using Accord.Statistics.Distributions.Univariate;
- using Accord.Statistics.Distributions.Univariate.Continuous;
using NUnit.Framework;
using System.Globalization;
[TestFixture]
public class BetaPrimeDistributionTest
{
- private TestContext testContextInstance;
-
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
-
[Test]
public void Confirm_BetPrimeDistribution_Relative_to_F_Distribution()
{
diff --git a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/KumaraswamyDistributionTest.cs b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/KumaraswamyDistributionTest.cs
index 2c61b9cf4..7d4eb4f1d 100644
--- a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/KumaraswamyDistributionTest.cs
+++ b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/KumaraswamyDistributionTest.cs
@@ -24,27 +24,12 @@ namespace Accord.Tests.Statistics.Distributions.Univariate.Continuous
{
using System;
using System.Globalization;
- using Accord.Statistics.Distributions.Univariate.Continuous;
+ using Accord.Statistics.Distributions.Univariate;
using NUnit.Framework;
[TestFixture]
public class KumaraswamyDistributionTest
{
- private TestContext testContextInstance;
-
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
-
[Test]
public void Constructor_KumaraswamyDistribution_PDF_given_0d2_AND_1d2_Parameters_Moments_matches_R_output()
{
diff --git a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/TrapezoidalDistributionTest.cs b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/TrapezoidalDistributionTest.cs
index fef4289bf..6c7fe40b6 100644
--- a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/TrapezoidalDistributionTest.cs
+++ b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/TrapezoidalDistributionTest.cs
@@ -23,28 +23,13 @@
namespace Accord.Tests.Statistics.Distributions.Univariate.Continuous
{
using System;
- using Accord.Statistics.Distributions.Univariate.Continuous;
+ using Accord.Statistics.Distributions.Univariate;
using NUnit.Framework;
using System.Globalization;
[TestFixture]
public class TrapezoidalDistributionTest
{
-
- private TestContext testContextInstance;
-
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
[Test]
public void TrapezoidalDistributionConstructorTest()
{
diff --git a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/UQuadraticDistributionTest.cs b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/UQuadraticDistributionTest.cs
index dba01ffe8..03f3eae0c 100644
--- a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/UQuadraticDistributionTest.cs
+++ b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/Continuous/UQuadraticDistributionTest.cs
@@ -23,7 +23,7 @@
namespace Accord.Tests.Statistics.Distributions.Univariate.Continuous
{
using System;
- using Accord.Statistics.Distributions.Univariate.Continuous;
+ using Accord.Statistics.Distributions.Univariate;
using NUnit.Framework;
using System.Globalization;
@@ -31,20 +31,6 @@ namespace Accord.Tests.Statistics.Distributions.Univariate.Continuous
public class UQuadraticDistributionTest
{
- private TestContext testContextInstance;
-
- public TestContext TestContext
- {
- get
- {
- return testContextInstance;
- }
- set
- {
- testContextInstance = value;
- }
- }
-
[Test]
public void Constructor_UQuadratic()
{
diff --git a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/MixtureDistributionTest.cs b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/MixtureDistributionTest.cs
index 246281550..21d4ecb87 100644
--- a/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/MixtureDistributionTest.cs
+++ b/Unit Tests/Accord.Tests.Statistics/Distributions/Univariate/MixtureDistributionTest.cs
@@ -380,7 +380,7 @@ public void MixtureFitTest()
Threshold = 0
});
- var result = mixture.ToString("N2");
+ var result = mixture.ToString("N2", System.Globalization.CultureInfo.InvariantCulture);
Assert.AreEqual("Mixture(x; 0.50*N(x; μ = -2.00, σ² = 0.25) + 0.50*N(x; μ = 4.00, σ² = 0.25))", result);
}