diff --git a/README.md b/README.md
index 92ce5da..12fb9b9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-## ofxTSNE
+# ofxTSNE
ofxTSNE is an [addon](https://www.ofxaddons.com) for [openframeworks](https://www.openframeworks.cc) which wraps the [t-SNE](https://lvdmaaten.github.io/tsne/) (t-Distributed Stochastic Neighbor Embedding) algorithm by [Laurens van der Maaten](https://lvdmaaten.github.io).
@@ -19,7 +19,7 @@ ofxTSNE is very simple to run, containing only one function. The harder part is
![t-SNE images from Caltech-256](http://www.genekogan.com/images/misc/ofxTsne2.jpg)
-`example-images` applies t-SNE to a directory of images. It uses [ofxCcv](https://www.github.com/kylemcdonald/ofxCcv) to encode each image as a compact (4096-dim) feature vector derived from a convolutional neural net trained on ImageNet. The resulting representation captures high-level similarities among images, enabling ofxTSNE to group them effectively according more to content (e.g. images of cats get clustered together), relatively invariant to changes in color, lighting, position, etc.
+`example-images` applies t-SNE to a directory of images. It uses [ofxCcv](https://www.github.com/kylemcdonald/ofxCcv) to encode each image as a compact (4096-dim) feature vector derived from a trained convolutional neural network. The resulting representation captures high-level similarities among images, enabling ofxTSNE to group them effectively according more to content (e.g. images of cats get clustered together), relatively invariant to changes in color, lighting, position, etc.
To run this example, you need to take a few extra steps.
diff --git a/download_images.py b/download_images.py
new file mode 100644
index 0000000..ad155e7
--- /dev/null
+++ b/download_images.py
@@ -0,0 +1,26 @@
+import urllib
+import os
+
+
+root_dir = 'example-images/bin/data/images'
+num_images_per_category = 30
+categories = [ [2, "american-flag"], [63, "electric-guitar-101"], [56, "dog"], [24, "butterfly"], [15, "bonsai"], [25, "cactus"], [38, "chimp"], [60, "duck"], [53, "desk-globe"], [95, "hamburger"], [195, "soda-can"], [187, "skyscraper"], [150, "octopus"], [152, "owl"], [136, "mandolin"], [127, "laptop-101"], [80, "frog"], [29, "cannon"], [37, "chess-board"], [10, "beer-mug"], [246, "wine-bottle"], [250, "zebra"], [221, "tomato"], [113, "hummingbird"], [91, "grand-piano-101"], [87, "goldfish"], [86, "golden-gate-bridge"], [81, "frying-pan"], [57, "dolphin-101"], [46, "computer-monitor"], [22, "buddha-101"] ]
+
+
+
+
+cmd = 'mkdir %s' % root_dir
+os.system(cmd)
+
+url_root = 'http://www.vision.caltech.edu/Image_Datasets/Caltech256/images/'
+for c in categories:
+ for i in range(21,31):#range(1,num_images_per_category+1):
+ path = 'http://www.vision.caltech.edu/Image_Datasets/Caltech256/images/%03d.%s/%03d_%04d.jpg' % (c[0], c[1], c[0], i)
+ print "download %s"%path
+ urllib.urlretrieve(path, "%s/%s-%04d.jpg " % (root_dir, c[1], i))
+
+
+
+
+
+
diff --git a/example-images/Makefile b/example-images/Makefile
new file mode 100644
index 0000000..8d8e4c0
--- /dev/null
+++ b/example-images/Makefile
@@ -0,0 +1,13 @@
+# Attempt to load a config.make file.
+# If none is found, project defaults in config.project.make will be used.
+ifneq ($(wildcard config.make),)
+ include config.make
+endif
+
+# make sure the the OF_ROOT location is defined
+ifndef OF_ROOT
+ OF_ROOT=$(realpath ../../..)
+endif
+
+# call the project makefile!
+include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk
diff --git a/example-images/Project.xcconfig b/example-images/Project.xcconfig
new file mode 100644
index 0000000..e570b15
--- /dev/null
+++ b/example-images/Project.xcconfig
@@ -0,0 +1,17 @@
+//THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT.
+//THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED
+OF_PATH = ../../..
+
+//THIS HAS ALL THE HEADER AND LIBS FOR OF CORE
+#include "../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig"
+
+//ICONS - NEW IN 0072
+ICON_NAME_DEBUG = icon-debug.icns
+ICON_NAME_RELEASE = icon.icns
+ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/
+
+//IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to:
+//ICON_FILE_PATH = bin/data/
+
+OTHER_LDFLAGS = $(OF_CORE_LIBS) $(OF_CORE_FRAMEWORKS)
+HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS)
diff --git a/example-images/addons.make b/example-images/addons.make
new file mode 100644
index 0000000..f583b9c
--- /dev/null
+++ b/example-images/addons.make
@@ -0,0 +1,3 @@
+ofxCcv
+ofxGui
+ofxTSNE
diff --git a/example-images/bin/data/.gitkeep b/example-images/bin/data/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/example-images/config.make b/example-images/config.make
new file mode 100644
index 0000000..df10f64
--- /dev/null
+++ b/example-images/config.make
@@ -0,0 +1,142 @@
+################################################################################
+# CONFIGURE PROJECT MAKEFILE (optional)
+# This file is where we make project specific configurations.
+################################################################################
+
+################################################################################
+# OF ROOT
+# The location of your root openFrameworks installation
+# (default) OF_ROOT = ../../..
+################################################################################
+# OF_ROOT = ../../..
+
+################################################################################
+# PROJECT ROOT
+# The location of the project - a starting place for searching for files
+# (default) PROJECT_ROOT = . (this directory)
+#
+################################################################################
+# PROJECT_ROOT = .
+
+################################################################################
+# PROJECT SPECIFIC CHECKS
+# This is a project defined section to create internal makefile flags to
+# conditionally enable or disable the addition of various features within
+# this makefile. For instance, if you want to make changes based on whether
+# GTK is installed, one might test that here and create a variable to check.
+################################################################################
+# None
+
+################################################################################
+# PROJECT EXTERNAL SOURCE PATHS
+# These are fully qualified paths that are not within the PROJECT_ROOT folder.
+# Like source folders in the PROJECT_ROOT, these paths are subject to
+# exlclusion via the PROJECT_EXLCUSIONS list.
+#
+# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXTERNAL_SOURCE_PATHS =
+
+################################################################################
+# PROJECT EXCLUSIONS
+# These makefiles assume that all folders in your current project directory
+# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
+# to look for source code. The any folders or files that match any of the
+# items in the PROJECT_EXCLUSIONS list below will be ignored.
+#
+# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
+# string unless teh user adds a wildcard (%) operator to match subdirectories.
+# GNU make only allows one wildcard for matching. The second wildcard (%) is
+# treated literally.
+#
+# (default) PROJECT_EXCLUSIONS = (blank)
+#
+# Will automatically exclude the following:
+#
+# $(PROJECT_ROOT)/bin%
+# $(PROJECT_ROOT)/obj%
+# $(PROJECT_ROOT)/%.xcodeproj
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXCLUSIONS =
+
+################################################################################
+# PROJECT LINKER FLAGS
+# These flags will be sent to the linker when compiling the executable.
+#
+# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+
+# Currently, shared libraries that are needed are copied to the
+# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
+# add a runtime path to search for those shared libraries, since they aren't
+# incorporated directly into the final executable application binary.
+# TODO: should this be a default setting?
+# PROJECT_LDFLAGS=-Wl,-rpath=./libs
+
+################################################################################
+# PROJECT DEFINES
+# Create a space-delimited list of DEFINES. The list will be converted into
+# CFLAGS with the "-D" flag later in the makefile.
+#
+# (default) PROJECT_DEFINES = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_DEFINES =
+
+################################################################################
+# PROJECT CFLAGS
+# This is a list of fully qualified CFLAGS required when compiling for this
+# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
+# defined in your platform specific core configuration files. These flags are
+# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
+#
+# (default) PROJECT_CFLAGS = (blank)
+#
+# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
+# your platform specific configuration file will be applied by default and
+# further flags here may not be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CFLAGS =
+
+################################################################################
+# PROJECT OPTIMIZATION CFLAGS
+# These are lists of CFLAGS that are target-specific. While any flags could
+# be conditionally added, they are usually limited to optimization flags.
+# These flags are added BEFORE the PROJECT_CFLAGS.
+#
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
+#
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
+#
+# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
+# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
+# file will be applied by default and further optimization flags here may not
+# be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
+
+################################################################################
+# PROJECT COMPILERS
+# Custom compilers can be set for CC and CXX
+# (default) PROJECT_CXX = (blank)
+# (default) PROJECT_CC = (blank)
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CXX =
+# PROJECT_CC =
diff --git a/example-images/example-images.xcodeproj/project.pbxproj b/example-images/example-images.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..ab87279
--- /dev/null
+++ b/example-images/example-images.xcodeproj/project.pbxproj
@@ -0,0 +1,1372 @@
+
+
+
+ archiveVersion
+ 1
+ classes
+
+ objectVersion
+ 46
+ objects
+
+ A18A04F43F1A3D8641B0D261
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxTSNE.h
+ path
+ ../../../addons/ofxTSNE/src/ofxTSNE.h
+ sourceTree
+ SOURCE_ROOT
+
+ 51A4134BF889D553064DCD2E
+
+ fileRef
+ D985BBD882BD1582C610B30C
+ isa
+ PBXBuildFile
+
+ D985BBD882BD1582C610B30C
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxTSNE.cpp
+ path
+ ../../../addons/ofxTSNE/src/ofxTSNE.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 1F7816F26F468BAC49B9ADD0
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ vptree.h
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/vptree.h
+ sourceTree
+ SOURCE_ROOT
+
+ 54DCDCE01CF02EC24329509D
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ tsne.h
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/tsne.h
+ sourceTree
+ SOURCE_ROOT
+
+ BF438D1989EA8474A24FC372
+
+ fileRef
+ C5EC22EBF07D1C6136CAFF40
+ isa
+ PBXBuildFile
+
+ C5EC22EBF07D1C6136CAFF40
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ tsne.cpp
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/tsne.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ D361105E69E9248C8CDD4024
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ sptree.h
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/sptree.h
+ sourceTree
+ SOURCE_ROOT
+
+ C289F16CCC88C08ABEBC3CE6
+
+ children
+
+ 29CFCFEEAF44F7849B7A8E2C
+ D361105E69E9248C8CDD4024
+ C5EC22EBF07D1C6136CAFF40
+ 54DCDCE01CF02EC24329509D
+ 1F7816F26F468BAC49B9ADD0
+
+ isa
+ PBXGroup
+ name
+ bhtsne
+ sourceTree
+ <group>
+
+ 84110FEC26026E23FCEDE55A
+
+ children
+
+ C289F16CCC88C08ABEBC3CE6
+ D985BBD882BD1582C610B30C
+ A18A04F43F1A3D8641B0D261
+
+ isa
+ PBXGroup
+ name
+ src
+ sourceTree
+ <group>
+
+ A2C3A140678F172C21702046
+
+ children
+
+ 84110FEC26026E23FCEDE55A
+
+ isa
+ PBXGroup
+ name
+ ofxTSNE
+ sourceTree
+ <group>
+
+ 3F59654CA5CEEFA57C8D09DC
+
+ fileRef
+ 29CFCFEEAF44F7849B7A8E2C
+ isa
+ PBXBuildFile
+
+ 29CFCFEEAF44F7849B7A8E2C
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ sptree.cpp
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/sptree.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 0A1DAC09F322AE313A40706D
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxToggle.h
+ path
+ ../../../addons/ofxGui/src/ofxToggle.h
+ sourceTree
+ SOURCE_ROOT
+
+ 1CD33E884D9E3358252E82A1
+
+ fileRef
+ 907C5B5E104864A2D3A25745
+ isa
+ PBXBuildFile
+
+ 907C5B5E104864A2D3A25745
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxToggle.cpp
+ path
+ ../../../addons/ofxGui/src/ofxToggle.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ C70D8946940288799E82131E
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxSliderGroup.h
+ path
+ ../../../addons/ofxGui/src/ofxSliderGroup.h
+ sourceTree
+ SOURCE_ROOT
+
+ B56FE57CC35806596D38118C
+
+ fileRef
+ 802251BAF1B35B1D67B32FD0
+ isa
+ PBXBuildFile
+
+ 802251BAF1B35B1D67B32FD0
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxSliderGroup.cpp
+ path
+ ../../../addons/ofxGui/src/ofxSliderGroup.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 52AFA1F08C420992CAAAE648
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxSlider.h
+ path
+ ../../../addons/ofxGui/src/ofxSlider.h
+ sourceTree
+ SOURCE_ROOT
+
+ 837220E80EB56CD44AD27F2A
+
+ fileRef
+ 15F2C6477A769C03A56D1401
+ isa
+ PBXBuildFile
+
+ 15F2C6477A769C03A56D1401
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxSlider.cpp
+ path
+ ../../../addons/ofxGui/src/ofxSlider.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 89449E3044D456F7DE7BEA14
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxPanel.h
+ path
+ ../../../addons/ofxGui/src/ofxPanel.h
+ sourceTree
+ SOURCE_ROOT
+
+ F285EB3169F1566CA3D93C20
+
+ fileRef
+ E112B3AEBEA2C091BF2B40AE
+ isa
+ PBXBuildFile
+
+ E112B3AEBEA2C091BF2B40AE
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxPanel.cpp
+ path
+ ../../../addons/ofxGui/src/ofxPanel.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ B87C60311EC1FE841C1ECD89
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxLabel.h
+ path
+ ../../../addons/ofxGui/src/ofxLabel.h
+ sourceTree
+ SOURCE_ROOT
+
+ 483908258D00B98B4BE69F07
+
+ fileRef
+ 78D67A00EB899FAC09430597
+ isa
+ PBXBuildFile
+
+ 78D67A00EB899FAC09430597
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxLabel.cpp
+ path
+ ../../../addons/ofxGui/src/ofxLabel.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 1C0DA2561397A7DE0246858B
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxGuiGroup.h
+ path
+ ../../../addons/ofxGui/src/ofxGuiGroup.h
+ sourceTree
+ SOURCE_ROOT
+
+ B266578FC55D23BFEBC042E7
+
+ fileRef
+ ECF8674C7975F1063C5E30CA
+ isa
+ PBXBuildFile
+
+ ECF8674C7975F1063C5E30CA
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxGuiGroup.cpp
+ path
+ ../../../addons/ofxGui/src/ofxGuiGroup.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 17E65988300FBD9AAA2CD0CA
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxGui.h
+ path
+ ../../../addons/ofxGui/src/ofxGui.h
+ sourceTree
+ SOURCE_ROOT
+
+ 2834D88A62CD23F3DE2C47D1
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxButton.h
+ path
+ ../../../addons/ofxGui/src/ofxButton.h
+ sourceTree
+ SOURCE_ROOT
+
+ 5CBB2AB3A60F65431D7B555D
+
+ fileRef
+ C88333E71C9457E441C33474
+ isa
+ PBXBuildFile
+
+ C88333E71C9457E441C33474
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxButton.cpp
+ path
+ ../../../addons/ofxGui/src/ofxButton.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 87F26B4B24CBD428AD9EEBAA
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxBaseGui.h
+ path
+ ../../../addons/ofxGui/src/ofxBaseGui.h
+ sourceTree
+ SOURCE_ROOT
+
+ A763ED608B35AE3310251DEE
+
+ children
+
+ 9604B925D32EE39065747725
+ 87F26B4B24CBD428AD9EEBAA
+ C88333E71C9457E441C33474
+ 2834D88A62CD23F3DE2C47D1
+ 17E65988300FBD9AAA2CD0CA
+ ECF8674C7975F1063C5E30CA
+ 1C0DA2561397A7DE0246858B
+ 78D67A00EB899FAC09430597
+ B87C60311EC1FE841C1ECD89
+ E112B3AEBEA2C091BF2B40AE
+ 89449E3044D456F7DE7BEA14
+ 15F2C6477A769C03A56D1401
+ 52AFA1F08C420992CAAAE648
+ 802251BAF1B35B1D67B32FD0
+ C70D8946940288799E82131E
+ 907C5B5E104864A2D3A25745
+ 0A1DAC09F322AE313A40706D
+
+ isa
+ PBXGroup
+ name
+ src
+ sourceTree
+ <group>
+
+ 480A780D8D0308AE4A368801
+
+ children
+
+ A763ED608B35AE3310251DEE
+
+ isa
+ PBXGroup
+ name
+ ofxGui
+ sourceTree
+ <group>
+
+ 856AA354D08AB4B323081444
+
+ fileRef
+ 9604B925D32EE39065747725
+ isa
+ PBXBuildFile
+
+ 9604B925D32EE39065747725
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxBaseGui.cpp
+ path
+ ../../../addons/ofxGui/src/ofxBaseGui.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 61711D3347CDFB64FA721D44
+
+ children
+
+ 85307C7E25682171EB5DC998
+
+ isa
+ PBXGroup
+ name
+ include
+ sourceTree
+ <group>
+
+ FBBD8BC6A172852ABC6FF337
+
+ children
+
+ 61711D3347CDFB64FA721D44
+
+ isa
+ PBXGroup
+ name
+ ccv
+ sourceTree
+ <group>
+
+ 88578B999DE5C1A63035FFCB
+
+ children
+
+ FBBD8BC6A172852ABC6FF337
+
+ isa
+ PBXGroup
+ name
+ libs
+ sourceTree
+ <group>
+
+ 85307C7E25682171EB5DC998
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ccv.h
+ path
+ ../../../addons/ofxCcv/libs/ccv/include/ccv.h
+ sourceTree
+ SOURCE_ROOT
+
+ DE75137AC67515D3FC3624C7
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxCcv.h
+ path
+ ../../../addons/ofxCcv/src/ofxCcv.h
+ sourceTree
+ SOURCE_ROOT
+
+ CBD10E62E7E6E2DA133E22ED
+
+ children
+
+ EA24FDDC5E989AF2191488A3
+ DE75137AC67515D3FC3624C7
+
+ isa
+ PBXGroup
+ name
+ src
+ sourceTree
+ <group>
+
+ 795B0427BBCB5647F47B56C8
+
+ children
+
+ CBD10E62E7E6E2DA133E22ED
+ 88578B999DE5C1A63035FFCB
+
+ isa
+ PBXGroup
+ name
+ ofxCcv
+ sourceTree
+ <group>
+
+ 6A5A3AF2E51903FC129D6939
+
+ fileRef
+ EA24FDDC5E989AF2191488A3
+ isa
+ PBXBuildFile
+
+ EA24FDDC5E989AF2191488A3
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxCcv.cpp
+ path
+ ../../../addons/ofxCcv/src/ofxCcv.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ BB4B014C10F69532006C3DED
+
+ children
+
+ 795B0427BBCB5647F47B56C8
+ 480A780D8D0308AE4A368801
+ A2C3A140678F172C21702046
+
+ isa
+ PBXGroup
+ name
+ addons
+ sourceTree
+ <group>
+
+ 6948EE371B920CB800B5AC1A
+
+ children
+
+ isa
+ PBXGroup
+ name
+ local_addons
+ sourceTree
+ <group>
+
+ E4328143138ABC890047C5CB
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ wrapper.pb-project
+ name
+ openFrameworksLib.xcodeproj
+ path
+ ../../../libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj
+ sourceTree
+ SOURCE_ROOT
+
+ E4328144138ABC890047C5CB
+
+ children
+
+ E4328148138ABC890047C5CB
+
+ isa
+ PBXGroup
+ name
+ Products
+ sourceTree
+ <group>
+
+ E4328147138ABC890047C5CB
+
+ containerPortal
+ E4328143138ABC890047C5CB
+ isa
+ PBXContainerItemProxy
+ proxyType
+ 2
+ remoteGlobalIDString
+ E4B27C1510CBEB8E00536013
+ remoteInfo
+ openFrameworks
+
+ E4328148138ABC890047C5CB
+
+ fileType
+ archive.ar
+ isa
+ PBXReferenceProxy
+ path
+ openFrameworksDebug.a
+ remoteRef
+ E4328147138ABC890047C5CB
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ E4328149138ABC9F0047C5CB
+
+ fileRef
+ E4328148138ABC890047C5CB
+ isa
+ PBXBuildFile
+
+ E4B69B4A0A3A1720003C02F2
+
+ children
+
+ E4B6FCAD0C3E899E008CF71C
+ E4EB6923138AFD0F00A09F29
+ E4B69E1C0A3A1BDC003C02F2
+ E4EEC9E9138DF44700A80321
+ BB4B014C10F69532006C3DED
+ 6948EE371B920CB800B5AC1A
+ E4B69B5B0A3A1756003C02F2
+
+ isa
+ PBXGroup
+ sourceTree
+ <group>
+
+ E4B69B4C0A3A1720003C02F2
+
+ attributes
+
+ LastUpgradeCheck
+ 0600
+
+ buildConfigurationList
+ E4B69B4D0A3A1720003C02F2
+ compatibilityVersion
+ Xcode 3.2
+ developmentRegion
+ English
+ hasScannedForEncodings
+ 0
+ isa
+ PBXProject
+ knownRegions
+
+ English
+ Japanese
+ French
+ German
+
+ mainGroup
+ E4B69B4A0A3A1720003C02F2
+ productRefGroup
+ E4B69B4A0A3A1720003C02F2
+ projectDirPath
+
+ projectReferences
+
+
+ ProductGroup
+ E4328144138ABC890047C5CB
+ ProjectRef
+ E4328143138ABC890047C5CB
+
+
+ projectRoot
+
+ targets
+
+ E4B69B5A0A3A1756003C02F2
+
+
+ E4B69B4D0A3A1720003C02F2
+
+ buildConfigurations
+
+ E4B69B4E0A3A1720003C02F2
+ E4B69B4F0A3A1720003C02F2
+
+ defaultConfigurationIsVisible
+ 0
+ defaultConfigurationName
+ Release
+ isa
+ XCConfigurationList
+
+ E4B69B4E0A3A1720003C02F2
+
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+ buildSettings
+
+ OTHER_LDFLAGS
+
+ $(OF_CORE_FRAMEWORKS) $(OF_CORE_LIBS)
+ ../../../addons/ofxCcv/libs/ccv/lib/osx/ccv.a
+
+ HEADER_SEARCH_PATHS
+
+ $(OF_CORE_HEADERS)
+ src
+ ../../../addons/ofxCcv/libs
+ ../../../addons/ofxCcv/libs/ccv
+ ../../../addons/ofxCcv/libs/ccv/include
+ ../../../addons/ofxCcv/libs/ccv/lib
+ ../../../addons/ofxCcv/libs/ccv/lib/osx
+ ../../../addons/ofxCcv/src
+ ../../../addons/ofxGui/src
+ ../../../addons/ofxTSNE/src
+ ../../../addons/ofxTSNE/src/bhtsne
+
+ CONFIGURATION_BUILD_DIR
+ $(SRCROOT)/bin/
+ COPY_PHASE_STRIP
+ NO
+ DEAD_CODE_STRIPPING
+ YES
+ GCC_AUTO_VECTORIZATION
+ YES
+ GCC_ENABLE_SSE3_EXTENSIONS
+ YES
+ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS
+ YES
+ GCC_INLINES_ARE_PRIVATE_EXTERN
+ NO
+ GCC_OPTIMIZATION_LEVEL
+ 0
+ GCC_SYMBOLS_PRIVATE_EXTERN
+ NO
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS
+ YES
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO
+ NO
+ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL
+ NO
+ GCC_WARN_UNINITIALIZED_AUTOS
+ NO
+ GCC_WARN_UNUSED_VALUE
+ NO
+ GCC_WARN_UNUSED_VARIABLE
+ NO
+ MACOSX_DEPLOYMENT_TARGET
+ 10.8
+ ONLY_ACTIVE_ARCH
+ YES
+ OTHER_CPLUSPLUSFLAGS
+
+ -D__MACOSX_CORE__
+ -mtune=native
+
+ SDKROOT
+ macosx
+
+ isa
+ XCBuildConfiguration
+ name
+ Debug
+
+ E4B69B4F0A3A1720003C02F2
+
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+ buildSettings
+
+ OTHER_LDFLAGS
+
+ $(OF_CORE_FRAMEWORKS) $(OF_CORE_LIBS)
+ ../../../addons/ofxCcv/libs/ccv/lib/osx/ccv.a
+
+ HEADER_SEARCH_PATHS
+
+ $(OF_CORE_HEADERS)
+ src
+ ../../../addons/ofxCcv/libs
+ ../../../addons/ofxCcv/libs/ccv
+ ../../../addons/ofxCcv/libs/ccv/include
+ ../../../addons/ofxCcv/libs/ccv/lib
+ ../../../addons/ofxCcv/libs/ccv/lib/osx
+ ../../../addons/ofxCcv/src
+ ../../../addons/ofxGui/src
+ ../../../addons/ofxTSNE/src
+ ../../../addons/ofxTSNE/src/bhtsne
+
+ CONFIGURATION_BUILD_DIR
+ $(SRCROOT)/bin/
+ COPY_PHASE_STRIP
+ YES
+ DEAD_CODE_STRIPPING
+ YES
+ GCC_AUTO_VECTORIZATION
+ YES
+ GCC_ENABLE_SSE3_EXTENSIONS
+ YES
+ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS
+ YES
+ GCC_INLINES_ARE_PRIVATE_EXTERN
+ NO
+ GCC_OPTIMIZATION_LEVEL
+ 3
+ GCC_SYMBOLS_PRIVATE_EXTERN
+ NO
+ GCC_UNROLL_LOOPS
+ YES
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS
+ YES
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO
+ NO
+ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL
+ NO
+ GCC_WARN_UNINITIALIZED_AUTOS
+ NO
+ GCC_WARN_UNUSED_VALUE
+ NO
+ GCC_WARN_UNUSED_VARIABLE
+ NO
+ MACOSX_DEPLOYMENT_TARGET
+ 10.8
+ OTHER_CPLUSPLUSFLAGS
+
+ -D__MACOSX_CORE__
+ -mtune=native
+
+ SDKROOT
+ macosx
+
+ isa
+ XCBuildConfiguration
+ name
+ Release
+
+ E4B69B580A3A1756003C02F2
+
+ buildActionMask
+ 2147483647
+ files
+
+ E4B69E200A3A1BDC003C02F2
+ E4B69E210A3A1BDC003C02F2
+ 6A5A3AF2E51903FC129D6939
+ 856AA354D08AB4B323081444
+ 5CBB2AB3A60F65431D7B555D
+ B266578FC55D23BFEBC042E7
+ 483908258D00B98B4BE69F07
+ F285EB3169F1566CA3D93C20
+ 837220E80EB56CD44AD27F2A
+ B56FE57CC35806596D38118C
+ 1CD33E884D9E3358252E82A1
+ 3F59654CA5CEEFA57C8D09DC
+ BF438D1989EA8474A24FC372
+ 51A4134BF889D553064DCD2E
+
+ isa
+ PBXSourcesBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ E4B69B590A3A1756003C02F2
+
+ buildActionMask
+ 2147483647
+ files
+
+ E4328149138ABC9F0047C5CB
+
+ isa
+ PBXFrameworksBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ E4B69B5A0A3A1756003C02F2
+
+ buildConfigurationList
+ E4B69B5F0A3A1757003C02F2
+ buildPhases
+
+ E4B69B580A3A1756003C02F2
+ E4B69B590A3A1756003C02F2
+ E4B6FFFD0C3F9AB9008CF71C
+ E4C2427710CC5ABF004149E2
+
+ buildRules
+
+ dependencies
+
+ E4EEB9AC138B136A00A80321
+
+ isa
+ PBXNativeTarget
+ name
+ example-images
+ productName
+ myOFApp
+ productReference
+ E4B69B5B0A3A1756003C02F2
+ productType
+ com.apple.product-type.application
+
+ E4B69B5B0A3A1756003C02F2
+
+ explicitFileType
+ wrapper.application
+ includeInIndex
+ 0
+ isa
+ PBXFileReference
+ path
+ example-imagesDebug.app
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ E4B69B5F0A3A1757003C02F2
+
+ buildConfigurations
+
+ E4B69B600A3A1757003C02F2
+ E4B69B610A3A1757003C02F2
+
+ defaultConfigurationIsVisible
+ 0
+ defaultConfigurationName
+ Release
+ isa
+ XCConfigurationList
+
+ E4B69B600A3A1757003C02F2
+
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+ buildSettings
+
+ OTHER_LDFLAGS
+
+ $(OF_CORE_FRAMEWORKS) $(OF_CORE_LIBS)
+ ../../../addons/ofxCcv/libs/ccv/lib/osx/ccv.a
+
+ HEADER_SEARCH_PATHS
+
+ $(OF_CORE_HEADERS)
+ src
+ ../../../addons/ofxCcv/libs
+ ../../../addons/ofxCcv/libs/ccv
+ ../../../addons/ofxCcv/libs/ccv/include
+ ../../../addons/ofxCcv/libs/ccv/lib
+ ../../../addons/ofxCcv/libs/ccv/lib/osx
+ ../../../addons/ofxCcv/src
+ ../../../addons/ofxGui/src
+ ../../../addons/ofxTSNE/src
+ ../../../addons/ofxTSNE/src/bhtsne
+
+ COMBINE_HIDPI_IMAGES
+ YES
+ COPY_PHASE_STRIP
+ NO
+ FRAMEWORK_SEARCH_PATHS
+
+ $(inherited)
+ $(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)
+
+ FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1
+ "$(SRCROOT)/../../../libs/glut/lib/osx"
+ GCC_DYNAMIC_NO_PIC
+ NO
+ GCC_GENERATE_DEBUGGING_SYMBOLS
+ YES
+ GCC_MODEL_TUNING
+ NONE
+ ICON
+ $(ICON_NAME_DEBUG)
+ ICON_FILE
+ $(ICON_FILE_PATH)$(ICON)
+ INFOPLIST_FILE
+ openFrameworks-Info.plist
+ INSTALL_PATH
+ $(HOME)/Applications
+ LIBRARY_SEARCH_PATHS
+ $(inherited)
+ PRODUCT_NAME
+ $(TARGET_NAME)Debug
+ WRAPPER_EXTENSION
+ app
+
+ isa
+ XCBuildConfiguration
+ name
+ Debug
+
+ E4B69B610A3A1757003C02F2
+
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+ buildSettings
+
+ OTHER_LDFLAGS
+
+ $(OF_CORE_FRAMEWORKS) $(OF_CORE_LIBS)
+ ../../../addons/ofxCcv/libs/ccv/lib/osx/ccv.a
+
+ HEADER_SEARCH_PATHS
+
+ $(OF_CORE_HEADERS)
+ src
+ ../../../addons/ofxCcv/libs
+ ../../../addons/ofxCcv/libs/ccv
+ ../../../addons/ofxCcv/libs/ccv/include
+ ../../../addons/ofxCcv/libs/ccv/lib
+ ../../../addons/ofxCcv/libs/ccv/lib/osx
+ ../../../addons/ofxCcv/src
+ ../../../addons/ofxGui/src
+ ../../../addons/ofxTSNE/src
+ ../../../addons/ofxTSNE/src/bhtsne
+
+ COMBINE_HIDPI_IMAGES
+ YES
+ COPY_PHASE_STRIP
+ YES
+ FRAMEWORK_SEARCH_PATHS
+
+ $(inherited)
+ $(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)
+
+ FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1
+ "$(SRCROOT)/../../../libs/glut/lib/osx"
+ GCC_GENERATE_DEBUGGING_SYMBOLS
+ YES
+ GCC_MODEL_TUNING
+ NONE
+ ICON
+ $(ICON_NAME_RELEASE)
+ ICON_FILE
+ $(ICON_FILE_PATH)$(ICON)
+ INFOPLIST_FILE
+ openFrameworks-Info.plist
+ INSTALL_PATH
+ $(HOME)/Applications
+ LIBRARY_SEARCH_PATHS
+ $(inherited)
+ PRODUCT_NAME
+ $(TARGET_NAME)
+ WRAPPER_EXTENSION
+ app
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+
+ isa
+ XCBuildConfiguration
+ name
+ Release
+
+ E4B69E1C0A3A1BDC003C02F2
+
+ children
+
+ E4B69E1D0A3A1BDC003C02F2
+ E4B69E1E0A3A1BDC003C02F2
+ E4B69E1F0A3A1BDC003C02F2
+
+ isa
+ PBXGroup
+ path
+ src
+ sourceTree
+ SOURCE_ROOT
+
+ E4B69E1D0A3A1BDC003C02F2
+
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ lastKnownFileType
+ sourcecode.cpp.cpp
+ name
+ main.cpp
+ path
+ src/main.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ E4B69E1E0A3A1BDC003C02F2
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofApp.cpp
+ path
+ src/ofApp.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ E4B69E1F0A3A1BDC003C02F2
+
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ lastKnownFileType
+ sourcecode.c.h
+ name
+ ofApp.h
+ path
+ src/ofApp.h
+ sourceTree
+ SOURCE_ROOT
+
+ E4B69E200A3A1BDC003C02F2
+
+ fileRef
+ E4B69E1D0A3A1BDC003C02F2
+ isa
+ PBXBuildFile
+
+ E4B69E210A3A1BDC003C02F2
+
+ fileRef
+ E4B69E1E0A3A1BDC003C02F2
+ isa
+ PBXBuildFile
+
+ E4B6FCAD0C3E899E008CF71C
+
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.xml
+ path
+ openFrameworks-Info.plist
+ sourceTree
+ <group>
+
+ E4B6FFFD0C3F9AB9008CF71C
+
+ buildActionMask
+ 2147483647
+ files
+
+ inputPaths
+
+ isa
+ PBXShellScriptBuildPhase
+ outputPaths
+
+ runOnlyForDeploymentPostprocessing
+ 0
+ shellPath
+ /bin/sh
+ shellScript
+ rsync -aved ../../../libs/fmodex/lib/osx/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/"; install_name_tool -change ./libfmodex.dylib @executable_path/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME";
+mkdir -p "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/"
+rsync -aved "$ICON_FILE" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/"
+rsync -aved ../../../libs/glut/lib/osx/GLUT.framework "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/"
+
+
+ E4C2427710CC5ABF004149E2
+
+ buildActionMask
+ 2147483647
+ dstPath
+
+ dstSubfolderSpec
+ 10
+ files
+
+ isa
+ PBXCopyFilesBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ E4EB691F138AFCF100A09F29
+
+ fileEncoding
+ 4
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ CoreOF.xcconfig
+ path
+ ../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig
+ sourceTree
+ SOURCE_ROOT
+
+ E4EB6923138AFD0F00A09F29
+
+ fileEncoding
+ 4
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ path
+ Project.xcconfig
+ sourceTree
+ <group>
+
+ E4EEB9AB138B136A00A80321
+
+ containerPortal
+ E4328143138ABC890047C5CB
+ isa
+ PBXContainerItemProxy
+ proxyType
+ 1
+ remoteGlobalIDString
+ E4B27C1410CBEB8E00536013
+ remoteInfo
+ openFrameworks
+
+ E4EEB9AC138B136A00A80321
+
+ isa
+ PBXTargetDependency
+ name
+ openFrameworks
+ targetProxy
+ E4EEB9AB138B136A00A80321
+
+ E4EEC9E9138DF44700A80321
+
+ children
+
+ E4EB691F138AFCF100A09F29
+ E4328143138ABC890047C5CB
+
+ isa
+ PBXGroup
+ name
+ openFrameworks
+ sourceTree
+ <group>
+
+
+ rootObject
+ E4B69B4C0A3A1720003C02F2
+
+
diff --git a/example-images/example-images.xcodeproj/project.xcworkspace/xcuserdata/gene.xcuserdatad/UserInterfaceState.xcuserstate b/example-images/example-images.xcodeproj/project.xcworkspace/xcuserdata/gene.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..b50d009
Binary files /dev/null and b/example-images/example-images.xcodeproj/project.xcworkspace/xcuserdata/gene.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/example-images/example-images.xcodeproj/xcshareddata/xcschemes/example-images Debug.xcscheme b/example-images/example-images.xcodeproj/xcshareddata/xcschemes/example-images Debug.xcscheme
new file mode 100644
index 0000000..1ea6620
--- /dev/null
+++ b/example-images/example-images.xcodeproj/xcshareddata/xcschemes/example-images Debug.xcscheme
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example-images/example-images.xcodeproj/xcshareddata/xcschemes/example-images Release.xcscheme b/example-images/example-images.xcodeproj/xcshareddata/xcschemes/example-images Release.xcscheme
new file mode 100644
index 0000000..0bdfdc1
--- /dev/null
+++ b/example-images/example-images.xcodeproj/xcshareddata/xcschemes/example-images Release.xcscheme
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example-images/example-images.xcodeproj/xcuserdata/gene.xcuserdatad/xcschemes/xcschememanagement.plist b/example-images/example-images.xcodeproj/xcuserdata/gene.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..13dfb6e
--- /dev/null
+++ b/example-images/example-images.xcodeproj/xcuserdata/gene.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+
+
+
+
+ SuppressBuildableAutocreation
+
+ E4B69B5A0A3A1756003C02F2
+
+ primary
+
+
+
+
+
diff --git a/example-images/openFrameworks-Info.plist b/example-images/openFrameworks-Info.plist
new file mode 100644
index 0000000..8d64d2b
--- /dev/null
+++ b/example-images/openFrameworks-Info.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIdentifier
+ cc.openFrameworks.ofapp
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ CFBundleIconFile
+ ${ICON}
+
+
diff --git a/example-images/src/main.cpp b/example-images/src/main.cpp
new file mode 100644
index 0000000..e57370b
--- /dev/null
+++ b/example-images/src/main.cpp
@@ -0,0 +1,13 @@
+#include "ofMain.h"
+#include "ofApp.h"
+
+//========================================================================
+int main( ){
+ ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context
+
+ // this kicks off the running of my app
+ // can be OF_WINDOW or OF_FULLSCREEN
+ // pass in width and height too:
+ ofRunApp(new ofApp());
+
+}
diff --git a/example-images/src/ofApp.cpp b/example-images/src/ofApp.cpp
new file mode 100644
index 0000000..2e21baa
--- /dev/null
+++ b/example-images/src/ofApp.cpp
@@ -0,0 +1,131 @@
+#include "ofApp.h"
+
+//--------------------------------------------------------------
+void ofApp::setup(){
+
+ // load all the images
+ ofLog() << "Gathering images...";
+ ofDirectory dir;
+ int nFiles = dir.listDir(ofToDataPath("images/"));
+ if(nFiles) {
+ for(int i=0; i
encoding = ccv.encode(images[i], ccv.numLayers()-1);
+ encodings.push_back(encoding);
+ }
+
+ // run t-SNE and load image points to imagePoints
+ ofLog() << "Run t-SNE on images";
+ imagePoints = tsne.run(encodings, 2, 25, 0.1, true);
+
+ // make the images the same size
+ for (int i=0; i images;
+ vector > imagePoints;
+ vector > encodings;
+
+ ofxPanel gui;
+ ofParameter scale;
+ ofParameter imageSize;
+};
diff --git a/example/Makefile b/example/Makefile
new file mode 100644
index 0000000..8d8e4c0
--- /dev/null
+++ b/example/Makefile
@@ -0,0 +1,13 @@
+# Attempt to load a config.make file.
+# If none is found, project defaults in config.project.make will be used.
+ifneq ($(wildcard config.make),)
+ include config.make
+endif
+
+# make sure the the OF_ROOT location is defined
+ifndef OF_ROOT
+ OF_ROOT=$(realpath ../../..)
+endif
+
+# call the project makefile!
+include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk
diff --git a/example/Project.xcconfig b/example/Project.xcconfig
new file mode 100644
index 0000000..e570b15
--- /dev/null
+++ b/example/Project.xcconfig
@@ -0,0 +1,17 @@
+//THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT.
+//THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED
+OF_PATH = ../../..
+
+//THIS HAS ALL THE HEADER AND LIBS FOR OF CORE
+#include "../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig"
+
+//ICONS - NEW IN 0072
+ICON_NAME_DEBUG = icon-debug.icns
+ICON_NAME_RELEASE = icon.icns
+ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/
+
+//IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to:
+//ICON_FILE_PATH = bin/data/
+
+OTHER_LDFLAGS = $(OF_CORE_LIBS) $(OF_CORE_FRAMEWORKS)
+HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS)
diff --git a/example/addons.make b/example/addons.make
new file mode 100644
index 0000000..aaf6171
--- /dev/null
+++ b/example/addons.make
@@ -0,0 +1 @@
+ofxTSNE
diff --git a/example/config.make b/example/config.make
new file mode 100644
index 0000000..df10f64
--- /dev/null
+++ b/example/config.make
@@ -0,0 +1,142 @@
+################################################################################
+# CONFIGURE PROJECT MAKEFILE (optional)
+# This file is where we make project specific configurations.
+################################################################################
+
+################################################################################
+# OF ROOT
+# The location of your root openFrameworks installation
+# (default) OF_ROOT = ../../..
+################################################################################
+# OF_ROOT = ../../..
+
+################################################################################
+# PROJECT ROOT
+# The location of the project - a starting place for searching for files
+# (default) PROJECT_ROOT = . (this directory)
+#
+################################################################################
+# PROJECT_ROOT = .
+
+################################################################################
+# PROJECT SPECIFIC CHECKS
+# This is a project defined section to create internal makefile flags to
+# conditionally enable or disable the addition of various features within
+# this makefile. For instance, if you want to make changes based on whether
+# GTK is installed, one might test that here and create a variable to check.
+################################################################################
+# None
+
+################################################################################
+# PROJECT EXTERNAL SOURCE PATHS
+# These are fully qualified paths that are not within the PROJECT_ROOT folder.
+# Like source folders in the PROJECT_ROOT, these paths are subject to
+# exlclusion via the PROJECT_EXLCUSIONS list.
+#
+# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXTERNAL_SOURCE_PATHS =
+
+################################################################################
+# PROJECT EXCLUSIONS
+# These makefiles assume that all folders in your current project directory
+# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
+# to look for source code. The any folders or files that match any of the
+# items in the PROJECT_EXCLUSIONS list below will be ignored.
+#
+# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
+# string unless teh user adds a wildcard (%) operator to match subdirectories.
+# GNU make only allows one wildcard for matching. The second wildcard (%) is
+# treated literally.
+#
+# (default) PROJECT_EXCLUSIONS = (blank)
+#
+# Will automatically exclude the following:
+#
+# $(PROJECT_ROOT)/bin%
+# $(PROJECT_ROOT)/obj%
+# $(PROJECT_ROOT)/%.xcodeproj
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXCLUSIONS =
+
+################################################################################
+# PROJECT LINKER FLAGS
+# These flags will be sent to the linker when compiling the executable.
+#
+# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+
+# Currently, shared libraries that are needed are copied to the
+# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
+# add a runtime path to search for those shared libraries, since they aren't
+# incorporated directly into the final executable application binary.
+# TODO: should this be a default setting?
+# PROJECT_LDFLAGS=-Wl,-rpath=./libs
+
+################################################################################
+# PROJECT DEFINES
+# Create a space-delimited list of DEFINES. The list will be converted into
+# CFLAGS with the "-D" flag later in the makefile.
+#
+# (default) PROJECT_DEFINES = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_DEFINES =
+
+################################################################################
+# PROJECT CFLAGS
+# This is a list of fully qualified CFLAGS required when compiling for this
+# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
+# defined in your platform specific core configuration files. These flags are
+# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
+#
+# (default) PROJECT_CFLAGS = (blank)
+#
+# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
+# your platform specific configuration file will be applied by default and
+# further flags here may not be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CFLAGS =
+
+################################################################################
+# PROJECT OPTIMIZATION CFLAGS
+# These are lists of CFLAGS that are target-specific. While any flags could
+# be conditionally added, they are usually limited to optimization flags.
+# These flags are added BEFORE the PROJECT_CFLAGS.
+#
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
+#
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
+#
+# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
+# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
+# file will be applied by default and further optimization flags here may not
+# be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
+
+################################################################################
+# PROJECT COMPILERS
+# Custom compilers can be set for CC and CXX
+# (default) PROJECT_CXX = (blank)
+# (default) PROJECT_CC = (blank)
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CXX =
+# PROJECT_CC =
diff --git a/example/example.xcodeproj/project.pbxproj b/example/example.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..b600b7c
--- /dev/null
+++ b/example/example.xcodeproj/project.pbxproj
@@ -0,0 +1,837 @@
+
+
+
+ archiveVersion
+ 1
+ classes
+
+ objectVersion
+ 46
+ objects
+
+ A18A04F43F1A3D8641B0D261
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxTSNE.h
+ path
+ ../../../addons/ofxTSNE/src/ofxTSNE.h
+ sourceTree
+ SOURCE_ROOT
+
+ 51A4134BF889D553064DCD2E
+
+ fileRef
+ D985BBD882BD1582C610B30C
+ isa
+ PBXBuildFile
+
+ D985BBD882BD1582C610B30C
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofxTSNE.cpp
+ path
+ ../../../addons/ofxTSNE/src/ofxTSNE.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ 1F7816F26F468BAC49B9ADD0
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ vptree.h
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/vptree.h
+ sourceTree
+ SOURCE_ROOT
+
+ 54DCDCE01CF02EC24329509D
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ tsne.h
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/tsne.h
+ sourceTree
+ SOURCE_ROOT
+
+ BF438D1989EA8474A24FC372
+
+ fileRef
+ C5EC22EBF07D1C6136CAFF40
+ isa
+ PBXBuildFile
+
+ C5EC22EBF07D1C6136CAFF40
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ tsne.cpp
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/tsne.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ D361105E69E9248C8CDD4024
+
+ explicitFileType
+ sourcecode.c.h
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ sptree.h
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/sptree.h
+ sourceTree
+ SOURCE_ROOT
+
+ C289F16CCC88C08ABEBC3CE6
+
+ children
+
+ 29CFCFEEAF44F7849B7A8E2C
+ D361105E69E9248C8CDD4024
+ C5EC22EBF07D1C6136CAFF40
+ 54DCDCE01CF02EC24329509D
+ 1F7816F26F468BAC49B9ADD0
+
+ isa
+ PBXGroup
+ name
+ bhtsne
+ sourceTree
+ <group>
+
+ 84110FEC26026E23FCEDE55A
+
+ children
+
+ C289F16CCC88C08ABEBC3CE6
+ D985BBD882BD1582C610B30C
+ A18A04F43F1A3D8641B0D261
+
+ isa
+ PBXGroup
+ name
+ src
+ sourceTree
+ <group>
+
+ A2C3A140678F172C21702046
+
+ children
+
+ 84110FEC26026E23FCEDE55A
+
+ isa
+ PBXGroup
+ name
+ ofxTSNE
+ sourceTree
+ <group>
+
+ 3F59654CA5CEEFA57C8D09DC
+
+ fileRef
+ 29CFCFEEAF44F7849B7A8E2C
+ isa
+ PBXBuildFile
+
+ 29CFCFEEAF44F7849B7A8E2C
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ sptree.cpp
+ path
+ ../../../addons/ofxTSNE/src/bhtsne/sptree.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ BB4B014C10F69532006C3DED
+
+ children
+
+ A2C3A140678F172C21702046
+
+ isa
+ PBXGroup
+ name
+ addons
+ sourceTree
+ <group>
+
+ 6948EE371B920CB800B5AC1A
+
+ children
+
+ isa
+ PBXGroup
+ name
+ local_addons
+ sourceTree
+ <group>
+
+ E4328143138ABC890047C5CB
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ wrapper.pb-project
+ name
+ openFrameworksLib.xcodeproj
+ path
+ ../../../libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj
+ sourceTree
+ SOURCE_ROOT
+
+ E4328144138ABC890047C5CB
+
+ children
+
+ E4328148138ABC890047C5CB
+
+ isa
+ PBXGroup
+ name
+ Products
+ sourceTree
+ <group>
+
+ E4328147138ABC890047C5CB
+
+ containerPortal
+ E4328143138ABC890047C5CB
+ isa
+ PBXContainerItemProxy
+ proxyType
+ 2
+ remoteGlobalIDString
+ E4B27C1510CBEB8E00536013
+ remoteInfo
+ openFrameworks
+
+ E4328148138ABC890047C5CB
+
+ fileType
+ archive.ar
+ isa
+ PBXReferenceProxy
+ path
+ openFrameworksDebug.a
+ remoteRef
+ E4328147138ABC890047C5CB
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ E4328149138ABC9F0047C5CB
+
+ fileRef
+ E4328148138ABC890047C5CB
+ isa
+ PBXBuildFile
+
+ E4B69B4A0A3A1720003C02F2
+
+ children
+
+ E4B6FCAD0C3E899E008CF71C
+ E4EB6923138AFD0F00A09F29
+ E4B69E1C0A3A1BDC003C02F2
+ E4EEC9E9138DF44700A80321
+ BB4B014C10F69532006C3DED
+ 6948EE371B920CB800B5AC1A
+ E4B69B5B0A3A1756003C02F2
+
+ isa
+ PBXGroup
+ sourceTree
+ <group>
+
+ E4B69B4C0A3A1720003C02F2
+
+ attributes
+
+ LastUpgradeCheck
+ 0600
+
+ buildConfigurationList
+ E4B69B4D0A3A1720003C02F2
+ compatibilityVersion
+ Xcode 3.2
+ developmentRegion
+ English
+ hasScannedForEncodings
+ 0
+ isa
+ PBXProject
+ knownRegions
+
+ English
+ Japanese
+ French
+ German
+
+ mainGroup
+ E4B69B4A0A3A1720003C02F2
+ productRefGroup
+ E4B69B4A0A3A1720003C02F2
+ projectDirPath
+
+ projectReferences
+
+
+ ProductGroup
+ E4328144138ABC890047C5CB
+ ProjectRef
+ E4328143138ABC890047C5CB
+
+
+ projectRoot
+
+ targets
+
+ E4B69B5A0A3A1756003C02F2
+
+
+ E4B69B4D0A3A1720003C02F2
+
+ buildConfigurations
+
+ E4B69B4E0A3A1720003C02F2
+ E4B69B4F0A3A1720003C02F2
+
+ defaultConfigurationIsVisible
+ 0
+ defaultConfigurationName
+ Release
+ isa
+ XCConfigurationList
+
+ E4B69B4E0A3A1720003C02F2
+
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+ buildSettings
+
+ HEADER_SEARCH_PATHS
+
+ $(OF_CORE_HEADERS)
+ ../../../addons/ofxTSNE/src
+ ../../../addons/ofxTSNE/src/bhtsne
+
+ CONFIGURATION_BUILD_DIR
+ $(SRCROOT)/bin/
+ COPY_PHASE_STRIP
+ NO
+ DEAD_CODE_STRIPPING
+ YES
+ GCC_AUTO_VECTORIZATION
+ YES
+ GCC_ENABLE_SSE3_EXTENSIONS
+ YES
+ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS
+ YES
+ GCC_INLINES_ARE_PRIVATE_EXTERN
+ NO
+ GCC_OPTIMIZATION_LEVEL
+ 0
+ GCC_SYMBOLS_PRIVATE_EXTERN
+ NO
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS
+ YES
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO
+ NO
+ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL
+ NO
+ GCC_WARN_UNINITIALIZED_AUTOS
+ NO
+ GCC_WARN_UNUSED_VALUE
+ NO
+ GCC_WARN_UNUSED_VARIABLE
+ NO
+ MACOSX_DEPLOYMENT_TARGET
+ 10.8
+ ONLY_ACTIVE_ARCH
+ YES
+ OTHER_CPLUSPLUSFLAGS
+
+ -D__MACOSX_CORE__
+ -mtune=native
+
+ SDKROOT
+ macosx
+
+ isa
+ XCBuildConfiguration
+ name
+ Debug
+
+ E4B69B4F0A3A1720003C02F2
+
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+ buildSettings
+
+ HEADER_SEARCH_PATHS
+
+ $(OF_CORE_HEADERS)
+ ../../../addons/ofxTSNE/src
+ ../../../addons/ofxTSNE/src/bhtsne
+
+ CONFIGURATION_BUILD_DIR
+ $(SRCROOT)/bin/
+ COPY_PHASE_STRIP
+ YES
+ DEAD_CODE_STRIPPING
+ YES
+ GCC_AUTO_VECTORIZATION
+ YES
+ GCC_ENABLE_SSE3_EXTENSIONS
+ YES
+ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS
+ YES
+ GCC_INLINES_ARE_PRIVATE_EXTERN
+ NO
+ GCC_OPTIMIZATION_LEVEL
+ 3
+ GCC_SYMBOLS_PRIVATE_EXTERN
+ NO
+ GCC_UNROLL_LOOPS
+ YES
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS
+ YES
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO
+ NO
+ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL
+ NO
+ GCC_WARN_UNINITIALIZED_AUTOS
+ NO
+ GCC_WARN_UNUSED_VALUE
+ NO
+ GCC_WARN_UNUSED_VARIABLE
+ NO
+ MACOSX_DEPLOYMENT_TARGET
+ 10.8
+ OTHER_CPLUSPLUSFLAGS
+
+ -D__MACOSX_CORE__
+ -mtune=native
+
+ SDKROOT
+ macosx
+
+ isa
+ XCBuildConfiguration
+ name
+ Release
+
+ E4B69B580A3A1756003C02F2
+
+ buildActionMask
+ 2147483647
+ files
+
+ E4B69E200A3A1BDC003C02F2
+ E4B69E210A3A1BDC003C02F2
+ 3F59654CA5CEEFA57C8D09DC
+ BF438D1989EA8474A24FC372
+ 51A4134BF889D553064DCD2E
+
+ isa
+ PBXSourcesBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ E4B69B590A3A1756003C02F2
+
+ buildActionMask
+ 2147483647
+ files
+
+ E4328149138ABC9F0047C5CB
+
+ isa
+ PBXFrameworksBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ E4B69B5A0A3A1756003C02F2
+
+ buildConfigurationList
+ E4B69B5F0A3A1757003C02F2
+ buildPhases
+
+ E4B69B580A3A1756003C02F2
+ E4B69B590A3A1756003C02F2
+ E4B6FFFD0C3F9AB9008CF71C
+ E4C2427710CC5ABF004149E2
+
+ buildRules
+
+ dependencies
+
+ E4EEB9AC138B136A00A80321
+
+ isa
+ PBXNativeTarget
+ name
+ example
+ productName
+ myOFApp
+ productReference
+ E4B69B5B0A3A1756003C02F2
+ productType
+ com.apple.product-type.application
+
+ E4B69B5B0A3A1756003C02F2
+
+ explicitFileType
+ wrapper.application
+ includeInIndex
+ 0
+ isa
+ PBXFileReference
+ path
+ exampleDebug.app
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ E4B69B5F0A3A1757003C02F2
+
+ buildConfigurations
+
+ E4B69B600A3A1757003C02F2
+ E4B69B610A3A1757003C02F2
+
+ defaultConfigurationIsVisible
+ 0
+ defaultConfigurationName
+ Release
+ isa
+ XCConfigurationList
+
+ E4B69B600A3A1757003C02F2
+
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+ buildSettings
+
+ HEADER_SEARCH_PATHS
+
+ $(OF_CORE_HEADERS)
+ ../../../addons/ofxTSNE/src
+ ../../../addons/ofxTSNE/src/bhtsne
+
+ COMBINE_HIDPI_IMAGES
+ YES
+ COPY_PHASE_STRIP
+ NO
+ FRAMEWORK_SEARCH_PATHS
+
+ $(inherited)
+ $(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)
+
+ FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1
+ "$(SRCROOT)/../../../libs/glut/lib/osx"
+ GCC_DYNAMIC_NO_PIC
+ NO
+ GCC_GENERATE_DEBUGGING_SYMBOLS
+ YES
+ GCC_MODEL_TUNING
+ NONE
+ ICON
+ $(ICON_NAME_DEBUG)
+ ICON_FILE
+ $(ICON_FILE_PATH)$(ICON)
+ INFOPLIST_FILE
+ openFrameworks-Info.plist
+ INSTALL_PATH
+ $(HOME)/Applications
+ LIBRARY_SEARCH_PATHS
+ $(inherited)
+ PRODUCT_NAME
+ $(TARGET_NAME)Debug
+ WRAPPER_EXTENSION
+ app
+
+ isa
+ XCBuildConfiguration
+ name
+ Debug
+
+ E4B69B610A3A1757003C02F2
+
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+ buildSettings
+
+ HEADER_SEARCH_PATHS
+
+ $(OF_CORE_HEADERS)
+ ../../../addons/ofxTSNE/src
+ ../../../addons/ofxTSNE/src/bhtsne
+
+ COMBINE_HIDPI_IMAGES
+ YES
+ COPY_PHASE_STRIP
+ YES
+ FRAMEWORK_SEARCH_PATHS
+
+ $(inherited)
+ $(FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1)
+
+ FRAMEWORK_SEARCH_PATHS_QUOTED_FOR_TARGET_1
+ "$(SRCROOT)/../../../libs/glut/lib/osx"
+ GCC_GENERATE_DEBUGGING_SYMBOLS
+ YES
+ GCC_MODEL_TUNING
+ NONE
+ ICON
+ $(ICON_NAME_RELEASE)
+ ICON_FILE
+ $(ICON_FILE_PATH)$(ICON)
+ INFOPLIST_FILE
+ openFrameworks-Info.plist
+ INSTALL_PATH
+ $(HOME)/Applications
+ LIBRARY_SEARCH_PATHS
+ $(inherited)
+ PRODUCT_NAME
+ $(TARGET_NAME)
+ WRAPPER_EXTENSION
+ app
+ baseConfigurationReference
+ E4EB6923138AFD0F00A09F29
+
+ isa
+ XCBuildConfiguration
+ name
+ Release
+
+ E4B69E1C0A3A1BDC003C02F2
+
+ children
+
+ E4B69E1D0A3A1BDC003C02F2
+ E4B69E1E0A3A1BDC003C02F2
+ E4B69E1F0A3A1BDC003C02F2
+
+ isa
+ PBXGroup
+ path
+ src
+ sourceTree
+ SOURCE_ROOT
+
+ E4B69E1D0A3A1BDC003C02F2
+
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ lastKnownFileType
+ sourcecode.cpp.cpp
+ name
+ main.cpp
+ path
+ src/main.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ E4B69E1E0A3A1BDC003C02F2
+
+ explicitFileType
+ sourcecode.cpp.cpp
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ name
+ ofApp.cpp
+ path
+ src/ofApp.cpp
+ sourceTree
+ SOURCE_ROOT
+
+ E4B69E1F0A3A1BDC003C02F2
+
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ lastKnownFileType
+ sourcecode.c.h
+ name
+ ofApp.h
+ path
+ src/ofApp.h
+ sourceTree
+ SOURCE_ROOT
+
+ E4B69E200A3A1BDC003C02F2
+
+ fileRef
+ E4B69E1D0A3A1BDC003C02F2
+ isa
+ PBXBuildFile
+
+ E4B69E210A3A1BDC003C02F2
+
+ fileRef
+ E4B69E1E0A3A1BDC003C02F2
+ isa
+ PBXBuildFile
+
+ E4B6FCAD0C3E899E008CF71C
+
+ fileEncoding
+ 30
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.xml
+ path
+ openFrameworks-Info.plist
+ sourceTree
+ <group>
+
+ E4B6FFFD0C3F9AB9008CF71C
+
+ buildActionMask
+ 2147483647
+ files
+
+ inputPaths
+
+ isa
+ PBXShellScriptBuildPhase
+ outputPaths
+
+ runOnlyForDeploymentPostprocessing
+ 0
+ shellPath
+ /bin/sh
+ shellScript
+ rsync -aved ../../../libs/fmodex/lib/osx/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/"; install_name_tool -change ./libfmodex.dylib @executable_path/libfmodex.dylib "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME";
+mkdir -p "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/"
+rsync -aved "$ICON_FILE" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/"
+rsync -aved ../../../libs/glut/lib/osx/GLUT.framework "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/"
+
+
+ E4C2427710CC5ABF004149E2
+
+ buildActionMask
+ 2147483647
+ dstPath
+
+ dstSubfolderSpec
+ 10
+ files
+
+ isa
+ PBXCopyFilesBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ E4EB691F138AFCF100A09F29
+
+ fileEncoding
+ 4
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ CoreOF.xcconfig
+ path
+ ../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig
+ sourceTree
+ SOURCE_ROOT
+
+ E4EB6923138AFD0F00A09F29
+
+ fileEncoding
+ 4
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ path
+ Project.xcconfig
+ sourceTree
+ <group>
+
+ E4EEB9AB138B136A00A80321
+
+ containerPortal
+ E4328143138ABC890047C5CB
+ isa
+ PBXContainerItemProxy
+ proxyType
+ 1
+ remoteGlobalIDString
+ E4B27C1410CBEB8E00536013
+ remoteInfo
+ openFrameworks
+
+ E4EEB9AC138B136A00A80321
+
+ isa
+ PBXTargetDependency
+ name
+ openFrameworks
+ targetProxy
+ E4EEB9AB138B136A00A80321
+
+ E4EEC9E9138DF44700A80321
+
+ children
+
+ E4EB691F138AFCF100A09F29
+ E4328143138ABC890047C5CB
+
+ isa
+ PBXGroup
+ name
+ openFrameworks
+ sourceTree
+ <group>
+
+
+ rootObject
+ E4B69B4C0A3A1720003C02F2
+
+
diff --git a/example/example.xcodeproj/project.xcworkspace/xcuserdata/gene.xcuserdatad/UserInterfaceState.xcuserstate b/example/example.xcodeproj/project.xcworkspace/xcuserdata/gene.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..bf6081a
Binary files /dev/null and b/example/example.xcodeproj/project.xcworkspace/xcuserdata/gene.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/example/example.xcodeproj/xcshareddata/xcschemes/example Debug.xcscheme b/example/example.xcodeproj/xcshareddata/xcschemes/example Debug.xcscheme
new file mode 100644
index 0000000..a637354
--- /dev/null
+++ b/example/example.xcodeproj/xcshareddata/xcschemes/example Debug.xcscheme
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/example.xcodeproj/xcshareddata/xcschemes/example Release.xcscheme b/example/example.xcodeproj/xcshareddata/xcschemes/example Release.xcscheme
new file mode 100644
index 0000000..1b9ed60
--- /dev/null
+++ b/example/example.xcodeproj/xcshareddata/xcschemes/example Release.xcscheme
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/example.xcodeproj/xcuserdata/gene.xcuserdatad/xcschemes/xcschememanagement.plist b/example/example.xcodeproj/xcuserdata/gene.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..13dfb6e
--- /dev/null
+++ b/example/example.xcodeproj/xcuserdata/gene.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+
+
+
+
+ SuppressBuildableAutocreation
+
+ E4B69B5A0A3A1756003C02F2
+
+ primary
+
+
+
+
+
diff --git a/example/openFrameworks-Info.plist b/example/openFrameworks-Info.plist
new file mode 100644
index 0000000..8d64d2b
--- /dev/null
+++ b/example/openFrameworks-Info.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIdentifier
+ cc.openFrameworks.ofapp
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ CFBundleIconFile
+ ${ICON}
+
+
diff --git a/example/src/main.cpp b/example/src/main.cpp
new file mode 100644
index 0000000..e57370b
--- /dev/null
+++ b/example/src/main.cpp
@@ -0,0 +1,13 @@
+#include "ofMain.h"
+#include "ofApp.h"
+
+//========================================================================
+int main( ){
+ ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context
+
+ // this kicks off the running of my app
+ // can be OF_WINDOW or OF_FULLSCREEN
+ // pass in width and height too:
+ ofRunApp(new ofApp());
+
+}
diff --git a/example/src/ofApp.cpp b/example/src/ofApp.cpp
new file mode 100644
index 0000000..17a0546
--- /dev/null
+++ b/example/src/ofApp.cpp
@@ -0,0 +1,191 @@
+#include "ofApp.h"
+
+//--------------------------------------------------------------
+void ofApp::setup(){
+
+ // first let's construct our toy dataset.
+ // we will create N samples of dimension D, which will be distributed
+ // into a number of classes, where a point belonging to a particular
+ // class will be located close to the center point for that class.
+ // Note: TSNE doesn't operate on classes/labels and you don't need to
+ // use them. we are creating the dataset with color-coded classes
+ // so we can see TSNE's ability to retain clusters of points when
+ // transforming them from high-dimensional to low-dimensional space, so
+ // in this example, the classes are just for us to see this clearer.
+
+ // pick initial parameters
+ int N = 2000; // number of points in our dataset
+ int D = 100; // number of dimensions in our data
+ int numClasses = 10; // how many classes to create
+
+
+ // first let's make our classes
+
+ vector classColors = vector{ofColor::red, ofColor::green,
+ ofColor::blue, ofColor::cyan, ofColor::magenta, ofColor::black,
+ ofColor::yellow, ofColor::violet, ofColor::pink, ofColor::gray};
+ vector > classCenters;
+ classCenters.resize(numClasses);
+
+ for (int i = 0; i < numClasses; i++) {
+ // pick a random center point for this class
+ vector classCenter;
+ classCenter.resize(D);
+ for (int j=0; j point;
+ point.resize(D);
+
+ // the TestPoint will be located with some (fairly large) random
+ // deviation from the center point of its class
+ for (int j=0; j > where the inner vector corresponds
+ // to a single data point. So let's unpack our testPoints into this.
+
+ vector > data;
+ for (int i = 0; i < N; i++) {
+ data.push_back(testPoints[i].point);
+ }
+
+ // ofxTSNE takes four parameters:
+ //
+ // dims = number of dimensions to embed our points into. we will
+ // use 2 points to visualize along (x, y), although t-SNE is commonly
+ // used for 3d as well. since t-SNE is best known for visualization,
+ // it's most commonly run with 2 or 3 dims, but more can be used.
+ // perplexity = a measure of the dataset's Shannon entropy, this can be
+ // loosely interpreted as how uncertain the data is / how difficult it is
+ // to be modeled by a probability distribution. generally speaking, larger
+ // datasets need a higher perplexity, but if your points end up looking
+ // like a poorly-arranged uniformly-distributed ball, your perplexity is
+ // too high. this value is usually set between 5 and 50 with 30 being
+ // a good default. t-SNE is fairly insensitive to this parameter so
+ // in most cases the default should work fine.
+ // theta / angle = this parameter controls the accuracy/speed tradeoff
+ // of the Barnes-Hut simulation used to solve the t-SNE embedding. low
+ // theta is more accurate but slower, and high theta is faster but
+ // maybe less optimal solution. it should be between 0 and 1. in practice
+ // you can usually get away with higher theta (say 0.5) without sacrificing
+ // noticeable accuracy.
+ // normalize = this will automatically remap all tsne points to range {0, 1}
+ // if false, you'll get the original points.
+
+
+ int dims = 2;
+ float perplexity = 30;
+ float theta = 0.5;
+ bool normalize = true;
+
+ // finally let's run ofxTSNE! this may take a while depending on your
+ // data, and it will return a set of embedded points, structured as
+ // a vector > where the inner vector contains (dims) elements.
+ // We will unpack these points and assign them back to our testPoints dataset.
+
+ vector > tsnePoints = tsne.run(data, dims, perplexity, theta, normalize);
+
+ // unpack the embedded points back into our testPoints
+ for (int i=0; i point;
+ ofPoint tsnePoint;
+ };
+
+ ofxTSNE tsne;
+ vector testPoints;
+};
diff --git a/ofxaddons_thumbnail.png b/ofxaddons_thumbnail.png
new file mode 100644
index 0000000..be3d0cc
Binary files /dev/null and b/ofxaddons_thumbnail.png differ
diff --git a/setup_ccv.sh b/setup_ccv.sh
new file mode 100755
index 0000000..ee591fd
--- /dev/null
+++ b/setup_ccv.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+DIR=example-images/bin/data
+DB_URL="https://raw.githubusercontent.com/liuliu/ccv/unstable/samples/image-net-2012.sqlite3"
+DB_FILE="$DIR/image-net-2012.sqlite3"
+WORDS_URL="https://raw.githubusercontent.com/liuliu/ccv/unstable/samples/image-net-2012.words"
+WORDS_FILE="$DIR/image-net-2012.words"
+mkdir -p $DIR
+if [ ! -e $DB_FILE ] ; then
+ echo "Downloading image-net-2012 network (ccv)"
+ curl -o $DB_FILE $DB_URL
+ curl -o $WORDS_FILE $WORDS_URL
+fi
+echo "Downloaded: image-net-2012 network (ccv)"
diff --git a/src/bhtsne/sptree.cpp b/src/bhtsne/sptree.cpp
new file mode 100755
index 0000000..10aa4ef
--- /dev/null
+++ b/src/bhtsne/sptree.cpp
@@ -0,0 +1,428 @@
+/*
+ *
+ * Copyright (c) 2014, Laurens van der Maaten (Delft University of Technology)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Delft University of Technology.
+ * 4. Neither the name of the Delft University of Technology nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY LAURENS VAN DER MAATEN ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL LAURENS VAN DER MAATEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include "sptree.h"
+
+
+
+// Constructs cell
+Cell::Cell(unsigned int inp_dimension) {
+ dimension = inp_dimension;
+ corner = (double*) malloc(dimension * sizeof(double));
+ width = (double*) malloc(dimension * sizeof(double));
+}
+
+Cell::Cell(unsigned int inp_dimension, double* inp_corner, double* inp_width) {
+ dimension = inp_dimension;
+ corner = (double*) malloc(dimension * sizeof(double));
+ width = (double*) malloc(dimension * sizeof(double));
+ for(int d = 0; d < dimension; d++) setCorner(d, inp_corner[d]);
+ for(int d = 0; d < dimension; d++) setWidth( d, inp_width[d]);
+}
+
+// Destructs cell
+Cell::~Cell() {
+ free(corner);
+ free(width);
+}
+
+double Cell::getCorner(unsigned int d) {
+ return corner[d];
+}
+
+double Cell::getWidth(unsigned int d) {
+ return width[d];
+}
+
+void Cell::setCorner(unsigned int d, double val) {
+ corner[d] = val;
+}
+
+void Cell::setWidth(unsigned int d, double val) {
+ width[d] = val;
+}
+
+// Checks whether a point lies in a cell
+bool Cell::containsPoint(double point[])
+{
+ for(int d = 0; d < dimension; d++) {
+ if(corner[d] - width[d] > point[d]) return false;
+ if(corner[d] + width[d] < point[d]) return false;
+ }
+ return true;
+}
+
+
+// Default constructor for SPTree -- build tree, too!
+SPTree::SPTree(unsigned int D, double* inp_data, unsigned int N)
+{
+
+ // Compute mean, width, and height of current map (boundaries of SPTree)
+ int nD = 0;
+ double* mean_Y = (double*) calloc(D, sizeof(double));
+ double* min_Y = (double*) malloc(D * sizeof(double)); for(unsigned int d = 0; d < D; d++) min_Y[d] = DBL_MAX;
+ double* max_Y = (double*) malloc(D * sizeof(double)); for(unsigned int d = 0; d < D; d++) max_Y[d] = -DBL_MAX;
+ for(unsigned int n = 0; n < N; n++) {
+ for(unsigned int d = 0; d < D; d++) {
+ mean_Y[d] += inp_data[n * D + d];
+ if(inp_data[nD + d] < min_Y[d]) min_Y[d] = inp_data[nD + d];
+ if(inp_data[nD + d] > max_Y[d]) max_Y[d] = inp_data[nD + d];
+ }
+ nD += D;
+ }
+ for(int d = 0; d < D; d++) mean_Y[d] /= (double) N;
+
+ // Construct SPTree
+ double* width = (double*) malloc(D * sizeof(double));
+ for(int d = 0; d < D; d++) width[d] = fmax(max_Y[d] - mean_Y[d], mean_Y[d] - min_Y[d]) + 1e-5;
+ init(NULL, D, inp_data, mean_Y, width);
+ fill(N);
+
+ // Clean up memory
+ free(mean_Y);
+ free(max_Y);
+ free(min_Y);
+ free(width);
+}
+
+
+// Constructor for SPTree with particular size and parent -- build the tree, too!
+SPTree::SPTree(unsigned int D, double* inp_data, unsigned int N, double* inp_corner, double* inp_width)
+{
+ init(NULL, D, inp_data, inp_corner, inp_width);
+ fill(N);
+}
+
+
+// Constructor for SPTree with particular size (do not fill the tree)
+SPTree::SPTree(unsigned int D, double* inp_data, double* inp_corner, double* inp_width)
+{
+ init(NULL, D, inp_data, inp_corner, inp_width);
+}
+
+
+// Constructor for SPTree with particular size and parent (do not fill tree)
+SPTree::SPTree(SPTree* inp_parent, unsigned int D, double* inp_data, double* inp_corner, double* inp_width) {
+ init(inp_parent, D, inp_data, inp_corner, inp_width);
+}
+
+
+// Constructor for SPTree with particular size and parent -- build the tree, too!
+SPTree::SPTree(SPTree* inp_parent, unsigned int D, double* inp_data, unsigned int N, double* inp_corner, double* inp_width)
+{
+ init(inp_parent, D, inp_data, inp_corner, inp_width);
+ fill(N);
+}
+
+
+// Main initialization function
+void SPTree::init(SPTree* inp_parent, unsigned int D, double* inp_data, double* inp_corner, double* inp_width)
+{
+ parent = inp_parent;
+ dimension = D;
+ no_children = 2;
+ for(unsigned int d = 1; d < D; d++) no_children *= 2;
+ data = inp_data;
+ is_leaf = true;
+ size = 0;
+ cum_size = 0;
+
+ boundary = new Cell(dimension);
+ for(unsigned int d = 0; d < D; d++) boundary->setCorner(d, inp_corner[d]);
+ for(unsigned int d = 0; d < D; d++) boundary->setWidth( d, inp_width[d]);
+
+ children = (SPTree**) malloc(no_children * sizeof(SPTree*));
+ for(unsigned int i = 0; i < no_children; i++) children[i] = NULL;
+
+ center_of_mass = (double*) malloc(D * sizeof(double));
+ for(unsigned int d = 0; d < D; d++) center_of_mass[d] = .0;
+
+ buff = (double*) malloc(D * sizeof(double));
+}
+
+
+// Destructor for SPTree
+SPTree::~SPTree()
+{
+ for(unsigned int i = 0; i < no_children; i++) {
+ if(children[i] != NULL) delete children[i];
+ }
+ free(children);
+ free(center_of_mass);
+ free(buff);
+ delete boundary;
+}
+
+
+// Update the data underlying this tree
+void SPTree::setData(double* inp_data)
+{
+ data = inp_data;
+}
+
+
+// Get the parent of the current tree
+SPTree* SPTree::getParent()
+{
+ return parent;
+}
+
+
+// Insert a point into the SPTree
+bool SPTree::insert(unsigned int new_index)
+{
+ // Ignore objects which do not belong in this quad tree
+ double* point = data + new_index * dimension;
+ if(!boundary->containsPoint(point))
+ return false;
+
+ // Online update of cumulative size and center-of-mass
+ cum_size++;
+ double mult1 = (double) (cum_size - 1) / (double) cum_size;
+ double mult2 = 1.0 / (double) cum_size;
+ for(unsigned int d = 0; d < dimension; d++) center_of_mass[d] *= mult1;
+ for(unsigned int d = 0; d < dimension; d++) center_of_mass[d] += mult2 * point[d];
+
+ // If there is space in this quad tree and it is a leaf, add the object here
+ if(is_leaf && size < QT_NODE_CAPACITY) {
+ index[size] = new_index;
+ size++;
+ return true;
+ }
+
+ // Don't add duplicates for now (this is not very nice)
+ bool any_duplicate = false;
+ for(unsigned int n = 0; n < size; n++) {
+ bool duplicate = true;
+ for(unsigned int d = 0; d < dimension; d++) {
+ if(point[d] != data[index[n] * dimension + d]) { duplicate = false; break; }
+ }
+ any_duplicate = any_duplicate | duplicate;
+ }
+ if(any_duplicate) return true;
+
+ // Otherwise, we need to subdivide the current cell
+ if(is_leaf) subdivide();
+
+ // Find out where the point can be inserted
+ for(unsigned int i = 0; i < no_children; i++) {
+ if(children[i]->insert(new_index)) return true;
+ }
+
+ // Otherwise, the point cannot be inserted (this should never happen)
+ return false;
+}
+
+
+// Create four children which fully divide this cell into four quads of equal area
+void SPTree::subdivide() {
+
+ // Create new children
+ double* new_corner = (double*) malloc(dimension * sizeof(double));
+ double* new_width = (double*) malloc(dimension * sizeof(double));
+ for(unsigned int i = 0; i < no_children; i++) {
+ unsigned int div = 1;
+ for(unsigned int d = 0; d < dimension; d++) {
+ new_width[d] = .5 * boundary->getWidth(d);
+ if((i / div) % 2 == 1) new_corner[d] = boundary->getCorner(d) - .5 * boundary->getWidth(d);
+ else new_corner[d] = boundary->getCorner(d) + .5 * boundary->getWidth(d);
+ div *= 2;
+ }
+ children[i] = new SPTree(this, dimension, data, new_corner, new_width);
+ }
+ free(new_corner);
+ free(new_width);
+
+ // Move existing points to correct children
+ for(unsigned int i = 0; i < size; i++) {
+ bool success = false;
+ for(unsigned int j = 0; j < no_children; j++) {
+ if(!success) success = children[j]->insert(index[i]);
+ }
+ index[i] = -1;
+ }
+
+ // Empty parent node
+ size = 0;
+ is_leaf = false;
+}
+
+
+// Build SPTree on dataset
+void SPTree::fill(unsigned int N)
+{
+ for(unsigned int i = 0; i < N; i++) insert(i);
+}
+
+
+// Checks whether the specified tree is correct
+bool SPTree::isCorrect()
+{
+ for(unsigned int n = 0; n < size; n++) {
+ double* point = data + index[n] * dimension;
+ if(!boundary->containsPoint(point)) return false;
+ }
+ if(!is_leaf) {
+ bool correct = true;
+ for(int i = 0; i < no_children; i++) correct = correct && children[i]->isCorrect();
+ return correct;
+ }
+ else return true;
+}
+
+
+
+// Build a list of all indices in SPTree
+void SPTree::getAllIndices(unsigned int* indices)
+{
+ getAllIndices(indices, 0);
+}
+
+
+// Build a list of all indices in SPTree
+unsigned int SPTree::getAllIndices(unsigned int* indices, unsigned int loc)
+{
+
+ // Gather indices in current quadrant
+ for(unsigned int i = 0; i < size; i++) indices[loc + i] = index[i];
+ loc += size;
+
+ // Gather indices in children
+ if(!is_leaf) {
+ for(int i = 0; i < no_children; i++) loc = children[i]->getAllIndices(indices, loc);
+ }
+ return loc;
+}
+
+
+unsigned int SPTree::getDepth() {
+ if(is_leaf) return 1;
+ int depth = 0;
+ for(unsigned int i = 0; i < no_children; i++) depth = fmax(depth, children[i]->getDepth());
+ return 1 + depth;
+}
+
+
+// Compute non-edge forces using Barnes-Hut algorithm
+void SPTree::computeNonEdgeForces(unsigned int point_index, double theta, double neg_f[], double* sum_Q)
+{
+
+ // Make sure that we spend no time on empty nodes or self-interactions
+ if(cum_size == 0 || (is_leaf && size == 1 && index[0] == point_index)) return;
+
+ // Compute distance between point and center-of-mass
+ double D = .0;
+ unsigned int ind = point_index * dimension;
+ for(unsigned int d = 0; d < dimension; d++) buff[d] = data[ind + d] - center_of_mass[d];
+ for(unsigned int d = 0; d < dimension; d++) D += buff[d] * buff[d];
+
+ // Check whether we can use this node as a "summary"
+ double max_width = 0.0;
+ double cur_width;
+ for(unsigned int d = 0; d < dimension; d++) {
+ cur_width = boundary->getWidth(d);
+ max_width = (max_width > cur_width) ? max_width : cur_width;
+ }
+ if(is_leaf || max_width / sqrt(D) < theta) {
+
+ // Compute and add t-SNE force between point and current node
+ D = 1.0 / (1.0 + D);
+ double mult = cum_size * D;
+ *sum_Q += mult;
+ mult *= D;
+ for(unsigned int d = 0; d < dimension; d++) neg_f[d] += mult * buff[d];
+ }
+ else {
+
+ // Recursively apply Barnes-Hut to children
+ for(unsigned int i = 0; i < no_children; i++) children[i]->computeNonEdgeForces(point_index, theta, neg_f, sum_Q);
+ }
+}
+
+
+// Computes edge forces
+void SPTree::computeEdgeForces(unsigned int* row_P, unsigned int* col_P, double* val_P, int N, double* pos_f)
+{
+
+ // Loop over all edges in the graph
+ unsigned int ind1 = 0;
+ unsigned int ind2 = 0;
+ double D;
+ for(unsigned int n = 0; n < N; n++) {
+ for(unsigned int i = row_P[n]; i < row_P[n + 1]; i++) {
+
+ // Compute pairwise distance and Q-value
+ D = 1.0;
+ ind2 = col_P[i] * dimension;
+ for(unsigned int d = 0; d < dimension; d++) buff[d] = data[ind1 + d] - data[ind2 + d];
+ for(unsigned int d = 0; d < dimension; d++) D += buff[d] * buff[d];
+ D = val_P[i] / D;
+
+ // Sum positive force
+ for(unsigned int d = 0; d < dimension; d++) pos_f[ind1 + d] += D * buff[d];
+ }
+ ind1 += dimension;
+ }
+}
+
+
+// Print out tree
+void SPTree::print()
+{
+ if(cum_size == 0) {
+ printf("Empty node\n");
+ return;
+ }
+
+ if(is_leaf) {
+ printf("Leaf node; data = [");
+ for(int i = 0; i < size; i++) {
+ double* point = data + index[i] * dimension;
+ for(int d = 0; d < dimension; d++) printf("%f, ", point[d]);
+ printf(" (index = %d)", index[i]);
+ if(i < size - 1) printf("\n");
+ else printf("]\n");
+ }
+ }
+ else {
+ printf("Intersection node with center-of-mass = [");
+ for(int d = 0; d < dimension; d++) printf("%f, ", center_of_mass[d]);
+ printf("]; children are:\n");
+ for(int i = 0; i < no_children; i++) children[i]->print();
+ }
+}
+
diff --git a/src/bhtsne/sptree.h b/src/bhtsne/sptree.h
new file mode 100755
index 0000000..b138a9a
--- /dev/null
+++ b/src/bhtsne/sptree.h
@@ -0,0 +1,115 @@
+/*
+ *
+ * Copyright (c) 2014, Laurens van der Maaten (Delft University of Technology)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Delft University of Technology.
+ * 4. Neither the name of the Delft University of Technology nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY LAURENS VAN DER MAATEN ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL LAURENS VAN DER MAATEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef SPTREE_H
+#define SPTREE_H
+
+using namespace std;
+
+
+class Cell {
+
+ unsigned int dimension;
+ double* corner;
+ double* width;
+
+
+public:
+ Cell(unsigned int inp_dimension);
+ Cell(unsigned int inp_dimension, double* inp_corner, double* inp_width);
+ ~Cell();
+
+ double getCorner(unsigned int d);
+ double getWidth(unsigned int d);
+ void setCorner(unsigned int d, double val);
+ void setWidth(unsigned int d, double val);
+ bool containsPoint(double point[]);
+};
+
+
+class SPTree
+{
+
+ // Fixed constants
+ static const unsigned int QT_NODE_CAPACITY = 1;
+
+ // A buffer we use when doing force computations
+ double* buff;
+
+ // Properties of this node in the tree
+ SPTree* parent;
+ unsigned int dimension;
+ bool is_leaf;
+ unsigned int size;
+ unsigned int cum_size;
+
+ // Axis-aligned bounding box stored as a center with half-dimensions to represent the boundaries of this quad tree
+ Cell* boundary;
+
+ // Indices in this space-partitioning tree node, corresponding center-of-mass, and list of all children
+ double* data;
+ double* center_of_mass;
+ unsigned int index[QT_NODE_CAPACITY];
+
+ // Children
+ SPTree** children;
+ unsigned int no_children;
+
+public:
+ SPTree(unsigned int D, double* inp_data, unsigned int N);
+ SPTree(unsigned int D, double* inp_data, double* inp_corner, double* inp_width);
+ SPTree(unsigned int D, double* inp_data, unsigned int N, double* inp_corner, double* inp_width);
+ SPTree(SPTree* inp_parent, unsigned int D, double* inp_data, unsigned int N, double* inp_corner, double* inp_width);
+ SPTree(SPTree* inp_parent, unsigned int D, double* inp_data, double* inp_corner, double* inp_width);
+ ~SPTree();
+ void setData(double* inp_data);
+ SPTree* getParent();
+ void construct(Cell boundary);
+ bool insert(unsigned int new_index);
+ void subdivide();
+ bool isCorrect();
+ void rebuildTree();
+ void getAllIndices(unsigned int* indices);
+ unsigned int getDepth();
+ void computeNonEdgeForces(unsigned int point_index, double theta, double neg_f[], double* sum_Q);
+ void computeEdgeForces(unsigned int* row_P, unsigned int* col_P, double* val_P, int N, double* pos_f);
+ void print();
+
+private:
+ void init(SPTree* inp_parent, unsigned int D, double* inp_data, double* inp_corner, double* inp_width);
+ void fill(unsigned int N);
+ unsigned int getAllIndices(unsigned int* indices, unsigned int loc);
+ bool isChild(unsigned int test_index, unsigned int start, unsigned int end);
+};
+
+#endif
diff --git a/src/bhtsne/tsne.cpp b/src/bhtsne/tsne.cpp
new file mode 100755
index 0000000..11fa0a4
--- /dev/null
+++ b/src/bhtsne/tsne.cpp
@@ -0,0 +1,758 @@
+/*
+ *
+ * Copyright (c) 2014, Laurens van der Maaten (Delft University of Technology)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Delft University of Technology.
+ * 4. Neither the name of the Delft University of Technology nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY LAURENS VAN DER MAATEN ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL LAURENS VAN DER MAATEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "vptree.h"
+#include "sptree.h"
+#include "tsne.h"
+
+
+using namespace std;
+
+// Perform t-SNE
+void TSNE::run(double* X, int N, int D, double* Y, int no_dims, double perplexity, double theta) {
+
+ // Determine whether we are using an exact algorithm
+ if(N - 1 < 3 * perplexity) { printf("Perplexity too large for the number of data points!\n"); exit(1); }
+ printf("Using no_dims = %d, perplexity = %f, and theta = %f\n", no_dims, perplexity, theta);
+ bool exact = (theta == .0) ? true : false;
+
+ // Set learning parameters
+ float total_time = .0;
+ clock_t start, end;
+ int max_iter = 1000, stop_lying_iter = 250, mom_switch_iter = 250;
+ double momentum = .5, final_momentum = .8;
+ double eta = 200.0;
+
+ // Allocate some memory
+ double* dY = (double*) malloc(N * no_dims * sizeof(double));
+ double* uY = (double*) malloc(N * no_dims * sizeof(double));
+ double* gains = (double*) malloc(N * no_dims * sizeof(double));
+ if(dY == NULL || uY == NULL || gains == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ for(int i = 0; i < N * no_dims; i++) uY[i] = .0;
+ for(int i = 0; i < N * no_dims; i++) gains[i] = 1.0;
+
+ // Normalize input data (to prevent numerical problems)
+ printf("Computing input similarities...\n");
+ start = clock();
+ zeroMean(X, N, D);
+ double max_X = .0;
+ for(int i = 0; i < N * D; i++) {
+ if(X[i] > max_X) max_X = X[i];
+ }
+ for(int i = 0; i < N * D; i++) X[i] /= max_X;
+
+ // Compute input similarities for exact t-SNE
+ double* P; unsigned int* row_P; unsigned int* col_P; double* val_P;
+ if(exact) {
+
+ // Compute similarities
+ printf("Exact?");
+ P = (double*) malloc(N * N * sizeof(double));
+ if(P == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ computeGaussianPerplexity(X, N, D, P, perplexity);
+
+ // Symmetrize input similarities
+ printf("Symmetrizing...\n");
+ int nN = 0;
+ for(int n = 0; n < N; n++) {
+ int mN = 0;
+ for(int m = n + 1; m < N; m++) {
+ P[nN + m] += P[mN + n];
+ P[mN + n] = P[nN + m];
+ mN += N;
+ }
+ nN += N;
+ }
+ double sum_P = .0;
+ for(int i = 0; i < N * N; i++) sum_P += P[i];
+ for(int i = 0; i < N * N; i++) P[i] /= sum_P;
+ }
+
+ // Compute input similarities for approximate t-SNE
+ else {
+
+ // Compute asymmetric pairwise input similarities
+ computeGaussianPerplexity(X, N, D, &row_P, &col_P, &val_P, perplexity, (int) (3 * perplexity));
+
+ // Symmetrize input similarities
+ symmetrizeMatrix(&row_P, &col_P, &val_P, N);
+ double sum_P = .0;
+ for(int i = 0; i < row_P[N]; i++) sum_P += val_P[i];
+ for(int i = 0; i < row_P[N]; i++) val_P[i] /= sum_P;
+ }
+ end = clock();
+
+ // Lie about the P-values
+ if(exact) { for(int i = 0; i < N * N; i++) P[i] *= 12.0; }
+ else { for(int i = 0; i < row_P[N]; i++) val_P[i] *= 12.0; }
+
+ // Initialize solution (randomly)
+ for(int i = 0; i < N * no_dims; i++) Y[i] = randn() * .0001;
+
+ // Perform main training loop
+ if(exact) printf("Input similarities computed in %4.2f seconds!\nLearning embedding...\n", (float) (end - start) / CLOCKS_PER_SEC);
+ else printf("Input similarities computed in %4.2f seconds (sparsity = %f)!\nLearning embedding...\n", (float) (end - start) / CLOCKS_PER_SEC, (double) row_P[N] / ((double) N * (double) N));
+ start = clock();
+ for(int iter = 0; iter < max_iter; iter++) {
+
+ // Compute (approximate) gradient
+ if(exact) computeExactGradient(P, Y, N, no_dims, dY);
+ else computeGradient(P, row_P, col_P, val_P, Y, N, no_dims, dY, theta);
+
+ // Update gains
+ for(int i = 0; i < N * no_dims; i++) gains[i] = (sign(dY[i]) != sign(uY[i])) ? (gains[i] + .2) : (gains[i] * .8);
+ for(int i = 0; i < N * no_dims; i++) if(gains[i] < .01) gains[i] = .01;
+
+ // Perform gradient update (with momentum and gains)
+ for(int i = 0; i < N * no_dims; i++) uY[i] = momentum * uY[i] - eta * gains[i] * dY[i];
+ for(int i = 0; i < N * no_dims; i++) Y[i] = Y[i] + uY[i];
+
+ // Make solution zero-mean
+ zeroMean(Y, N, no_dims);
+
+ // Stop lying about the P-values after a while, and switch momentum
+ if(iter == stop_lying_iter) {
+ if(exact) { for(int i = 0; i < N * N; i++) P[i] /= 12.0; }
+ else { for(int i = 0; i < row_P[N]; i++) val_P[i] /= 12.0; }
+ }
+ if(iter == mom_switch_iter) momentum = final_momentum;
+
+ // Print out progress
+ if(iter > 0 && (iter % 50 == 0 || iter == max_iter - 1)) {
+ end = clock();
+ double C = .0;
+ if(exact) C = evaluateError(P, Y, N, no_dims);
+ else C = evaluateError(row_P, col_P, val_P, Y, N, no_dims, theta); // doing approximate computation here!
+ if(iter == 0)
+ printf("Iteration %d: error is %f\n", iter + 1, C);
+ else {
+ total_time += (float) (end - start) / CLOCKS_PER_SEC;
+ printf("Iteration %d: error is %f (50 iterations in %4.2f seconds)\n", iter, C, (float) (end - start) / CLOCKS_PER_SEC);
+ }
+ start = clock();
+ }
+ }
+ end = clock(); total_time += (float) (end - start) / CLOCKS_PER_SEC;
+
+ // Clean up memory
+ free(dY);
+ free(uY);
+ free(gains);
+ if(exact) free(P);
+ else {
+ free(row_P); row_P = NULL;
+ free(col_P); col_P = NULL;
+ free(val_P); val_P = NULL;
+ }
+ printf("Fitting performed in %4.2f seconds.\n", total_time);
+}
+
+
+// Compute gradient of the t-SNE cost function (using Barnes-Hut algorithm)
+void TSNE::computeGradient(double* P, unsigned int* inp_row_P, unsigned int* inp_col_P, double* inp_val_P, double* Y, int N, int D, double* dC, double theta)
+{
+
+ // Construct space-partitioning tree on current map
+ SPTree* tree = new SPTree(D, Y, N);
+
+ // Compute all terms required for t-SNE gradient
+ double sum_Q = .0;
+ double* pos_f = (double*) calloc(N * D, sizeof(double));
+ double* neg_f = (double*) calloc(N * D, sizeof(double));
+ if(pos_f == NULL || neg_f == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ tree->computeEdgeForces(inp_row_P, inp_col_P, inp_val_P, N, pos_f);
+ for(int n = 0; n < N; n++) tree->computeNonEdgeForces(n, theta, neg_f + n * D, &sum_Q);
+
+ // Compute final t-SNE gradient
+ for(int i = 0; i < N * D; i++) {
+ dC[i] = pos_f[i] - (neg_f[i] / sum_Q);
+ }
+ free(pos_f);
+ free(neg_f);
+ delete tree;
+}
+
+// Compute gradient of the t-SNE cost function (exact)
+void TSNE::computeExactGradient(double* P, double* Y, int N, int D, double* dC) {
+
+ // Make sure the current gradient contains zeros
+ for(int i = 0; i < N * D; i++) dC[i] = 0.0;
+
+ // Compute the squared Euclidean distance matrix
+ double* DD = (double*) malloc(N * N * sizeof(double));
+ if(DD == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ computeSquaredEuclideanDistance(Y, N, D, DD);
+
+ // Compute Q-matrix and normalization sum
+ double* Q = (double*) malloc(N * N * sizeof(double));
+ if(Q == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ double sum_Q = .0;
+ int nN = 0;
+ for(int n = 0; n < N; n++) {
+ for(int m = 0; m < N; m++) {
+ if(n != m) {
+ Q[nN + m] = 1 / (1 + DD[nN + m]);
+ sum_Q += Q[nN + m];
+ }
+ }
+ nN += N;
+ }
+
+ // Perform the computation of the gradient
+ nN = 0;
+ int nD = 0;
+ for(int n = 0; n < N; n++) {
+ int mD = 0;
+ for(int m = 0; m < N; m++) {
+ if(n != m) {
+ double mult = (P[nN + m] - (Q[nN + m] / sum_Q)) * Q[nN + m];
+ for(int d = 0; d < D; d++) {
+ dC[nD + d] += (Y[nD + d] - Y[mD + d]) * mult;
+ }
+ }
+ mD += D;
+ }
+ nN += N;
+ nD += D;
+ }
+
+ // Free memory
+ free(DD); DD = NULL;
+ free(Q); Q = NULL;
+}
+
+
+// Evaluate t-SNE cost function (exactly)
+double TSNE::evaluateError(double* P, double* Y, int N, int D) {
+
+ // Compute the squared Euclidean distance matrix
+ double* DD = (double*) malloc(N * N * sizeof(double));
+ double* Q = (double*) malloc(N * N * sizeof(double));
+ if(DD == NULL || Q == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ computeSquaredEuclideanDistance(Y, N, D, DD);
+
+ // Compute Q-matrix and normalization sum
+ int nN = 0;
+ double sum_Q = DBL_MIN;
+ for(int n = 0; n < N; n++) {
+ for(int m = 0; m < N; m++) {
+ if(n != m) {
+ Q[nN + m] = 1 / (1 + DD[nN + m]);
+ sum_Q += Q[nN + m];
+ }
+ else Q[nN + m] = DBL_MIN;
+ }
+ nN += N;
+ }
+ for(int i = 0; i < N * N; i++) Q[i] /= sum_Q;
+
+ // Sum t-SNE error
+ double C = .0;
+ for(int n = 0; n < N * N; n++) {
+ C += P[n] * log((P[n] + FLT_MIN) / (Q[n] + FLT_MIN));
+ }
+
+ // Clean up memory
+ free(DD);
+ free(Q);
+ return C;
+}
+
+// Evaluate t-SNE cost function (approximately)
+double TSNE::evaluateError(unsigned int* row_P, unsigned int* col_P, double* val_P, double* Y, int N, int D, double theta)
+{
+
+ // Get estimate of normalization term
+ SPTree* tree = new SPTree(D, Y, N);
+ double* buff = (double*) calloc(D, sizeof(double));
+ double sum_Q = .0;
+ for(int n = 0; n < N; n++) tree->computeNonEdgeForces(n, theta, buff, &sum_Q);
+
+ // Loop over all edges to compute t-SNE error
+ int ind1, ind2;
+ double C = .0, Q;
+ for(int n = 0; n < N; n++) {
+ ind1 = n * D;
+ for(int i = row_P[n]; i < row_P[n + 1]; i++) {
+ Q = .0;
+ ind2 = col_P[i] * D;
+ for(int d = 0; d < D; d++) buff[d] = Y[ind1 + d];
+ for(int d = 0; d < D; d++) buff[d] -= Y[ind2 + d];
+ for(int d = 0; d < D; d++) Q += buff[d] * buff[d];
+ Q = (1.0 / (1.0 + Q)) / sum_Q;
+ C += val_P[i] * log((val_P[i] + FLT_MIN) / (Q + FLT_MIN));
+ }
+ }
+
+ // Clean up memory
+ free(buff);
+ delete tree;
+ return C;
+}
+
+
+// Compute input similarities with a fixed perplexity
+void TSNE::computeGaussianPerplexity(double* X, int N, int D, double* P, double perplexity) {
+
+ // Compute the squared Euclidean distance matrix
+ double* DD = (double*) malloc(N * N * sizeof(double));
+ if(DD == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ computeSquaredEuclideanDistance(X, N, D, DD);
+
+ // Compute the Gaussian kernel row by row
+ int nN = 0;
+ for(int n = 0; n < N; n++) {
+
+ // Initialize some variables
+ bool found = false;
+ double beta = 1.0;
+ double min_beta = -DBL_MAX;
+ double max_beta = DBL_MAX;
+ double tol = 1e-5;
+ double sum_P;
+
+ // Iterate until we found a good perplexity
+ int iter = 0;
+ while(!found && iter < 200) {
+
+ // Compute Gaussian kernel row
+ for(int m = 0; m < N; m++) P[nN + m] = exp(-beta * DD[nN + m]);
+ P[nN + n] = DBL_MIN;
+
+ // Compute entropy of current row
+ sum_P = DBL_MIN;
+ for(int m = 0; m < N; m++) sum_P += P[nN + m];
+ double H = 0.0;
+ for(int m = 0; m < N; m++) H += beta * (DD[nN + m] * P[nN + m]);
+ H = (H / sum_P) + log(sum_P);
+
+ // Evaluate whether the entropy is within the tolerance level
+ double Hdiff = H - log(perplexity);
+ if(Hdiff < tol && -Hdiff < tol) {
+ found = true;
+ }
+ else {
+ if(Hdiff > 0) {
+ min_beta = beta;
+ if(max_beta == DBL_MAX || max_beta == -DBL_MAX)
+ beta *= 2.0;
+ else
+ beta = (beta + max_beta) / 2.0;
+ }
+ else {
+ max_beta = beta;
+ if(min_beta == -DBL_MAX || min_beta == DBL_MAX)
+ beta /= 2.0;
+ else
+ beta = (beta + min_beta) / 2.0;
+ }
+ }
+
+ // Update iteration counter
+ iter++;
+ }
+
+ // Row normalize P
+ for(int m = 0; m < N; m++) P[nN + m] /= sum_P;
+ nN += N;
+ }
+
+ // Clean up memory
+ free(DD); DD = NULL;
+}
+
+
+// Compute input similarities with a fixed perplexity using ball trees (this function allocates memory another function should free)
+void TSNE::computeGaussianPerplexity(double* X, int N, int D, unsigned int** _row_P, unsigned int** _col_P, double** _val_P, double perplexity, int K) {
+
+ if(perplexity > K) printf("Perplexity should be lower than K!\n");
+
+ // Allocate the memory we need
+ *_row_P = (unsigned int*) malloc((N + 1) * sizeof(unsigned int));
+ *_col_P = (unsigned int*) calloc(N * K, sizeof(unsigned int));
+ *_val_P = (double*) calloc(N * K, sizeof(double));
+ if(*_row_P == NULL || *_col_P == NULL || *_val_P == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ unsigned int* row_P = *_row_P;
+ unsigned int* col_P = *_col_P;
+ double* val_P = *_val_P;
+ double* cur_P = (double*) malloc((N - 1) * sizeof(double));
+ if(cur_P == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ row_P[0] = 0;
+ for(int n = 0; n < N; n++) row_P[n + 1] = row_P[n] + (unsigned int) K;
+
+ // Build ball tree on data set
+ VpTree* tree = new VpTree();
+ vector obj_X(N, DataPoint(D, -1, X));
+ for(int n = 0; n < N; n++) obj_X[n] = DataPoint(D, n, X + n * D);
+ tree->create(obj_X);
+
+ // Loop over all points to find nearest neighbors
+ printf("Building tree...\n");
+ vector indices;
+ vector distances;
+ for(int n = 0; n < N; n++) {
+
+ if(n % 10000 == 0) printf(" - point %d of %d\n", n, N);
+
+ // Find nearest neighbors
+ indices.clear();
+ distances.clear();
+ tree->search(obj_X[n], K + 1, &indices, &distances);
+
+ // Initialize some variables for binary search
+ bool found = false;
+ double beta = 1.0;
+ double min_beta = -DBL_MAX;
+ double max_beta = DBL_MAX;
+ double tol = 1e-5;
+
+ // Iterate until we found a good perplexity
+ int iter = 0; double sum_P;
+ while(!found && iter < 200) {
+
+ // Compute Gaussian kernel row
+ for(int m = 0; m < K; m++) cur_P[m] = exp(-beta * distances[m + 1] * distances[m + 1]);
+
+ // Compute entropy of current row
+ sum_P = DBL_MIN;
+ for(int m = 0; m < K; m++) sum_P += cur_P[m];
+ double H = .0;
+ for(int m = 0; m < K; m++) H += beta * (distances[m + 1] * distances[m + 1] * cur_P[m]);
+ H = (H / sum_P) + log(sum_P);
+
+ // Evaluate whether the entropy is within the tolerance level
+ double Hdiff = H - log(perplexity);
+ if(Hdiff < tol && -Hdiff < tol) {
+ found = true;
+ }
+ else {
+ if(Hdiff > 0) {
+ min_beta = beta;
+ if(max_beta == DBL_MAX || max_beta == -DBL_MAX)
+ beta *= 2.0;
+ else
+ beta = (beta + max_beta) / 2.0;
+ }
+ else {
+ max_beta = beta;
+ if(min_beta == -DBL_MAX || min_beta == DBL_MAX)
+ beta /= 2.0;
+ else
+ beta = (beta + min_beta) / 2.0;
+ }
+ }
+
+ // Update iteration counter
+ iter++;
+ }
+
+ // Row-normalize current row of P and store in matrix
+ for(unsigned int m = 0; m < K; m++) cur_P[m] /= sum_P;
+ for(unsigned int m = 0; m < K; m++) {
+ col_P[row_P[n] + m] = (unsigned int) indices[m + 1].index();
+ val_P[row_P[n] + m] = cur_P[m];
+ }
+ }
+
+ // Clean up memory
+ obj_X.clear();
+ free(cur_P);
+ delete tree;
+}
+
+
+// Symmetrizes a sparse matrix
+void TSNE::symmetrizeMatrix(unsigned int** _row_P, unsigned int** _col_P, double** _val_P, int N) {
+
+ // Get sparse matrix
+ unsigned int* row_P = *_row_P;
+ unsigned int* col_P = *_col_P;
+ double* val_P = *_val_P;
+
+ // Count number of elements and row counts of symmetric matrix
+ int* row_counts = (int*) calloc(N, sizeof(int));
+ if(row_counts == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ for(int n = 0; n < N; n++) {
+ for(int i = row_P[n]; i < row_P[n + 1]; i++) {
+
+ // Check whether element (col_P[i], n) is present
+ bool present = false;
+ for(int m = row_P[col_P[i]]; m < row_P[col_P[i] + 1]; m++) {
+ if(col_P[m] == n) present = true;
+ }
+ if(present) row_counts[n]++;
+ else {
+ row_counts[n]++;
+ row_counts[col_P[i]]++;
+ }
+ }
+ }
+ int no_elem = 0;
+ for(int n = 0; n < N; n++) no_elem += row_counts[n];
+
+ // Allocate memory for symmetrized matrix
+ unsigned int* sym_row_P = (unsigned int*) malloc((N + 1) * sizeof(unsigned int));
+ unsigned int* sym_col_P = (unsigned int*) malloc(no_elem * sizeof(unsigned int));
+ double* sym_val_P = (double*) malloc(no_elem * sizeof(double));
+ if(sym_row_P == NULL || sym_col_P == NULL || sym_val_P == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+
+ // Construct new row indices for symmetric matrix
+ sym_row_P[0] = 0;
+ for(int n = 0; n < N; n++) sym_row_P[n + 1] = sym_row_P[n] + (unsigned int) row_counts[n];
+
+ // Fill the result matrix
+ int* offset = (int*) calloc(N, sizeof(int));
+ if(offset == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ for(int n = 0; n < N; n++) {
+ for(unsigned int i = row_P[n]; i < row_P[n + 1]; i++) { // considering element(n, col_P[i])
+
+ // Check whether element (col_P[i], n) is present
+ bool present = false;
+ for(unsigned int m = row_P[col_P[i]]; m < row_P[col_P[i] + 1]; m++) {
+ if(col_P[m] == n) {
+ present = true;
+ if(n <= col_P[i]) { // make sure we do not add elements twice
+ sym_col_P[sym_row_P[n] + offset[n]] = col_P[i];
+ sym_col_P[sym_row_P[col_P[i]] + offset[col_P[i]]] = n;
+ sym_val_P[sym_row_P[n] + offset[n]] = val_P[i] + val_P[m];
+ sym_val_P[sym_row_P[col_P[i]] + offset[col_P[i]]] = val_P[i] + val_P[m];
+ }
+ }
+ }
+
+ // If (col_P[i], n) is not present, there is no addition involved
+ if(!present) {
+ sym_col_P[sym_row_P[n] + offset[n]] = col_P[i];
+ sym_col_P[sym_row_P[col_P[i]] + offset[col_P[i]]] = n;
+ sym_val_P[sym_row_P[n] + offset[n]] = val_P[i];
+ sym_val_P[sym_row_P[col_P[i]] + offset[col_P[i]]] = val_P[i];
+ }
+
+ // Update offsets
+ if(!present || (present && n <= col_P[i])) {
+ offset[n]++;
+ if(col_P[i] != n) offset[col_P[i]]++;
+ }
+ }
+ }
+
+ // Divide the result by two
+ for(int i = 0; i < no_elem; i++) sym_val_P[i] /= 2.0;
+
+ // Return symmetrized matrices
+ free(*_row_P); *_row_P = sym_row_P;
+ free(*_col_P); *_col_P = sym_col_P;
+ free(*_val_P); *_val_P = sym_val_P;
+
+ // Free up some memery
+ free(offset); offset = NULL;
+ free(row_counts); row_counts = NULL;
+}
+
+// Compute squared Euclidean distance matrix (using BLAS)
+void TSNE::computeSquaredEuclideanDistance(double* X, int N, int D, double* DD) {
+ double* dataSums = (double*) calloc(N, sizeof(double));
+ if(dataSums == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ int nD = 0;
+ for(int n = 0; n < N; n++) {
+ for(int d = 0; d < D; d++) {
+ dataSums[n] += (X[nD + d] * X[nD + d]);
+ }
+ nD += D;
+ }
+ int nN = 0;
+ for(int n = 0; n < N; n++) {
+ for(int m = 0; m < N; m++) {
+ DD[nN + m] = dataSums[n] + dataSums[m];
+ }
+ nN += N;
+ }
+ nN = 0; nD = 0;
+ for(int n = 0; n < N; n++) {
+ int mD = 0;
+ DD[nN + n] = 0.0;
+ for(int m = n + 1; m < N; m++) {
+ DD[nN + m] = 0.0;
+ for(int d = 0; d < D; d++) {
+ DD[nN + m] += (X[nD + d] - X[mD + d]) * (X[nD + d] - X[mD + d]);
+ }
+ DD[m * N + n] = DD[nN + m];
+ mD += D;
+ }
+ nN += N; nD += D;
+ }
+ free(dataSums); dataSums = NULL;
+}
+
+
+// Makes data zero-mean
+void TSNE::zeroMean(double* X, int N, int D) {
+
+ // Compute data mean
+ double* mean = (double*) calloc(D, sizeof(double));
+ if(mean == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ int nD = 0;
+ for(int n = 0; n < N; n++) {
+ for(int d = 0; d < D; d++) {
+ mean[d] += X[nD + d];
+ }
+ nD += D;
+ }
+ for(int d = 0; d < D; d++) {
+ mean[d] /= (double) N;
+ }
+
+ // Subtract data mean
+ nD = 0;
+ for(int n = 0; n < N; n++) {
+ for(int d = 0; d < D; d++) {
+ X[nD + d] -= mean[d];
+ }
+ nD += D;
+ }
+ free(mean); mean = NULL;
+}
+
+
+// Generates a Gaussian random number
+double TSNE::randn() {
+ double x, y, radius;
+ do {
+ x = 2 * (rand() / ((double) RAND_MAX + 1)) - 1;
+ y = 2 * (rand() / ((double) RAND_MAX + 1)) - 1;
+ radius = (x * x) + (y * y);
+ } while((radius >= 1.0) || (radius == 0.0));
+ radius = sqrt(-2 * log(radius) / radius);
+ x *= radius;
+ y *= radius;
+ return x;
+}
+
+// Function that loads data from a t-SNE file
+// Note: this function does a malloc that should be freed elsewhere
+bool TSNE::load_data(double** data, int* n, int* d, int* no_dims, double* theta, double* perplexity, int* rand_seed) {
+
+ // Open file, read first 2 integers, allocate memory, and read the data
+ FILE *h;
+ if((h = fopen("data.dat", "r+b")) == NULL) {
+ printf("Error: could not open data file.\n");
+ return false;
+ }
+ fread(n, sizeof(int), 1, h); // number of datapoints
+ fread(d, sizeof(int), 1, h); // original dimensionality
+ fread(theta, sizeof(double), 1, h); // gradient accuracy
+ fread(perplexity, sizeof(double), 1, h); // perplexity
+ fread(no_dims, sizeof(int), 1, h); // output dimensionality
+ *data = (double*) malloc(*d * *n * sizeof(double));
+ if(*data == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ fread(*data, sizeof(double), *n * *d, h); // the data
+ if(!feof(h)) fread(rand_seed, sizeof(int), 1, h); // random seed
+ fclose(h);
+ printf("Read the %i x %i data matrix successfully!\n", *n, *d);
+ return true;
+}
+
+// Function that saves map to a t-SNE file
+void TSNE::save_data(double* data, int* landmarks, double* costs, int n, int d) {
+
+ // Open file, write first 2 integers and then the data
+ FILE *h;
+ if((h = fopen("result.dat", "w+b")) == NULL) {
+ printf("Error: could not open data file.\n");
+ return;
+ }
+ fwrite(&n, sizeof(int), 1, h);
+ fwrite(&d, sizeof(int), 1, h);
+ fwrite(data, sizeof(double), n * d, h);
+ fwrite(landmarks, sizeof(int), n, h);
+ fwrite(costs, sizeof(double), n, h);
+ fclose(h);
+ printf("Wrote the %i x %i data matrix successfully!\n", n, d);
+}
+
+/*
+// Function that runs the Barnes-Hut implementation of t-SNE
+int main() {
+
+ // Define some variables
+ int origN, N, D, no_dims, *landmarks;
+ double perc_landmarks;
+ double perplexity, theta, *data;
+ int rand_seed = -1;
+ TSNE* tsne = new TSNE();
+
+ // Read the parameters and the dataset
+ if(tsne->load_data(&data, &origN, &D, &no_dims, &theta, &perplexity, &rand_seed)) {
+
+ // Set random seed
+ if(rand_seed >= 0) {
+ printf("Using random seed: %d\n", rand_seed);
+ srand((unsigned int) rand_seed);
+ }
+ else {
+ printf("Using current time as random seed...\n");
+ srand(time(NULL));
+ }
+
+ // Make dummy landmarks
+ N = origN;
+ int* landmarks = (int*) malloc(N * sizeof(int));
+ if(landmarks == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ for(int n = 0; n < N; n++) landmarks[n] = n;
+
+ // Now fire up the SNE implementation
+ double* Y = (double*) malloc(N * no_dims * sizeof(double));
+ double* costs = (double*) calloc(N, sizeof(double));
+ if(Y == NULL || costs == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+ tsne->run(data, N, D, Y, no_dims, perplexity, theta);
+
+ // Save the results
+ tsne->save_data(Y, landmarks, costs, N, no_dims);
+
+ // Clean up the memory
+ free(data); data = NULL;
+ free(Y); Y = NULL;
+ free(costs); costs = NULL;
+ free(landmarks); landmarks = NULL;
+ }
+ delete(tsne);
+}
+
+*/
\ No newline at end of file
diff --git a/src/bhtsne/tsne.h b/src/bhtsne/tsne.h
new file mode 100755
index 0000000..4e6a800
--- /dev/null
+++ b/src/bhtsne/tsne.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright (c) 2014, Laurens van der Maaten (Delft University of Technology)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Delft University of Technology.
+ * 4. Neither the name of the Delft University of Technology nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY LAURENS VAN DER MAATEN ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL LAURENS VAN DER MAATEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef TSNE_H
+#define TSNE_H
+
+
+static inline double sign(double x) { return (x == .0 ? .0 : (x < .0 ? -1.0 : 1.0)); }
+
+
+class TSNE
+{
+public:
+ void run(double* X, int N, int D, double* Y, int no_dims, double perplexity, double theta);
+ bool load_data(double** data, int* n, int* d, int* no_dims, double* theta, double* perplexity, int* rand_seed);
+ void save_data(double* data, int* landmarks, double* costs, int n, int d);
+ void symmetrizeMatrix(unsigned int** row_P, unsigned int** col_P, double** val_P, int N); // should be static!
+
+
+private:
+ void computeGradient(double* P, unsigned int* inp_row_P, unsigned int* inp_col_P, double* inp_val_P, double* Y, int N, int D, double* dC, double theta);
+ void computeExactGradient(double* P, double* Y, int N, int D, double* dC);
+ double evaluateError(double* P, double* Y, int N, int D);
+ double evaluateError(unsigned int* row_P, unsigned int* col_P, double* val_P, double* Y, int N, int D, double theta);
+ void zeroMean(double* X, int N, int D);
+ void computeGaussianPerplexity(double* X, int N, int D, double* P, double perplexity);
+ void computeGaussianPerplexity(double* X, int N, int D, unsigned int** _row_P, unsigned int** _col_P, double** _val_P, double perplexity, int K);
+ void computeSquaredEuclideanDistance(double* X, int N, int D, double* DD);
+ double randn();
+};
+
+#endif
+
diff --git a/src/bhtsne/vptree.h b/src/bhtsne/vptree.h
new file mode 100755
index 0000000..9e301d6
--- /dev/null
+++ b/src/bhtsne/vptree.h
@@ -0,0 +1,272 @@
+/*
+ *
+ * Copyright (c) 2014, Laurens van der Maaten (Delft University of Technology)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Delft University of Technology.
+ * 4. Neither the name of the Delft University of Technology nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY LAURENS VAN DER MAATEN ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL LAURENS VAN DER MAATEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+
+
+/* This code was adopted with minor modifications from Steve Hanov's great tutorial at http://stevehanov.ca/blog/index.php?id=130 */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#ifndef VPTREE_H
+#define VPTREE_H
+
+class DataPoint
+{
+ int _ind;
+
+public:
+ double* _x;
+ int _D;
+ DataPoint() {
+ _D = 1;
+ _ind = -1;
+ _x = NULL;
+ }
+ DataPoint(int D, int ind, double* x) {
+ _D = D;
+ _ind = ind;
+ _x = (double*) malloc(_D * sizeof(double));
+ for(int d = 0; d < _D; d++) _x[d] = x[d];
+ }
+ DataPoint(const DataPoint& other) { // this makes a deep copy -- should not free anything
+ if(this != &other) {
+ _D = other.dimensionality();
+ _ind = other.index();
+ _x = (double*) malloc(_D * sizeof(double));
+ for(int d = 0; d < _D; d++) _x[d] = other.x(d);
+ }
+ }
+ ~DataPoint() { if(_x != NULL) free(_x); }
+ DataPoint& operator= (const DataPoint& other) { // asignment should free old object
+ if(this != &other) {
+ if(_x != NULL) free(_x);
+ _D = other.dimensionality();
+ _ind = other.index();
+ _x = (double*) malloc(_D * sizeof(double));
+ for(int d = 0; d < _D; d++) _x[d] = other.x(d);
+ }
+ return *this;
+ }
+ int index() const { return _ind; }
+ int dimensionality() const { return _D; }
+ double x(int d) const { return _x[d]; }
+};
+
+double euclidean_distance(const DataPoint &t1, const DataPoint &t2) {
+ double dd = .0;
+ double* x1 = t1._x;
+ double* x2 = t2._x;
+ double diff;
+ for(int d = 0; d < t1._D; d++) {
+ diff = (x1[d] - x2[d]);
+ dd += diff * diff;
+ }
+ return sqrt(dd);
+}
+
+
+template
+class VpTree
+{
+public:
+
+ // Default constructor
+ VpTree() : _root(0) {}
+
+ // Destructor
+ ~VpTree() {
+ delete _root;
+ }
+
+ // Function to create a new VpTree from data
+ void create(const std::vector& items) {
+ delete _root;
+ _items = items;
+ _root = buildFromPoints(0, items.size());
+ }
+
+ // Function that uses the tree to find the k nearest neighbors of target
+ void search(const T& target, int k, std::vector* results, std::vector* distances)
+ {
+
+ // Use a priority queue to store intermediate results on
+ std::priority_queue heap;
+
+ // Variable that tracks the distance to the farthest point in our results
+ _tau = DBL_MAX;
+
+ // Perform the search
+ search(_root, target, k, heap);
+
+ // Gather final results
+ results->clear(); distances->clear();
+ while(!heap.empty()) {
+ results->push_back(_items[heap.top().index]);
+ distances->push_back(heap.top().dist);
+ heap.pop();
+ }
+
+ // Results are in reverse order
+ std::reverse(results->begin(), results->end());
+ std::reverse(distances->begin(), distances->end());
+ }
+
+private:
+ std::vector _items;
+ double _tau;
+
+ // Single node of a VP tree (has a point and radius; left children are closer to point than the radius)
+ struct Node
+ {
+ int index; // index of point in node
+ double threshold; // radius(?)
+ Node* left; // points closer by than threshold
+ Node* right; // points farther away than threshold
+
+ Node() :
+ index(0), threshold(0.), left(0), right(0) {}
+
+ ~Node() { // destructor
+ delete left;
+ delete right;
+ }
+ }* _root;
+
+
+ // An item on the intermediate result queue
+ struct HeapItem {
+ HeapItem( int index, double dist) :
+ index(index), dist(dist) {}
+ int index;
+ double dist;
+ bool operator<(const HeapItem& o) const {
+ return dist < o.dist;
+ }
+ };
+
+ // Distance comparator for use in std::nth_element
+ struct DistanceComparator
+ {
+ const T& item;
+ DistanceComparator(const T& item) : item(item) {}
+ bool operator()(const T& a, const T& b) {
+ return distance(item, a) < distance(item, b);
+ }
+ };
+
+ // Function that (recursively) fills the tree
+ Node* buildFromPoints( int lower, int upper )
+ {
+ if (upper == lower) { // indicates that we're done here!
+ return NULL;
+ }
+
+ // Lower index is center of current node
+ Node* node = new Node();
+ node->index = lower;
+
+ if (upper - lower > 1) { // if we did not arrive at leaf yet
+
+ // Choose an arbitrary point and move it to the start
+ int i = (int) ((double)rand() / RAND_MAX * (upper - lower - 1)) + lower;
+ std::swap(_items[lower], _items[i]);
+
+ // Partition around the median distance
+ int median = (upper + lower) / 2;
+ std::nth_element(_items.begin() + lower + 1,
+ _items.begin() + median,
+ _items.begin() + upper,
+ DistanceComparator(_items[lower]));
+
+ // Threshold of the new node will be the distance to the median
+ node->threshold = distance(_items[lower], _items[median]);
+
+ // Recursively build tree
+ node->index = lower;
+ node->left = buildFromPoints(lower + 1, median);
+ node->right = buildFromPoints(median, upper);
+ }
+
+ // Return result
+ return node;
+ }
+
+ // Helper function that searches the tree
+ void search(Node* node, const T& target, int k, std::priority_queue& heap)
+ {
+ if(node == NULL) return; // indicates that we're done here
+
+ // Compute distance between target and current node
+ double dist = distance(_items[node->index], target);
+
+ // If current node within radius tau
+ if(dist < _tau) {
+ if(heap.size() == k) heap.pop(); // remove furthest node from result list (if we already have k results)
+ heap.push(HeapItem(node->index, dist)); // add current node to result list
+ if(heap.size() == k) _tau = heap.top().dist; // update value of tau (farthest point in result list)
+ }
+
+ // Return if we arrived at a leaf
+ if(node->left == NULL && node->right == NULL) {
+ return;
+ }
+
+ // If the target lies within the radius of ball
+ if(dist < node->threshold) {
+ if(dist - _tau <= node->threshold) { // if there can still be neighbors inside the ball, recursively search left child first
+ search(node->left, target, k, heap);
+ }
+
+ if(dist + _tau >= node->threshold) { // if there can still be neighbors outside the ball, recursively search right child
+ search(node->right, target, k, heap);
+ }
+
+ // If the target lies outsize the radius of the ball
+ } else {
+ if(dist + _tau >= node->threshold) { // if there can still be neighbors outside the ball, recursively search right child first
+ search(node->right, target, k, heap);
+ }
+
+ if (dist - _tau <= node->threshold) { // if there can still be neighbors inside the ball, recursively search left child
+ search(node->left, target, k, heap);
+ }
+ }
+ }
+};
+
+#endif
diff --git a/src/ofxTSNE.cpp b/src/ofxTSNE.cpp
new file mode 100644
index 0000000..d307fa5
--- /dev/null
+++ b/src/ofxTSNE.cpp
@@ -0,0 +1,69 @@
+#include "ofxTSNE.h"
+
+
+vector > ofxTSNE::run(vector > & data, int dims, double perplexity, double theta, bool normalize) {
+ int N, D;
+ double *X, *Y;
+
+ N = data.size();
+ D = data[0].size();
+
+ if (N - 1 < 3 * perplexity) {
+ ofLog(OF_LOG_WARNING, "Perplexity too large for number of data points, setting to max");
+ perplexity = (float) (N-1) / 3.0 - 1.0;
+ }
+
+ X = (double*) malloc(D * N * sizeof(double));
+ Y = (double*) malloc(dims * N * sizeof(double));
+
+ int idx = 0;
+ for (int i=0; i min_, max_;
+ min_.resize(dims);
+ max_.resize(dims);
+ for (int i=0; i::max();
+ max_[i] = numeric_limits::min();
+ }
+
+ // unpack Y into tsnePoints
+ tsnePoints.clear();
+ int idxY = 0;
+ for (int i=0; i tsnePoint;
+ tsnePoint.resize(dims);
+ for (int j=0; j max_[j]) max_[j] = tsnePoint[j];
+ }
+ idxY++;
+ }
+ tsnePoints.push_back(tsnePoint);
+ }
+
+ // normalize if requested
+ if (normalize) {
+ for (int i=0; i > run(vector > & data, int dims=2, double perplexity=30, double theta=0.5, bool normalize=true);
+private:
+ TSNE tsne;
+ vector > tsnePoints;
+};