Commit 1732d4ef authored by SHASHIJ GUPTA's avatar SHASHIJ GUPTA

First Commit

parents
File added
function centroids = computeCentroids(X, idx, K)
%COMPUTECENTROIDS returns the new centroids by computing the means of the
%data points assigned to each centroid.
% centroids = COMPUTECENTROIDS(X, idx, K) returns the new centroids by
% computing the means of the data points assigned to each centroid. It is
% given a dataset X where each row is a single data point, a vector
% idx of centroid assignments (i.e. each entry in range [1..K]) for each
% example, and K, the number of centroids. You should return a matrix
% centroids, where each row of centroids is the mean of the data points
% assigned to it.
%
% Useful variables
[m n] = size(X);
% You need to return the following variables correctly.
centroids = zeros(K, n);
% ====================== YOUR CODE HERE ======================
% Instructions: Go over every centroid and compute mean of all points that
% belong to it. Concretely, the row vector centroids(i, :)
% should contain the mean of the data points assigned to
% centroid i.
%
% Note: You can use a for-loop over the centroids to compute this.
%
count = zeros(K,1);
for i = 1:m,
centroids(idx(i,1),:) = centroids(idx(i,1),:) + X(i,:);
count(idx(i,1),1)++;
end;
for i = 1:K,
centroids(i,:) = centroids(i,:)/count(i,1);
end;
% =============================================================
end
function [h, display_array] = displayData(X, example_width)
%DISPLAYDATA Display 2D data in a nice grid
% [h, display_array] = DISPLAYDATA(X, example_width) displays 2D data
% stored in X in a nice grid. It returns the figure handle h and the
% displayed array if requested.
% Set example_width automatically if not passed in
if ~exist('example_width', 'var') || isempty(example_width)
example_width = round(sqrt(size(X, 2)));
end
% Gray Image
colormap(gray);
% Compute rows, cols
[m n] = size(X);
example_height = (n / example_width);
% Compute number of items to display
display_rows = floor(sqrt(m));
display_cols = ceil(m / display_rows);
% Between images padding
pad = 1;
% Setup blank display
display_array = - ones(pad + display_rows * (example_height + pad), ...
pad + display_cols * (example_width + pad));
% Copy each example into a patch on the display array
curr_ex = 1;
for j = 1:display_rows
for i = 1:display_cols
if curr_ex > m,
break;
end
% Copy the patch
% Get the max value of the patch
max_val = max(abs(X(curr_ex, :)));
display_array(pad + (j - 1) * (example_height + pad) + (1:example_height), ...
pad + (i - 1) * (example_width + pad) + (1:example_width)) = ...
reshape(X(curr_ex, :), example_height, example_width) / max_val;
curr_ex = curr_ex + 1;
end
if curr_ex > m,
break;
end
end
% Display Image
h = imagesc(display_array, [-1 1]);
% Do not show axis
axis image off
drawnow;
end
function drawLine(p1, p2, varargin)
%DRAWLINE Draws a line from point p1 to point p2
% DRAWLINE(p1, p2) Draws a line from point p1 to point p2 and holds the
% current figure
plot([p1(1) p2(1)], [p1(2) p2(2)], varargin{:});
end
\ No newline at end of file
%% Machine Learning Online Class
% Exercise 7 | Principle Component Analysis and K-Means Clustering
%
% Instructions
% ------------
%
% This file contains code that helps you get started on the
% exercise. You will need to complete the following functions:
%
% pca.m
% projectData.m
% recoverData.m
% computeCentroids.m
% findClosestCentroids.m
% kMeansInitCentroids.m
%
% For this exercise, you will not need to change any code in this file,
% or any other files other than those mentioned above.
%
%% Initialization
clear ; close all; clc
%% ================= Part 1: Find Closest Centroids ====================
% To help you implement K-Means, we have divided the learning algorithm
% into two functions -- findClosestCentroids and computeCentroids. In this
% part, you should complete the code in the findClosestCentroids function.
%
fprintf('Finding closest centroids.\n\n');
% Load an example dataset that we will be using
load('ex7data2.mat');
% Select an initial set of centroids
K = 3; % 3 Centroids
initial_centroids = [3 3; 6 2; 8 5];
% Find the closest centroids for the examples using the
% initial_centroids
idx = findClosestCentroids(X, initial_centroids);
fprintf('Closest centroids for the first 3 examples: \n')
fprintf(' %d', idx(1:3));
fprintf('\n(the closest centroids should be 1, 3, 2 respectively)\n');
fprintf('Program paused. Press enter to continue.\n');
pause;
%% ===================== Part 2: Compute Means =========================
% After implementing the closest centroids function, you should now
% complete the computeCentroids function.
%
fprintf('\nComputing centroids means.\n\n');
% Compute means based on the closest centroids found in the previous part.
centroids = computeCentroids(X, idx, K);
fprintf('Centroids computed after initial finding of closest centroids: \n')
fprintf(' %f %f \n' , centroids');
fprintf('\n(the centroids should be\n');
fprintf(' [ 2.428301 3.157924 ]\n');
fprintf(' [ 5.813503 2.633656 ]\n');
fprintf(' [ 7.119387 3.616684 ]\n\n');
fprintf('Program paused. Press enter to continue.\n');
pause;
%% =================== Part 3: K-Means Clustering ======================
% After you have completed the two functions computeCentroids and
% findClosestCentroids, you have all the necessary pieces to run the
% kMeans algorithm. In this part, you will run the K-Means algorithm on
% the example dataset we have provided.
%
fprintf('\nRunning K-Means clustering on example dataset.\n\n');
% Load an example dataset
load('ex7data2.mat');
% Settings for running K-Means
K = 3;
max_iters = 10;
% For consistency, here we set centroids to specific values
% but in practice you want to generate them automatically, such as by
% settings them to be random examples (as can be seen in
% kMeansInitCentroids).
initial_centroids = [3 3; 6 2; 8 5];
% Run K-Means algorithm. The 'true' at the end tells our function to plot
% the progress of K-Means
[centroids, idx] = runkMeans(X, initial_centroids, max_iters, true);
fprintf('\nK-Means Done.\n\n');
fprintf('Program paused. Press enter to continue.\n');
pause;
%% ============= Part 4: K-Means Clustering on Pixels ===============
% In this exercise, you will use K-Means to compress an image. To do this,
% you will first run K-Means on the colors of the pixels in the image and
% then you will map each pixel onto its closest centroid.
%
% You should now complete the code in kMeansInitCentroids.m
%
fprintf('\nRunning K-Means clustering on pixels from an image.\n\n');
% Load an image of a bird
A = double(imread('bird_small.png'));
% If imread does not work for you, you can try instead
% load ('bird_small.mat');
A = A / 255; % Divide by 255 so that all values are in the range 0 - 1
% Size of the image
img_size = size(A);
% Reshape the image into an Nx3 matrix where N = number of pixels.
% Each row will contain the Red, Green and Blue pixel values
% This gives us our dataset matrix X that we will use K-Means on.
X = reshape(A, img_size(1) * img_size(2), 3);
% Run your K-Means algorithm on this data
% You should try different values of K and max_iters here
K = 16;
max_iters = 10;
% When using K-Means, it is important the initialize the centroids
% randomly.
% You should complete the code in kMeansInitCentroids.m before proceeding
initial_centroids = kMeansInitCentroids(X, K);
% Run K-Means
[centroids, idx] = runkMeans(X, initial_centroids, max_iters);
fprintf('Program paused. Press enter to continue.\n');
pause;
%% ================= Part 5: Image Compression ======================
% In this part of the exercise, you will use the clusters of K-Means to
% compress an image. To do this, we first find the closest clusters for
% each example. After that, we
fprintf('\nApplying K-Means to compress an image.\n\n');
% Find closest cluster members
idx = findClosestCentroids(X, centroids);
% Essentially, now we have represented the image X as in terms of the
% indices in idx.
% We can now recover the image from the indices (idx) by mapping each pixel
% (specified by its index in idx) to the centroid value
X_recovered = centroids(idx,:);
% Reshape the recovered image into proper dimensions
X_recovered = reshape(X_recovered, img_size(1), img_size(2), 3);
% Display the original image
subplot(1, 2, 1);
imagesc(A);
title('Original');
% Display compressed image side by side
subplot(1, 2, 2);
imagesc(X_recovered)
title(sprintf('Compressed, with %d colors.', K));
fprintf('Program paused. Press enter to continue.\n');
pause;
%% Machine Learning Online Class
% Exercise 7 | Principle Component Analysis and K-Means Clustering
%
% Instructions
% ------------
%
% This file contains code that helps you get started on the
% exercise. You will need to complete the following functions:
%
% pca.m
% projectData.m
% recoverData.m
% computeCentroids.m
% findClosestCentroids.m
% kMeansInitCentroids.m
%
% For this exercise, you will not need to change any code in this file,
% or any other files other than those mentioned above.
%
%% Initialization
clear ; close all; clc
%% ================== Part 1: Load Example Dataset ===================
% We start this exercise by using a small dataset that is easily to
% visualize
%
fprintf('Visualizing example dataset for PCA.\n\n');
% The following command loads the dataset. You should now have the
% variable X in your environment
load ('ex7data1.mat');
% Visualize the example dataset
plot(X(:, 1), X(:, 2), 'bo');
axis([0.5 6.5 2 8]); axis square;
fprintf('Program paused. Press enter to continue.\n');
pause;
%% =============== Part 2: Principal Component Analysis ===============
% You should now implement PCA, a dimension reduction technique. You
% should complete the code in pca.m
%
fprintf('\nRunning PCA on example dataset.\n\n');
% Before running PCA, it is important to first normalize X
[X_norm, mu, sigma] = featureNormalize(X);
% Run PCA
[U, S] = pca(X_norm);
% Compute mu, the mean of the each feature
% Draw the eigenvectors centered at mean of data. These lines show the
% directions of maximum variations in the dataset.
hold on;
drawLine(mu, mu + 1.5 * S(1,1) * U(:,1)', '-k', 'LineWidth', 2);
drawLine(mu, mu + 1.5 * S(2,2) * U(:,2)', '-k', 'LineWidth', 2);
hold off;
fprintf('Top eigenvector: \n');
fprintf(' U(:,1) = %f %f \n', U(1,1), U(2,1));
fprintf('\n(you should expect to see -0.707107 -0.707107)\n');
fprintf('Program paused. Press enter to continue.\n');
pause;
%% =================== Part 3: Dimension Reduction ===================
% You should now implement the projection step to map the data onto the
% first k eigenvectors. The code will then plot the data in this reduced
% dimensional space. This will show you what the data looks like when
% using only the corresponding eigenvectors to reconstruct it.
%
% You should complete the code in projectData.m
%
fprintf('\nDimension reduction on example dataset.\n\n');
% Plot the normalized dataset (returned from pca)
plot(X_norm(:, 1), X_norm(:, 2), 'bo');
axis([-4 3 -4 3]); axis square
% Project the data onto K = 1 dimension
K = 1;
Z = projectData(X_norm, U, K);
fprintf('Projection of the first example: %f\n', Z(1));
fprintf('\n(this value should be about 1.481274)\n\n');
X_rec = recoverData(Z, U, K);
fprintf('Approximation of the first example: %f %f\n', X_rec(1, 1), X_rec(1, 2));
fprintf('\n(this value should be about -1.047419 -1.047419)\n\n');
% Draw lines connecting the projected points to the original points
hold on;
plot(X_rec(:, 1), X_rec(:, 2), 'ro');
for i = 1:size(X_norm, 1)
drawLine(X_norm(i,:), X_rec(i,:), '--k', 'LineWidth', 1);
end
hold off
fprintf('Program paused. Press enter to continue.\n');
pause;
%% =============== Part 4: Loading and Visualizing Face Data =============
% We start the exercise by first loading and visualizing the dataset.
% The following code will load the dataset into your environment
%
fprintf('\nLoading face dataset.\n\n');
% Load Face dataset
load ('ex7faces.mat')
% Display the first 100 faces in the dataset
displayData(X(1:100, :));
fprintf('Program paused. Press enter to continue.\n');
pause;
%% =========== Part 5: PCA on Face Data: Eigenfaces ===================
% Run PCA and visualize the eigenvectors which are in this case eigenfaces
% We display the first 36 eigenfaces.
%
fprintf(['\nRunning PCA on face dataset.\n' ...
'(this might take a minute or two ...)\n\n']);
% Before running PCA, it is important to first normalize X by subtracting
% the mean value from each feature
[X_norm, mu, sigma] = featureNormalize(X);
% Run PCA
[U, S] = pca(X_norm);
% Visualize the top 36 eigenvectors found
displayData(U(:, 1:36)');
fprintf('Program paused. Press enter to continue.\n');
pause;
%% ============= Part 6: Dimension Reduction for Faces =================
% Project images to the eigen space using the top k eigenvectors
% If you are applying a machine learning algorithm
fprintf('\nDimension reduction for face dataset.\n\n');
K = 100;
Z = projectData(X_norm, U, K);
fprintf('The projected data Z has a size of: ')
fprintf('%d ', size(Z));
fprintf('\n\nProgram paused. Press enter to continue.\n');
pause;
%% ==== Part 7: Visualization of Faces after PCA Dimension Reduction ====
% Project images to the eigen space using the top K eigen vectors and
% visualize only using those K dimensions
% Compare to the original input, which is also displayed
fprintf('\nVisualizing the projected (reduced dimension) faces.\n\n');
K = 100;
X_rec = recoverData(Z, U, K);
% Display normalized data
subplot(1, 2, 1);
displayData(X_norm(1:100,:));
title('Original faces');
axis square;
% Display reconstructed data from only k eigenfaces
subplot(1, 2, 2);
displayData(X_rec(1:100,:));
title('Recovered faces');
axis square;
fprintf('Program paused. Press enter to continue.\n');
pause;
%% === Part 8(a): Optional (ungraded) Exercise: PCA for Visualization ===
% One useful application of PCA is to use it to visualize high-dimensional
% data. In the last K-Means exercise you ran K-Means on 3-dimensional
% pixel colors of an image. We first visualize this output in 3D, and then
% apply PCA to obtain a visualization in 2D.
close all; close all; clc
% Reload the image from the previous exercise and run K-Means on it
% For this to work, you need to complete the K-Means assignment first
A = double(imread('bird_small.png'));
% If imread does not work for you, you can try instead
% load ('bird_small.mat');
A = A / 255;
img_size = size(A);
X = reshape(A, img_size(1) * img_size(2), 3);
K = 16;
max_iters = 10;
initial_centroids = kMeansInitCentroids(X, K);
[centroids, idx] = runkMeans(X, initial_centroids, max_iters);
% Sample 1000 random indexes (since working with all the data is
% too expensive. If you have a fast computer, you may increase this.
sel = floor(rand(1000, 1) * size(X, 1)) + 1;
% Setup Color Palette
palette = hsv(K);
colors = palette(idx(sel), :);
% Visualize the data and centroid memberships in 3D
figure;
scatter3(X(sel, 1), X(sel, 2), X(sel, 3), 10, colors);
title('Pixel dataset plotted in 3D. Color shows centroid memberships');
fprintf('Program paused. Press enter to continue.\n');
pause;
%% === Part 8(b): Optional (ungraded) Exercise: PCA for Visualization ===
% Use PCA to project this cloud to 2D for visualization
% Subtract the mean to use PCA
[X_norm, mu, sigma] = featureNormalize(X);
% PCA and project the data to 2D
[U, S] = pca(X_norm);
Z = projectData(X_norm, U, 2);
% Plot in 2D
figure;
plotDataPoints(Z(sel, :), idx(sel), K);
title('Pixel dataset plotted in 2D, using PCA for dimensionality reduction');
fprintf('Program paused. Press enter to continue.\n');
pause;
File added
File added
File added
function [X_norm, mu, sigma] = featureNormalize(X)
%FEATURENORMALIZE Normalizes the features in X
% FEATURENORMALIZE(X) returns a normalized version of X where
% the mean value of each feature is 0 and the standard deviation
% is 1. This is often a good preprocessing step to do when
% working with learning algorithms.
mu = mean(X);
X_norm = bsxfun(@minus, X, mu);
sigma = std(X_norm);
X_norm = bsxfun(@rdivide, X_norm, sigma);
% ============================================================
end
function idx = findClosestCentroids(X, centroids)
%FINDCLOSESTCENTROIDS computes the centroid memberships for every example
% idx = FINDCLOSESTCENTROIDS (X, centroids) returns the closest centroids
% in idx for a dataset X where each row is a single example. idx = m x 1
% vector of centroid assignments (i.e. each entry in range [1..K])
%
% Set K
K = size(centroids, 1);
% You need to return the following variables correctly.
idx = zeros(size(X,1), 1);
% ====================== YOUR CODE HERE ======================
% Instructions: Go over every example, find its closest centroid, and store
% the index inside idx at the appropriate location.
% Concretely, idx(i) should contain the index of the centroid
% closest to example i. Hence, it should be a value in the
% range 1..K
%
% Note: You can use a for-loop over the examples to compute this.
%
for i = 1:size(X,1),
[a idx(i)] = min(sum(((X(i,:) - centroids).*(X(i,:) - centroids)),2));
end;
% =============================================================
end
function centroids = kMeansInitCentroids(X, K)
%KMEANSINITCENTROIDS This function initializes K centroids that are to be
%used in K-Means on the dataset X
% centroids = KMEANSINITCENTROIDS(X, K) returns K initial centroids to be
% used with the K-Means on the dataset X
%
% You should return this values correctly
centroids = zeros(K, size(X, 2));
% ====================== YOUR CODE HERE ======================
% Instructions: You should set centroids to randomly chosen examples from
% the dataset X
%
randidx = randperm(size(X, 1));
% Take the first K examples as centroids
centroids = X(randidx(1:K), :);
% =============================================================
end
The author of "jsonlab" toolbox is Qianqian Fang. Qianqian
is currently an Assistant Professor at Massachusetts General Hospital,
Harvard Medical School.
Address: Martinos Center for Biomedical Imaging,
Massachusetts General Hospital,
Harvard Medical School
Bldg 149, 13th St, Charlestown, MA 02129, USA
URL: http://nmr.mgh.harvard.edu/~fangq/
Email: <fangq at nmr.mgh.harvard.edu> or <fangqq at gmail.com>
The script loadjson.m was built upon previous works by
- Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
date: 2009/11/02
- François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
date: 2009/03/22
- Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
date: 2008/07/03
This toolbox contains patches submitted by the following contributors:
- Blake Johnson <bjohnso at bbn.com>
part of revision 341
- Niclas Borlin <Niclas.Borlin at cs.umu.se>
various fixes in revision 394, including
- loadjson crashes for all-zero sparse matrix.
- loadjson crashes for empty sparse matrix.
- Non-zero size of 0-by-N and N-by-0 empty matrices is lost after savejson/loadjson.
- loadjson crashes for sparse real column vector.
- loadjson crashes for sparse complex column vector.
- Data is corrupted by savejson for sparse real row vector.
- savejson crashes for sparse complex row vector.
- Yul Kang <yul.kang.on at gmail.com>
patches for svn revision 415.
- savejson saves an empty cell array as [] instead of null
- loadjson differentiates an empty struct from an empty array
============================================================================
JSONlab - a toolbox to encode/decode JSON/UBJSON files in MATLAB/Octave
----------------------------------------------------------------------------
JSONlab ChangeLog (key features marked by *):
== JSONlab 1.0 (codename: Optimus - Final), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2015/01/02 polish help info for all major functions, update examples, finalize 1.0
2014/12/19 fix a bug to strictly respect NoRowBracket in savejson
== JSONlab 1.0.0-RC2 (codename: Optimus - RC2), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2014/11/22 show progress bar in loadjson ('ShowProgress')
2014/11/17 add Compact option in savejson to output compact JSON format ('Compact')
2014/11/17 add FastArrayParser in loadjson to specify fast parser applicable levels
2014/09/18 start official github mirror: https://github.com/fangq/jsonlab
== JSONlab 1.0.0-RC1 (codename: Optimus - RC1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2014/09/17 fix several compatibility issues when running on octave versions 3.2-3.8
2014/09/17 support 2D cell and struct arrays in both savejson and saveubjson
2014/08/04 escape special characters in a JSON string
2014/02/16 fix a bug when saving ubjson files
== JSONlab 0.9.9 (codename: Optimus - beta), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2014/01/22 use binary read and write in saveubjson and loadubjson
== JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2013/10/07 better round-trip conservation for empty arrays and structs (patch submitted by Yul Kang)
== JSONlab 0.9.8 (codename: Optimus - alpha), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson
== JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin)
== JSONlab 0.9.0 (codename: Rodimus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2012/06/17 *new format for an invalid leading char, unpacking hex code in savejson
2012/06/01 support JSONP in savejson
2012/05/25 fix the empty cell bug (reported by Cyril Davin)
2012/04/05 savejson can save to a file (suggested by Patrick Rapin)
== JSONlab 0.8.1 (codename: Sentiel, Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2012/02/28 loadjson quotation mark escape bug, see http://bit.ly/yyk1nS
2012/01/25 patch to handle root-less objects, contributed by Blake Johnson
== JSONlab 0.8.0 (codename: Sentiel), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab
2012/01/11 remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer
2011/12/22 *accept sequence of 'param',value input in savejson and loadjson
2011/11/18 fix struct array bug reported by Mykel Kochenderfer
== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2011/10/21 fix a bug in loadjson, previous code does not use any of the acceleration
2011/10/20 loadjson supports JSON collections - concatenated JSON objects
== JSONlab 0.5.0 (codename: Nexus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
2011/10/16 package and release jsonlab 0.5.0
2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug
2011/10/11 *speed up readjson dramatically, interpret _Array* tags, show data in root level
2011/10/10 create jsonlab project, start jsonlab website, add online documentation
2011/10/07 *speed up savejson by 25x using sprintf instead of mat2str, add options support
2011/10/06 *savejson works for structs, cells and arrays
2011/09/09 derive loadjson from JSON parser from MATLAB Central, draft savejson.m
Copyright 2011-2015 Qianqian Fang <fangq at nmr.mgh.harvard.edu>. 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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 THE COPYRIGHT HOLDERS
OR CONTRIBUTORS 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.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of the copyright holders.
===============================================================================
= JSONLab =
= An open-source MATLAB/Octave JSON encoder and decoder =
===============================================================================
*Copyright (C) 2011-2015 Qianqian Fang <fangq at nmr.mgh.harvard.edu>
*License: BSD License, see License_BSD.txt for details
*Version: 1.0 (Optimus - Final)
-------------------------------------------------------------------------------
Table of Content:
I. Introduction
II. Installation
III.Using JSONLab
IV. Known Issues and TODOs
V. Contribution and feedback
-------------------------------------------------------------------------------
I. Introduction
JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable,
human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format
to represent complex and hierarchical data. It is as powerful as
[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely
used for data-exchange in applications, and is essential for the wild success
of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and
[http://en.wikipedia.org/wiki/Web_2.0 Web2.0].
UBJSON (Universal Binary JSON) is a binary JSON format, specifically
optimized for compact file size and better performance while keeping
the semantics as simple as the text-based JSON format. Using the UBJSON
format allows to wrap complex binary data in a flexible and extensible
structure, making it possible to process complex and large dataset
without accuracy loss due to text conversions.
We envision that both JSON and its binary version will serve as part of
the mainstream data-exchange formats for scientific research in the future.
It will provide the flexibility and generality achieved by other popular
general-purpose file specifications, such as
[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly
reduced complexity and enhanced performance.
JSONLab is a free and open-source implementation of a JSON/UBJSON encoder
and a decoder in the native MATLAB language. It can be used to convert a MATLAB
data structure (array, struct, cell, struct array and cell array) into
JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB
data structure. JSONLab supports both MATLAB and
[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone).
-------------------------------------------------------------------------------
II. Installation
The installation of JSONLab is no different than any other simple
MATLAB toolbox. You only need to download/unzip the JSONLab package
to a folder, and add the folder's path to MATLAB/Octave's path list
by using the following command:
addpath('/path/to/jsonlab');
If you want to add this path permanently, you need to type "pathtool",
browse to the jsonlab root folder and add to the list, then click "Save".
Then, run "rehash" in MATLAB, and type "which loadjson", if you see an
output, that means JSONLab is installed for MATLAB/Octave.
-------------------------------------------------------------------------------
III.Using JSONLab
JSONLab provides two functions, loadjson.m -- a MATLAB->JSON decoder,
and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and
two equivallent functions -- loadubjson and saveubjson for the binary
JSON. The detailed help info for the four functions can be found below:
=== loadjson.m ===
<pre>
data=loadjson(fname,opt)
or
data=loadjson(fname,'param1',value1,'param2',value2,...)
parse a JSON (JavaScript Object Notation) file or string
authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
created on 2011/09/09, including previous works from
Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
created on 2009/11/02
François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
created on 2009/03/22
Joel Feenstra:
http://www.mathworks.com/matlabcentral/fileexchange/20565
created on 2008/07/03
$Id: loadjson.m 452 2014-11-22 16:43:33Z fangq $
input:
fname: input file name, if fname contains "{}" or "[]", fname
will be interpreted as a JSON string
opt: a struct to store parsing options, opt can be replaced by
a list of ('param',value) pairs - the param string is equivallent
to a field in opt. opt can have the following
fields (first in [.|.] is the default)
opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
for each element of the JSON data, and group
arrays based on the cell2mat rules.
opt.FastArrayParser [1|0 or integer]: if set to 1, use a
speed-optimized array parser when loading an
array object. The fast array parser may
collapse block arrays into a single large
array similar to rules defined in cell2mat; 0 to
use a legacy parser; if set to a larger-than-1
value, this option will specify the minimum
dimension to enable the fast array parser. For
example, if the input is a 3D array, setting
FastArrayParser to 1 will return a 3D array;
setting to 2 will return a cell array of 2D
arrays; setting to 3 will return to a 2D cell
array of 1D vectors; setting to 4 will return a
3D cell array.
opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
output:
dat: a cell array, where {...} blocks are converted into cell arrays,
and [...] are converted to arrays
examples:
dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
dat=loadjson(['examples' filesep 'example1.json'])
dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
</pre>
=== savejson.m ===
<pre>
json=savejson(rootname,obj,filename)
or
json=savejson(rootname,obj,opt)
json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
Object Notation) string
author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
created on 2011/09/09
$Id: savejson.m 458 2014-12-19 22:17:17Z fangq $
input:
rootname: the name of the root-object, when set to '', the root name
is ignored, however, when opt.ForceRootName is set to 1 (see below),
the MATLAB variable name will be used as the root name.
obj: a MATLAB object (array, cell, cell array, struct, struct array).
filename: a string for the file name to save the output JSON data.
opt: a struct for additional options, ignore to use default values.
opt can have the following fields (first in [.|.] is the default)
opt.FileName [''|string]: a file name to save the output JSON data
opt.FloatFormat ['%.10g'|string]: format to show each numeric element
of a 1D/2D array;
opt.ArrayIndent [1|0]: if 1, output explicit data array with
precedent indentation; if 0, no indentation
opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
array in JSON array format; if sets to 1, an
array will be shown as a struct with fields
"_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
sparse arrays, the non-zero elements will be
saved to _ArrayData_ field in triplet-format i.e.
(ix,iy,val) and "_ArrayIsSparse_" will be added
with a value of 1; for a complex array, the
_ArrayData_ array will include two columns
(4 for sparse) to record the real and imaginary
parts, and also "_ArrayIsComplex_":1 is added.
opt.ParseLogical [0|1]: if this is set to 1, logical array elem
will use true/false rather than 1/0.
opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
numerical element will be shown without a square
bracket, unless it is the root object; if 0, square
brackets are forced for any numerical arrays.
opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
will use the name of the passed obj variable as the
root object name; if obj is an expression and
does not have a name, 'root' will be used; if this
is set to 0 and rootname is empty, the root level
will be merged down to the lower level.
opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
to represent +/-Inf. The matched pattern is '([-+]*)Inf'
and $1 represents the sign. For those who want to use
1e999 to represent Inf, they can set opt.Inf to '$11e999'
opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
to represent NaN
opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
for example, if opt.JSONP='foo', the JSON data is
wrapped inside a function call as 'foo(...);'
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
back to the string form
opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
opt can be replaced by a list of ('param',value) pairs. The param
string is equivallent to a field in opt and is case sensitive.
output:
json: a string in the JSON format (see http://json.org)
examples:
jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
'MeshCreator','FangQ','MeshTitle','T6 Cube',...
'SpecialData',[nan, inf, -inf]);
savejson('jmesh',jsonmesh)
savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
</pre>
=== loadubjson.m ===
<pre>
data=loadubjson(fname,opt)
or
data=loadubjson(fname,'param1',value1,'param2',value2,...)
parse a JSON (JavaScript Object Notation) file or string
authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
created on 2013/08/01
$Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
input:
fname: input file name, if fname contains "{}" or "[]", fname
will be interpreted as a UBJSON string
opt: a struct to store parsing options, opt can be replaced by
a list of ('param',value) pairs - the param string is equivallent
to a field in opt. opt can have the following
fields (first in [.|.] is the default)
opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
for each element of the JSON data, and group
arrays based on the cell2mat rules.
opt.IntEndian [B|L]: specify the endianness of the integer fields
in the UBJSON input data. B - Big-Endian format for
integers (as required in the UBJSON specification);
L - input integer fields are in Little-Endian order.
output:
dat: a cell array, where {...} blocks are converted into cell arrays,
and [...] are converted to arrays
examples:
obj=struct('string','value','array',[1 2 3]);
ubjdata=saveubjson('obj',obj);
dat=loadubjson(ubjdata)
dat=loadubjson(['examples' filesep 'example1.ubj'])
dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
</pre>
=== saveubjson.m ===
<pre>
json=saveubjson(rootname,obj,filename)
or
json=saveubjson(rootname,obj,opt)
json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
convert a MATLAB object (cell, struct or array) into a Universal
Binary JSON (UBJSON) binary string
author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
created on 2013/08/17
$Id: saveubjson.m 440 2014-09-17 19:59:45Z fangq $
input:
rootname: the name of the root-object, when set to '', the root name
is ignored, however, when opt.ForceRootName is set to 1 (see below),
the MATLAB variable name will be used as the root name.
obj: a MATLAB object (array, cell, cell array, struct, struct array)
filename: a string for the file name to save the output UBJSON data
opt: a struct for additional options, ignore to use default values.
opt can have the following fields (first in [.|.] is the default)
opt.FileName [''|string]: a file name to save the output JSON data
opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
array in JSON array format; if sets to 1, an
array will be shown as a struct with fields
"_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
sparse arrays, the non-zero elements will be
saved to _ArrayData_ field in triplet-format i.e.
(ix,iy,val) and "_ArrayIsSparse_" will be added
with a value of 1; for a complex array, the
_ArrayData_ array will include two columns
(4 for sparse) to record the real and imaginary
parts, and also "_ArrayIsComplex_":1 is added.
opt.ParseLogical [1|0]: if this is set to 1, logical array elem
will use true/false rather than 1/0.
opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
numerical element will be shown without a square
bracket, unless it is the root object; if 0, square
brackets are forced for any numerical arrays.
opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
will use the name of the passed obj variable as the
root object name; if obj is an expression and
does not have a name, 'root' will be used; if this
is set to 0 and rootname is empty, the root level
will be merged down to the lower level.
opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
for example, if opt.JSON='foo', the JSON data is
wrapped inside a function call as 'foo(...);'
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
back to the string form
opt can be replaced by a list of ('param',value) pairs. The param
string is equivallent to a field in opt and is case sensitive.
output:
json: a binary string in the UBJSON format (see http://ubjson.org)
examples:
jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
'MeshCreator','FangQ','MeshTitle','T6 Cube',...
'SpecialData',[nan, inf, -inf]);
saveubjson('jsonmesh',jsonmesh)
saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
</pre>
=== examples ===
Under the "examples" folder, you can find several scripts to demonstrate the
basic utilities of JSONLab. Running the "demo_jsonlab_basic.m" script, you
will see the conversions from MATLAB data structure to JSON text and backward.
In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet
and validate the loadjson/savejson functions for regression testing purposes.
Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson
and loadubjson pairs for various matlab data structures.
Please run these examples and understand how JSONLab works before you use
it to process your data.
-------------------------------------------------------------------------------
IV. Known Issues and TODOs
JSONLab has several known limitations. We are striving to make it more general
and robust. Hopefully in a few future releases, the limitations become less.
Here are the known issues:
# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays;
# When processing names containing multi-byte characters, Octave and MATLAB \
can give different field-names; you can use feature('DefaultCharacterSet','latin1') \
in MATLAB to get consistant results
# savejson can not handle class and dataset.
# saveubjson converts a logical array into a uint8 ([U]) array
# an unofficial N-D array count syntax is implemented in saveubjson. We are \
actively communicating with the UBJSON spec maintainer to investigate the \
possibility of making it upstream
# loadubjson can not parse all UBJSON Specification (Draft 9) compliant \
files, however, it can parse all UBJSON files produced by saveubjson.
-------------------------------------------------------------------------------
V. Contribution and feedback
JSONLab is an open-source project. This means you can not only use it and modify
it as you wish, but also you can contribute your changes back to JSONLab so
that everyone else can enjoy the improvement. For anyone who want to contribute,
please download JSONLab source code from it's subversion repository by using the
following command:
svn checkout svn://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab jsonlab
You can make changes to the files as needed. Once you are satisfied with your
changes, and ready to share it with others, please cd the root directory of
JSONLab, and type
svn diff > yourname_featurename.patch
You then email the .patch file to JSONLab's maintainer, Qianqian Fang, at
the email address shown in the beginning of this file. Qianqian will review
the changes and commit it to the subversion if they are satisfactory.
We appreciate any suggestions and feedbacks from you. Please use iso2mesh's
mailing list to report any questions you may have with JSONLab:
http://groups.google.com/group/iso2mesh-users?hl=en&pli=1
(Subscription to the mailing list is needed in order to post messages).
function val=jsonopt(key,default,varargin)
%
% val=jsonopt(key,default,optstruct)
%
% setting options based on a struct. The struct can be produced
% by varargin2struct from a list of 'param','value' pairs
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
%
% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $
%
% input:
% key: a string with which one look up a value from a struct
% default: if the key does not exist, return default
% optstruct: a struct where each sub-field is a key
%
% output:
% val: if key exists, val=optstruct.key; otherwise val=default
%
% license:
% BSD, see LICENSE_BSD.txt files for details
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
val=default;
if(nargin<=2) return; end
opt=varargin{1};
if(isstruct(opt) && isfield(opt,key))
val=getfield(opt,key);
end
function data = loadjson(fname,varargin)
%
% data=loadjson(fname,opt)
% or
% data=loadjson(fname,'param1',value1,'param2',value2,...)
%
% parse a JSON (JavaScript Object Notation) file or string
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% created on 2011/09/09, including previous works from
%
% Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
% created on 2009/11/02
% François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
% created on 2009/03/22
% Joel Feenstra:
% http://www.mathworks.com/matlabcentral/fileexchange/20565
% created on 2008/07/03
%
% $Id: loadjson.m 460 2015-01-03 00:30:45Z fangq $
%
% input:
% fname: input file name, if fname contains "{}" or "[]", fname
% will be interpreted as a JSON string
% opt: a struct to store parsing options, opt can be replaced by
% a list of ('param',value) pairs - the param string is equivallent
% to a field in opt. opt can have the following
% fields (first in [.|.] is the default)
%
% opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
% for each element of the JSON data, and group
% arrays based on the cell2mat rules.
% opt.FastArrayParser [1|0 or integer]: if set to 1, use a
% speed-optimized array parser when loading an
% array object. The fast array parser may
% collapse block arrays into a single large
% array similar to rules defined in cell2mat; 0 to
% use a legacy parser; if set to a larger-than-1
% value, this option will specify the minimum
% dimension to enable the fast array parser. For
% example, if the input is a 3D array, setting
% FastArrayParser to 1 will return a 3D array;
% setting to 2 will return a cell array of 2D
% arrays; setting to 3 will return to a 2D cell
% array of 1D vectors; setting to 4 will return a
% 3D cell array.
% opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
%
% output:
% dat: a cell array, where {...} blocks are converted into cell arrays,
% and [...] are converted to arrays
%
% examples:
% dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
% dat=loadjson(['examples' filesep 'example1.json'])
% dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
%
% license:
% BSD, see LICENSE_BSD.txt files for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
global pos inStr len esc index_esc len_esc isoct arraytoken
if(regexp(fname,'[\{\}\]\[]','once'))
string=fname;
elseif(exist(fname,'file'))
fid = fopen(fname,'rb');
string = fread(fid,inf,'uint8=>char')';
fclose(fid);
else
error('input file does not exist');
end
pos = 1; len = length(string); inStr = string;
isoct=exist('OCTAVE_VERSION','builtin');
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
jstr=regexprep(inStr,'\\\\',' ');
escquote=regexp(jstr,'\\"');
arraytoken=sort([arraytoken escquote]);
% String delimiters and escape chars identified to improve speed:
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
index_esc = 1; len_esc = length(esc);
opt=varargin2struct(varargin{:});
if(jsonopt('ShowProgress',0,opt)==1)
opt.progressbar_=waitbar(0,'loading ...');
end
jsoncount=1;
while pos <= len
switch(next_char)
case '{'
data{jsoncount} = parse_object(opt);
case '['
data{jsoncount} = parse_array(opt);
otherwise
error_pos('Outer level structure must be an object or an array');
end
jsoncount=jsoncount+1;
end % while
jsoncount=length(data);
if(jsoncount==1 && iscell(data))
data=data{1};
end
if(~isempty(data))
if(isstruct(data)) % data can be a struct array
data=jstruct2array(data);
elseif(iscell(data))
data=jcell2array(data);
end
end
if(isfield(opt,'progressbar_'))
close(opt.progressbar_);
end
%%
function newdata=jcell2array(data)
len=length(data);
newdata=data;
for i=1:len
if(isstruct(data{i}))
newdata{i}=jstruct2array(data{i});
elseif(iscell(data{i}))
newdata{i}=jcell2array(data{i});
end
end
%%-------------------------------------------------------------------------
function newdata=jstruct2array(data)
fn=fieldnames(data);
newdata=data;
len=length(data);
for i=1:length(fn) % depth-first
for j=1:len
if(isstruct(getfield(data(j),fn{i})))
newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
end
end
end
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
newdata=cell(len,1);
for j=1:len
ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
iscpx=0;
if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
if(data(j).x0x5F_ArrayIsComplex_)
iscpx=1;
end
end
if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
if(data(j).x0x5F_ArrayIsSparse_)
if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
dim=data(j).x0x5F_ArraySize_;
if(iscpx && size(ndata,2)==4-any(dim==1))
ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
end
if isempty(ndata)
% All-zeros sparse
ndata=sparse(dim(1),prod(dim(2:end)));
elseif dim(1)==1
% Sparse row vector
ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
elseif dim(2)==1
% Sparse column vector
ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
else
% Generic sparse array.
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
end
else
if(iscpx && size(ndata,2)==4)
ndata(:,3)=complex(ndata(:,3),ndata(:,4));
end
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
end
end
elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
if(iscpx && size(ndata,2)==2)
ndata=complex(ndata(:,1),ndata(:,2));
end
ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
end
newdata{j}=ndata;
end
if(len==1)
newdata=newdata{1};
end
end
%%-------------------------------------------------------------------------
function object = parse_object(varargin)
parse_char('{');
object = [];
if next_char ~= '}'
while 1
str = parseStr(varargin{:});
if isempty(str)
error_pos('Name of value at position %d cannot be empty');
end
parse_char(':');
val = parse_value(varargin{:});
eval( sprintf( 'object.%s = val;', valid_field(str) ) );
if next_char == '}'
break;
end
parse_char(',');
end
end
parse_char('}');
%%-------------------------------------------------------------------------
function object = parse_array(varargin) % JSON array is written in row-major order
global pos inStr isoct
parse_char('[');
object = cell(0, 1);
dim2=[];
arraydepth=jsonopt('JSONLAB_ArrayDepth_',1,varargin{:});
pbar=jsonopt('progressbar_',-1,varargin{:});
if next_char ~= ']'
if(jsonopt('FastArrayParser',1,varargin{:})>=1 && arraydepth>=jsonopt('FastArrayParser',1,varargin{:}))
[endpos, e1l, e1r, maxlevel]=matching_bracket(inStr,pos);
arraystr=['[' inStr(pos:endpos)];
arraystr=regexprep(arraystr,'"_NaN_"','NaN');
arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
arraystr(arraystr==sprintf('\n'))=[];
arraystr(arraystr==sprintf('\r'))=[];
%arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
astr=inStr((e1l+1):(e1r-1));
astr=regexprep(astr,'"_NaN_"','NaN');
astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
astr(astr==sprintf('\n'))=[];
astr(astr==sprintf('\r'))=[];
astr(astr==' ')='';
if(isempty(find(astr=='[', 1))) % array is 2D
dim2=length(sscanf(astr,'%f,',[1 inf]));
end
else % array is 1D
astr=arraystr(2:end-1);
astr(astr==' ')='';
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
if(nextidx>=length(astr)-1)
object=obj;
pos=endpos;
parse_char(']');
return;
end
end
if(~isempty(dim2))
astr=arraystr;
astr(astr=='[')='';
astr(astr==']')='';
astr(astr==' ')='';
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
if(nextidx>=length(astr)-1)
object=reshape(obj,dim2,numel(obj)/dim2)';
pos=endpos;
parse_char(']');
if(pbar>0)
waitbar(pos/length(inStr),pbar,'loading ...');
end
return;
end
end
arraystr=regexprep(arraystr,'\]\s*,','];');
else
arraystr='[';
end
try
if(isoct && regexp(arraystr,'"','once'))
error('Octave eval can produce empty cells for JSON-like input');
end
object=eval(arraystr);
pos=endpos;
catch
while 1
newopt=varargin2struct(varargin{:},'JSONLAB_ArrayDepth_',arraydepth+1);
val = parse_value(newopt);
object{end+1} = val;
if next_char == ']'
break;
end
parse_char(',');
end
end
end
if(jsonopt('SimplifyCell',0,varargin{:})==1)
try
oldobj=object;
object=cell2mat(object')';
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
object=oldobj;
elseif(size(object,1)>1 && ndims(object)==2)
object=object';
end
catch
end
end
parse_char(']');
if(pbar>0)
waitbar(pos/length(inStr),pbar,'loading ...');
end
%%-------------------------------------------------------------------------
function parse_char(c)
global pos inStr len
skip_whitespace;
if pos > len || inStr(pos) ~= c
error_pos(sprintf('Expected %c at position %%d', c));
else
pos = pos + 1;
skip_whitespace;
end
%%-------------------------------------------------------------------------
function c = next_char
global pos inStr len
skip_whitespace;
if pos > len
c = [];
else
c = inStr(pos);
end
%%-------------------------------------------------------------------------
function skip_whitespace
global pos inStr len
while pos <= len && isspace(inStr(pos))
pos = pos + 1;
end
%%-------------------------------------------------------------------------
function str = parseStr(varargin)
global pos inStr len esc index_esc len_esc
% len, ns = length(inStr), keyboard
if inStr(pos) ~= '"'
error_pos('String starting with " expected at position %d');
else
pos = pos + 1;
end
str = '';
while pos <= len
while index_esc <= len_esc && esc(index_esc) < pos
index_esc = index_esc + 1;
end
if index_esc > len_esc
str = [str inStr(pos:len)];
pos = len + 1;
break;
else
str = [str inStr(pos:esc(index_esc)-1)];
pos = esc(index_esc);
end
nstr = length(str); switch inStr(pos)
case '"'
pos = pos + 1;
if(~isempty(str))
if(strcmp(str,'_Inf_'))
str=Inf;
elseif(strcmp(str,'-_Inf_'))
str=-Inf;
elseif(strcmp(str,'_NaN_'))
str=NaN;
end
end
return;
case '\'
if pos+1 > len
error_pos('End of file reached right after escape character');
end
pos = pos + 1;
switch inStr(pos)
case {'"' '\' '/'}
str(nstr+1) = inStr(pos);
pos = pos + 1;
case {'b' 'f' 'n' 'r' 't'}
str(nstr+1) = sprintf(['\' inStr(pos)]);
pos = pos + 1;
case 'u'
if pos+4 > len
error_pos('End of file reached in escaped unicode character');
end
str(nstr+(1:6)) = inStr(pos-1:pos+4);
pos = pos + 5;
end
otherwise % should never happen
str(nstr+1) = inStr(pos), keyboard
pos = pos + 1;
end
end
error_pos('End of file while expecting end of inStr');
%%-------------------------------------------------------------------------
function num = parse_number(varargin)
global pos inStr len isoct
currstr=inStr(pos:end);
numstr=0;
if(isoct~=0)
numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
[num, one] = sscanf(currstr, '%f', 1);
delta=numstr+1;
else
[num, one, err, delta] = sscanf(currstr, '%f', 1);
if ~isempty(err)
error_pos('Error reading number at position %d');
end
end
pos = pos + delta-1;
%%-------------------------------------------------------------------------
function val = parse_value(varargin)
global pos inStr len
true = 1; false = 0;
pbar=jsonopt('progressbar_',-1,varargin{:});
if(pbar>0)
waitbar(pos/len,pbar,'loading ...');
end
switch(inStr(pos))
case '"'
val = parseStr(varargin{:});
return;
case '['
val = parse_array(varargin{:});
return;
case '{'
val = parse_object(varargin{:});
if isstruct(val)
if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
val=jstruct2array(val);
end
elseif isempty(val)
val = struct;
end
return;
case {'-','0','1','2','3','4','5','6','7','8','9'}
val = parse_number(varargin{:});
return;
case 't'
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
val = true;
pos = pos + 4;
return;
end
case 'f'
if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
val = false;
pos = pos + 5;
return;
end
case 'n'
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
val = [];
pos = pos + 4;
return;
end
end
error_pos('Value expected at position %d');
%%-------------------------------------------------------------------------
function error_pos(msg)
global pos inStr len
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
if poShow(3) == poShow(2)
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
end
msg = [sprintf(msg, pos) ': ' ...
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
error( ['JSONparser:invalidFormat: ' msg] );
%%-------------------------------------------------------------------------
function str = valid_field(str)
global isoct
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "x0x[Hex code]_" will be added if the first character is not a letter.
pos=regexp(str,'^[^A-Za-z]','once');
if(~isempty(pos))
if(~isoct)
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
else
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
end
end
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end
if(~isoct)
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
else
pos=regexp(str,'[^0-9A-Za-z_]');
if(isempty(pos)) return; end
str0=str;
pos0=[0 pos(:)' length(str)];
str='';
for i=1:length(pos)
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
end
if(pos(end)~=length(str))
str=[str str0(pos0(end-1)+1:pos0(end))];
end
end
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
%%-------------------------------------------------------------------------
function endpos = matching_quote(str,pos)
len=length(str);
while(pos<len)
if(str(pos)=='"')
if(~(pos>1 && str(pos-1)=='\'))
endpos=pos;
return;
end
end
pos=pos+1;
end
error('unmatched quotation mark');
%%-------------------------------------------------------------------------
function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
global arraytoken
level=1;
maxlevel=level;
endpos=0;
bpos=arraytoken(arraytoken>=pos);
tokens=str(bpos);
len=length(tokens);
pos=1;
e1l=[];
e1r=[];
while(pos<=len)
c=tokens(pos);
if(c==']')
level=level-1;
if(isempty(e1r)) e1r=bpos(pos); end
if(level==0)
endpos=bpos(pos);
return
end
end
if(c=='[')
if(isempty(e1l)) e1l=bpos(pos); end
level=level+1;
maxlevel=max(maxlevel,level);
end
if(c=='"')
pos=matching_quote(tokens,pos+1);
end
pos=pos+1;
end
if(endpos==0)
error('unmatched "]"');
end
function data = loadubjson(fname,varargin)
%
% data=loadubjson(fname,opt)
% or
% data=loadubjson(fname,'param1',value1,'param2',value2,...)
%
% parse a JSON (JavaScript Object Notation) file or string
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% created on 2013/08/01
%
% $Id: loadubjson.m 460 2015-01-03 00:30:45Z fangq $
%
% input:
% fname: input file name, if fname contains "{}" or "[]", fname
% will be interpreted as a UBJSON string
% opt: a struct to store parsing options, opt can be replaced by
% a list of ('param',value) pairs - the param string is equivallent
% to a field in opt. opt can have the following
% fields (first in [.|.] is the default)
%
% opt.SimplifyCell [0|1]: if set to 1, loadubjson will call cell2mat
% for each element of the JSON data, and group
% arrays based on the cell2mat rules.
% opt.IntEndian [B|L]: specify the endianness of the integer fields
% in the UBJSON input data. B - Big-Endian format for
% integers (as required in the UBJSON specification);
% L - input integer fields are in Little-Endian order.
%
% output:
% dat: a cell array, where {...} blocks are converted into cell arrays,
% and [...] are converted to arrays
%
% examples:
% obj=struct('string','value','array',[1 2 3]);
% ubjdata=saveubjson('obj',obj);
% dat=loadubjson(ubjdata)
% dat=loadubjson(['examples' filesep 'example1.ubj'])
% dat=loadubjson(['examples' filesep 'example1.ubj'],'SimplifyCell',1)
%
% license:
% BSD, see LICENSE_BSD.txt files for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
global pos inStr len esc index_esc len_esc isoct arraytoken fileendian systemendian
if(regexp(fname,'[\{\}\]\[]','once'))
string=fname;
elseif(exist(fname,'file'))
fid = fopen(fname,'rb');
string = fread(fid,inf,'uint8=>char')';
fclose(fid);
else
error('input file does not exist');
end
pos = 1; len = length(string); inStr = string;
isoct=exist('OCTAVE_VERSION','builtin');
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
jstr=regexprep(inStr,'\\\\',' ');
escquote=regexp(jstr,'\\"');
arraytoken=sort([arraytoken escquote]);
% String delimiters and escape chars identified to improve speed:
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
index_esc = 1; len_esc = length(esc);
opt=varargin2struct(varargin{:});
fileendian=upper(jsonopt('IntEndian','B',opt));
[os,maxelem,systemendian]=computer;
jsoncount=1;
while pos <= len
switch(next_char)
case '{'
data{jsoncount} = parse_object(opt);
case '['
data{jsoncount} = parse_array(opt);
otherwise
error_pos('Outer level structure must be an object or an array');
end
jsoncount=jsoncount+1;
end % while
jsoncount=length(data);
if(jsoncount==1 && iscell(data))
data=data{1};
end
if(~isempty(data))
if(isstruct(data)) % data can be a struct array
data=jstruct2array(data);
elseif(iscell(data))
data=jcell2array(data);
end
end
%%
function newdata=parse_collection(id,data,obj)
if(jsoncount>0 && exist('data','var'))
if(~iscell(data))
newdata=cell(1);
newdata{1}=data;
data=newdata;
end
end
%%
function newdata=jcell2array(data)
len=length(data);
newdata=data;
for i=1:len
if(isstruct(data{i}))
newdata{i}=jstruct2array(data{i});
elseif(iscell(data{i}))
newdata{i}=jcell2array(data{i});
end
end
%%-------------------------------------------------------------------------
function newdata=jstruct2array(data)
fn=fieldnames(data);
newdata=data;
len=length(data);
for i=1:length(fn) % depth-first
for j=1:len
if(isstruct(getfield(data(j),fn{i})))
newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
end
end
end
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
newdata=cell(len,1);
for j=1:len
ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
iscpx=0;
if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
if(data(j).x0x5F_ArrayIsComplex_)
iscpx=1;
end
end
if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
if(data(j).x0x5F_ArrayIsSparse_)
if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
dim=double(data(j).x0x5F_ArraySize_);
if(iscpx && size(ndata,2)==4-any(dim==1))
ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
end
if isempty(ndata)
% All-zeros sparse
ndata=sparse(dim(1),prod(dim(2:end)));
elseif dim(1)==1
% Sparse row vector
ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
elseif dim(2)==1
% Sparse column vector
ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
else
% Generic sparse array.
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
end
else
if(iscpx && size(ndata,2)==4)
ndata(:,3)=complex(ndata(:,3),ndata(:,4));
end
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
end
end
elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
if(iscpx && size(ndata,2)==2)
ndata=complex(ndata(:,1),ndata(:,2));
end
ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
end
newdata{j}=ndata;
end
if(len==1)
newdata=newdata{1};
end
end
%%-------------------------------------------------------------------------
function object = parse_object(varargin)
parse_char('{');
object = [];
type='';
count=-1;
if(next_char == '$')
type=inStr(pos+1); % TODO
pos=pos+2;
end
if(next_char == '#')
pos=pos+1;
count=double(parse_number());
end
if next_char ~= '}'
num=0;
while 1
str = parseStr(varargin{:});
if isempty(str)
error_pos('Name of value at position %d cannot be empty');
end
%parse_char(':');
val = parse_value(varargin{:});
num=num+1;
eval( sprintf( 'object.%s = val;', valid_field(str) ) );
if next_char == '}' || (count>=0 && num>=count)
break;
end
%parse_char(',');
end
end
if(count==-1)
parse_char('}');
end
%%-------------------------------------------------------------------------
function [cid,len]=elem_info(type)
id=strfind('iUIlLdD',type);
dataclass={'int8','uint8','int16','int32','int64','single','double'};
bytelen=[1,1,2,4,8,4,8];
if(id>0)
cid=dataclass{id};
len=bytelen(id);
else
error_pos('unsupported type at position %d');
end
%%-------------------------------------------------------------------------
function [data adv]=parse_block(type,count,varargin)
global pos inStr isoct fileendian systemendian
[cid,len]=elem_info(type);
datastr=inStr(pos:pos+len*count-1);
if(isoct)
newdata=int8(datastr);
else
newdata=uint8(datastr);
end
id=strfind('iUIlLdD',type);
if(id<=5 && fileendian~=systemendian)
newdata=swapbytes(typecast(newdata,cid));
end
data=typecast(newdata,cid);
adv=double(len*count);
%%-------------------------------------------------------------------------
function object = parse_array(varargin) % JSON array is written in row-major order
global pos inStr isoct
parse_char('[');
object = cell(0, 1);
dim=[];
type='';
count=-1;
if(next_char == '$')
type=inStr(pos+1);
pos=pos+2;
end
if(next_char == '#')
pos=pos+1;
if(next_char=='[')
dim=parse_array(varargin{:});
count=prod(double(dim));
else
count=double(parse_number());
end
end
if(~isempty(type))
if(count>=0)
[object adv]=parse_block(type,count,varargin{:});
if(~isempty(dim))
object=reshape(object,dim);
end
pos=pos+adv;
return;
else
endpos=matching_bracket(inStr,pos);
[cid,len]=elem_info(type);
count=(endpos-pos)/len;
[object adv]=parse_block(type,count,varargin{:});
pos=pos+adv;
parse_char(']');
return;
end
end
if next_char ~= ']'
while 1
val = parse_value(varargin{:});
object{end+1} = val;
if next_char == ']'
break;
end
%parse_char(',');
end
end
if(jsonopt('SimplifyCell',0,varargin{:})==1)
try
oldobj=object;
object=cell2mat(object')';
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
object=oldobj;
elseif(size(object,1)>1 && ndims(object)==2)
object=object';
end
catch
end
end
if(count==-1)
parse_char(']');
end
%%-------------------------------------------------------------------------
function parse_char(c)
global pos inStr len
skip_whitespace;
if pos > len || inStr(pos) ~= c
error_pos(sprintf('Expected %c at position %%d', c));
else
pos = pos + 1;
skip_whitespace;
end
%%-------------------------------------------------------------------------
function c = next_char
global pos inStr len
skip_whitespace;
if pos > len
c = [];
else
c = inStr(pos);
end
%%-------------------------------------------------------------------------
function skip_whitespace
global pos inStr len
while pos <= len && isspace(inStr(pos))
pos = pos + 1;
end
%%-------------------------------------------------------------------------
function str = parseStr(varargin)
global pos inStr esc index_esc len_esc
% len, ns = length(inStr), keyboard
type=inStr(pos);
if type ~= 'S' && type ~= 'C' && type ~= 'H'
error_pos('String starting with S expected at position %d');
else
pos = pos + 1;
end
if(type == 'C')
str=inStr(pos);
pos=pos+1;
return;
end
bytelen=double(parse_number());
if(length(inStr)>=pos+bytelen-1)
str=inStr(pos:pos+bytelen-1);
pos=pos+bytelen;
else
error_pos('End of file while expecting end of inStr');
end
%%-------------------------------------------------------------------------
function num = parse_number(varargin)
global pos inStr len isoct fileendian systemendian
id=strfind('iUIlLdD',inStr(pos));
if(isempty(id))
error_pos('expecting a number at position %d');
end
type={'int8','uint8','int16','int32','int64','single','double'};
bytelen=[1,1,2,4,8,4,8];
datastr=inStr(pos+1:pos+bytelen(id));
if(isoct)
newdata=int8(datastr);
else
newdata=uint8(datastr);
end
if(id<=5 && fileendian~=systemendian)
newdata=swapbytes(typecast(newdata,type{id}));
end
num=typecast(newdata,type{id});
pos = pos + bytelen(id)+1;
%%-------------------------------------------------------------------------
function val = parse_value(varargin)
global pos inStr len
true = 1; false = 0;
switch(inStr(pos))
case {'S','C','H'}
val = parseStr(varargin{:});
return;
case '['
val = parse_array(varargin{:});
return;
case '{'
val = parse_object(varargin{:});
if isstruct(val)
if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
val=jstruct2array(val);
end
elseif isempty(val)
val = struct;
end
return;
case {'i','U','I','l','L','d','D'}
val = parse_number(varargin{:});
return;
case 'T'
val = true;
pos = pos + 1;
return;
case 'F'
val = false;
pos = pos + 1;
return;
case {'Z','N'}
val = [];
pos = pos + 1;
return;
end
error_pos('Value expected at position %d');
%%-------------------------------------------------------------------------
function error_pos(msg)
global pos inStr len
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
if poShow(3) == poShow(2)
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
end
msg = [sprintf(msg, pos) ': ' ...
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
error( ['JSONparser:invalidFormat: ' msg] );
%%-------------------------------------------------------------------------
function str = valid_field(str)
global isoct
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "x0x[Hex code]_" will be added if the first character is not a letter.
pos=regexp(str,'^[^A-Za-z]','once');
if(~isempty(pos))
if(~isoct)
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
else
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
end
end
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end
if(~isoct)
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
else
pos=regexp(str,'[^0-9A-Za-z_]');
if(isempty(pos)) return; end
str0=str;
pos0=[0 pos(:)' length(str)];
str='';
for i=1:length(pos)
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
end
if(pos(end)~=length(str))
str=[str str0(pos0(end-1)+1:pos0(end))];
end
end
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
%%-------------------------------------------------------------------------
function endpos = matching_quote(str,pos)
len=length(str);
while(pos<len)
if(str(pos)=='"')
if(~(pos>1 && str(pos-1)=='\'))
endpos=pos;
return;
end
end
pos=pos+1;
end
error('unmatched quotation mark');
%%-------------------------------------------------------------------------
function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
global arraytoken
level=1;
maxlevel=level;
endpos=0;
bpos=arraytoken(arraytoken>=pos);
tokens=str(bpos);
len=length(tokens);
pos=1;
e1l=[];
e1r=[];
while(pos<=len)
c=tokens(pos);
if(c==']')
level=level-1;
if(isempty(e1r)) e1r=bpos(pos); end
if(level==0)
endpos=bpos(pos);
return
end
end
if(c=='[')
if(isempty(e1l)) e1l=bpos(pos); end
level=level+1;
maxlevel=max(maxlevel,level);
end
if(c=='"')
pos=matching_quote(tokens,pos+1);
end
pos=pos+1;
end
if(endpos==0)
error('unmatched "]"');
end
function s=mergestruct(s1,s2)
%
% s=mergestruct(s1,s2)
%
% merge two struct objects into one
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% date: 2012/12/22
%
% input:
% s1,s2: a struct object, s1 and s2 can not be arrays
%
% output:
% s: the merged struct object. fields in s1 and s2 will be combined in s.
%
% license:
% BSD, see LICENSE_BSD.txt files for details
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
if(~isstruct(s1) || ~isstruct(s2))
error('input parameters contain non-struct');
end
if(length(s1)>1 || length(s2)>1)
error('can not merge struct arrays');
end
fn=fieldnames(s2);
s=s1;
for i=1:length(fn)
s=setfield(s,fn{i},getfield(s2,fn{i}));
end
function json=savejson(rootname,obj,varargin)
%
% json=savejson(rootname,obj,filename)
% or
% json=savejson(rootname,obj,opt)
% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
%
% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
% Object Notation) string
%
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% created on 2011/09/09
%
% $Id: savejson.m 460 2015-01-03 00:30:45Z fangq $
%
% input:
% rootname: the name of the root-object, when set to '', the root name
% is ignored, however, when opt.ForceRootName is set to 1 (see below),
% the MATLAB variable name will be used as the root name.
% obj: a MATLAB object (array, cell, cell array, struct, struct array).
% filename: a string for the file name to save the output JSON data.
% opt: a struct for additional options, ignore to use default values.
% opt can have the following fields (first in [.|.] is the default)
%
% opt.FileName [''|string]: a file name to save the output JSON data
% opt.FloatFormat ['%.10g'|string]: format to show each numeric element
% of a 1D/2D array;
% opt.ArrayIndent [1|0]: if 1, output explicit data array with
% precedent indentation; if 0, no indentation
% opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
% array in JSON array format; if sets to 1, an
% array will be shown as a struct with fields
% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
% sparse arrays, the non-zero elements will be
% saved to _ArrayData_ field in triplet-format i.e.
% (ix,iy,val) and "_ArrayIsSparse_" will be added
% with a value of 1; for a complex array, the
% _ArrayData_ array will include two columns
% (4 for sparse) to record the real and imaginary
% parts, and also "_ArrayIsComplex_":1 is added.
% opt.ParseLogical [0|1]: if this is set to 1, logical array elem
% will use true/false rather than 1/0.
% opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
% numerical element will be shown without a square
% bracket, unless it is the root object; if 0, square
% brackets are forced for any numerical arrays.
% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
% will use the name of the passed obj variable as the
% root object name; if obj is an expression and
% does not have a name, 'root' will be used; if this
% is set to 0 and rootname is empty, the root level
% will be merged down to the lower level.
% opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
% to represent +/-Inf. The matched pattern is '([-+]*)Inf'
% and $1 represents the sign. For those who want to use
% 1e999 to represent Inf, they can set opt.Inf to '$11e999'
% opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
% to represent NaN
% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
% for example, if opt.JSONP='foo', the JSON data is
% wrapped inside a function call as 'foo(...);'
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
% back to the string form
% opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
% opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)
%
% opt can be replaced by a list of ('param',value) pairs. The param
% string is equivallent to a field in opt and is case sensitive.
% output:
% json: a string in the JSON format (see http://json.org)
%
% examples:
% jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
% 'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
% 'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
% 2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
% 'MeshCreator','FangQ','MeshTitle','T6 Cube',...
% 'SpecialData',[nan, inf, -inf]);
% savejson('jmesh',jsonmesh)
% savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')
%
% license:
% BSD, see LICENSE_BSD.txt files for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
if(nargin==1)
varname=inputname(1);
obj=rootname;
if(isempty(varname))
varname='root';
end
rootname=varname;
else
varname=inputname(2);
end
if(length(varargin)==1 && ischar(varargin{1}))
opt=struct('FileName',varargin{1});
else
opt=varargin2struct(varargin{:});
end
opt.IsOctave=exist('OCTAVE_VERSION','builtin');
rootisarray=0;
rootlevel=1;
forceroot=jsonopt('ForceRootName',0,opt);
if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
rootisarray=1;
rootlevel=0;
else
if(isempty(rootname))
rootname=varname;
end
end
if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
rootname='root';
end
whitespaces=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
if(jsonopt('Compact',0,opt)==1)
whitespaces=struct('tab','','newline','','sep',',');
end
if(~isfield(opt,'whitespaces_'))
opt.whitespaces_=whitespaces;
end
nl=whitespaces.newline;
json=obj2json(rootname,obj,rootlevel,opt);
if(rootisarray)
json=sprintf('%s%s',json,nl);
else
json=sprintf('{%s%s%s}\n',nl,json,nl);
end
jsonp=jsonopt('JSONP','',opt);
if(~isempty(jsonp))
json=sprintf('%s(%s);%s',jsonp,json,nl);
end
% save to a file if FileName is set, suggested by Patrick Rapin
if(~isempty(jsonopt('FileName','',opt)))
if(jsonopt('SaveBinary',0,opt)==1)
fid = fopen(opt.FileName, 'wb');
fwrite(fid,json);
else
fid = fopen(opt.FileName, 'wt');
fwrite(fid,json,'char');
end
fclose(fid);
end
%%-------------------------------------------------------------------------
function txt=obj2json(name,item,level,varargin)
if(iscell(item))
txt=cell2json(name,item,level,varargin{:});
elseif(isstruct(item))
txt=struct2json(name,item,level,varargin{:});
elseif(ischar(item))
txt=str2json(name,item,level,varargin{:});
else
txt=mat2json(name,item,level,varargin{:});
end
%%-------------------------------------------------------------------------
function txt=cell2json(name,item,level,varargin)
txt='';
if(~iscell(item))
error('input is not a cell');
end
dim=size(item);
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
item=reshape(item,dim(1),numel(item)/dim(1));
dim=size(item);
end
len=numel(item);
ws=jsonopt('whitespaces_',struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')),varargin{:});
padding0=repmat(ws.tab,1,level);
padding2=repmat(ws.tab,1,level+1);
nl=ws.newline;
if(len>1)
if(~isempty(name))
txt=sprintf('%s"%s": [%s',padding0, checkname(name,varargin{:}),nl); name='';
else
txt=sprintf('%s[%s',padding0,nl);
end
elseif(len==0)
if(~isempty(name))
txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name='';
else
txt=sprintf('%s[]',padding0);
end
end
for j=1:dim(2)
if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
for i=1:dim(1)
txt=sprintf('%s%s',txt,obj2json(name,item{i,j},level+(dim(1)>1)+1,varargin{:}));
if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
end
if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
%if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
end
if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
%%-------------------------------------------------------------------------
function txt=struct2json(name,item,level,varargin)
txt='';
if(~isstruct(item))
error('input is not a struct');
end
dim=size(item);
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
item=reshape(item,dim(1),numel(item)/dim(1));
dim=size(item);
end
len=numel(item);
ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'));
ws=jsonopt('whitespaces_',ws,varargin{:});
padding0=repmat(ws.tab,1,level);
padding2=repmat(ws.tab,1,level+1);
padding1=repmat(ws.tab,1,level+(dim(1)>1)+(len>1));
nl=ws.newline;
if(~isempty(name))
if(len>1) txt=sprintf('%s"%s": [%s',padding0,checkname(name,varargin{:}),nl); end
else
if(len>1) txt=sprintf('%s[%s',padding0,nl); end
end
for j=1:dim(2)
if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end
for i=1:dim(1)
names = fieldnames(item(i,j));
if(~isempty(name) && len==1)
txt=sprintf('%s%s"%s": {%s',txt,padding1, checkname(name,varargin{:}),nl);
else
txt=sprintf('%s%s{%s',txt,padding1,nl);
end
if(~isempty(names))
for e=1:length(names)
txt=sprintf('%s%s',txt,obj2json(names{e},getfield(item(i,j),...
names{e}),level+(dim(1)>1)+1+(len>1),varargin{:}));
if(e<length(names)) txt=sprintf('%s%s',txt,','); end
txt=sprintf('%s%s',txt,nl);
end
end
txt=sprintf('%s%s}',txt,padding1);
if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
end
if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end
if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end
end
if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end
%%-------------------------------------------------------------------------
function txt=str2json(name,item,level,varargin)
txt='';
if(~ischar(item))
error('input is not a string');
end
item=reshape(item, max(size(item),[1 0]));
len=size(item,1);
ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
ws=jsonopt('whitespaces_',ws,varargin{:});
padding1=repmat(ws.tab,1,level);
padding0=repmat(ws.tab,1,level+1);
nl=ws.newline;
sep=ws.sep;
if(~isempty(name))
if(len>1) txt=sprintf('%s"%s": [%s',padding1,checkname(name,varargin{:}),nl); end
else
if(len>1) txt=sprintf('%s[%s',padding1,nl); end
end
isoct=jsonopt('IsOctave',0,varargin{:});
for e=1:len
if(isoct)
val=regexprep(item(e,:),'\\','\\');
val=regexprep(val,'"','\"');
val=regexprep(val,'^"','\"');
else
val=regexprep(item(e,:),'\\','\\\\');
val=regexprep(val,'"','\\"');
val=regexprep(val,'^"','\\"');
end
val=escapejsonstring(val);
if(len==1)
obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];
if(isempty(name)) obj=['"',val,'"']; end
txt=sprintf('%s%s%s%s',txt,padding1,obj);
else
txt=sprintf('%s%s%s%s',txt,padding0,['"',val,'"']);
end
if(e==len) sep=''; end
txt=sprintf('%s%s',txt,sep);
end
if(len>1) txt=sprintf('%s%s%s%s',txt,nl,padding1,']'); end
%%-------------------------------------------------------------------------
function txt=mat2json(name,item,level,varargin)
if(~isnumeric(item) && ~islogical(item))
error('input is not an array');
end
ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
ws=jsonopt('whitespaces_',ws,varargin{:});
padding1=repmat(ws.tab,1,level);
padding0=repmat(ws.tab,1,level+1);
nl=ws.newline;
sep=ws.sep;
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:}))
if(isempty(name))
txt=sprintf('%s{%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
padding1,nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
else
txt=sprintf('%s"%s": {%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...
padding1,checkname(name,varargin{:}),nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);
end
else
if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1 && level>0)
numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');
else
numtxt=matdata2json(item,level+1,varargin{:});
end
if(isempty(name))
txt=sprintf('%s%s',padding1,numtxt);
else
if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
else
txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
end
end
return;
end
dataformat='%s%s%s%s%s';
if(issparse(item))
[ix,iy]=find(item);
data=full(item(find(item)));
if(~isreal(item))
data=[real(data(:)),imag(data(:))];
if(size(item,1)==1)
% Kludge to have data's 'transposedness' match item's.
% (Necessary for complex row vector handling below.)
data=data';
end
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
end
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sep);
if(size(item,1)==1)
% Row vector, store only column indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([iy(:),data'],level+2,varargin{:}), nl);
elseif(size(item,2)==1)
% Column vector, store only row indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([ix,data],level+2,varargin{:}), nl);
else
% General case, store row and column indices.
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([ix,iy,data],level+2,varargin{:}), nl);
end
else
if(isreal(item))
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json(item(:)',level+2,varargin{:}), nl);
else
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), nl);
end
end
txt=sprintf('%s%s%s',txt,padding1,'}');
%%-------------------------------------------------------------------------
function txt=matdata2json(mat,level,varargin)
ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));
ws=jsonopt('whitespaces_',ws,varargin{:});
tab=ws.tab;
nl=ws.newline;
if(size(mat,1)==1)
pre='';
post='';
level=level-1;
else
pre=sprintf('[%s',nl);
post=sprintf('%s%s]',nl,repmat(tab,1,level-1));
end
if(isempty(mat))
txt='null';
return;
end
floatformat=jsonopt('FloatFormat','%.10g',varargin{:});
%if(numel(mat)>1)
formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],%s',nl)]];
%else
% formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];
%end
if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)
formatstr=[repmat(tab,1,level) formatstr];
end
txt=sprintf(formatstr,mat');
txt(end-length(nl):end)=[];
if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)
txt=regexprep(txt,'1','true');
txt=regexprep(txt,'0','false');
end
%txt=regexprep(mat2str(mat),'\s+',',');
%txt=regexprep(txt,';',sprintf('],\n['));
% if(nargin>=2 && size(mat,1)>1)
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
% end
txt=[pre txt post];
if(any(isinf(mat(:))))
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
end
if(any(isnan(mat(:))))
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
end
%%-------------------------------------------------------------------------
function newname=checkname(name,varargin)
isunpack=jsonopt('UnpackHex',1,varargin{:});
newname=name;
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
return
end
if(isunpack)
isoct=jsonopt('IsOctave',0,varargin{:});
if(~isoct)
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
else
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
if(isempty(pos)) return; end
str0=name;
pos0=[0 pend(:)' length(name)];
newname='';
for i=1:length(pos)
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
end
if(pos(end)~=length(name))
newname=[newname str0(pos0(end-1)+1:pos0(end))];
end
end
end
%%-------------------------------------------------------------------------
function newstr=escapejsonstring(str)
newstr=str;
isoct=exist('OCTAVE_VERSION','builtin');
if(isoct)
vv=sscanf(OCTAVE_VERSION,'%f');
if(vv(1)>=3.8) isoct=0; end
end
if(isoct)
escapechars={'\a','\f','\n','\r','\t','\v'};
for i=1:length(escapechars);
newstr=regexprep(newstr,escapechars{i},escapechars{i});
end
else
escapechars={'\a','\b','\f','\n','\r','\t','\v'};
for i=1:length(escapechars);
newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));
end
end
function json=saveubjson(rootname,obj,varargin)
%
% json=saveubjson(rootname,obj,filename)
% or
% json=saveubjson(rootname,obj,opt)
% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
%
% convert a MATLAB object (cell, struct or array) into a Universal
% Binary JSON (UBJSON) binary string
%
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% created on 2013/08/17
%
% $Id: saveubjson.m 460 2015-01-03 00:30:45Z fangq $
%
% input:
% rootname: the name of the root-object, when set to '', the root name
% is ignored, however, when opt.ForceRootName is set to 1 (see below),
% the MATLAB variable name will be used as the root name.
% obj: a MATLAB object (array, cell, cell array, struct, struct array)
% filename: a string for the file name to save the output UBJSON data
% opt: a struct for additional options, ignore to use default values.
% opt can have the following fields (first in [.|.] is the default)
%
% opt.FileName [''|string]: a file name to save the output JSON data
% opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
% array in JSON array format; if sets to 1, an
% array will be shown as a struct with fields
% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
% sparse arrays, the non-zero elements will be
% saved to _ArrayData_ field in triplet-format i.e.
% (ix,iy,val) and "_ArrayIsSparse_" will be added
% with a value of 1; for a complex array, the
% _ArrayData_ array will include two columns
% (4 for sparse) to record the real and imaginary
% parts, and also "_ArrayIsComplex_":1 is added.
% opt.ParseLogical [1|0]: if this is set to 1, logical array elem
% will use true/false rather than 1/0.
% opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
% numerical element will be shown without a square
% bracket, unless it is the root object; if 0, square
% brackets are forced for any numerical arrays.
% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
% will use the name of the passed obj variable as the
% root object name; if obj is an expression and
% does not have a name, 'root' will be used; if this
% is set to 0 and rootname is empty, the root level
% will be merged down to the lower level.
% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
% for example, if opt.JSON='foo', the JSON data is
% wrapped inside a function call as 'foo(...);'
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
% back to the string form
%
% opt can be replaced by a list of ('param',value) pairs. The param
% string is equivallent to a field in opt and is case sensitive.
% output:
% json: a binary string in the UBJSON format (see http://ubjson.org)
%
% examples:
% jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...
% 'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...
% 'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...
% 2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...
% 'MeshCreator','FangQ','MeshTitle','T6 Cube',...
% 'SpecialData',[nan, inf, -inf]);
% saveubjson('jsonmesh',jsonmesh)
% saveubjson('jsonmesh',jsonmesh,'meshdata.ubj')
%
% license:
% BSD, see LICENSE_BSD.txt files for details
%
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
if(nargin==1)
varname=inputname(1);
obj=rootname;
if(isempty(varname))
varname='root';
end
rootname=varname;
else
varname=inputname(2);
end
if(length(varargin)==1 && ischar(varargin{1}))
opt=struct('FileName',varargin{1});
else
opt=varargin2struct(varargin{:});
end
opt.IsOctave=exist('OCTAVE_VERSION','builtin');
rootisarray=0;
rootlevel=1;
forceroot=jsonopt('ForceRootName',0,opt);
if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
rootisarray=1;
rootlevel=0;
else
if(isempty(rootname))
rootname=varname;
end
end
if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
rootname='root';
end
json=obj2ubjson(rootname,obj,rootlevel,opt);
if(~rootisarray)
json=['{' json '}'];
end
jsonp=jsonopt('JSONP','',opt);
if(~isempty(jsonp))
json=[jsonp '(' json ')'];
end
% save to a file if FileName is set, suggested by Patrick Rapin
if(~isempty(jsonopt('FileName','',opt)))
fid = fopen(opt.FileName, 'wb');
fwrite(fid,json);
fclose(fid);
end
%%-------------------------------------------------------------------------
function txt=obj2ubjson(name,item,level,varargin)
if(iscell(item))
txt=cell2ubjson(name,item,level,varargin{:});
elseif(isstruct(item))
txt=struct2ubjson(name,item,level,varargin{:});
elseif(ischar(item))
txt=str2ubjson(name,item,level,varargin{:});
else
txt=mat2ubjson(name,item,level,varargin{:});
end
%%-------------------------------------------------------------------------
function txt=cell2ubjson(name,item,level,varargin)
txt='';
if(~iscell(item))
error('input is not a cell');
end
dim=size(item);
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
item=reshape(item,dim(1),numel(item)/dim(1));
dim=size(item);
end
len=numel(item); % let's handle 1D cell first
if(len>1)
if(~isempty(name))
txt=[S_(checkname(name,varargin{:})) '[']; name='';
else
txt='[';
end
elseif(len==0)
if(~isempty(name))
txt=[S_(checkname(name,varargin{:})) 'Z']; name='';
else
txt='Z';
end
end
for j=1:dim(2)
if(dim(1)>1) txt=[txt '[']; end
for i=1:dim(1)
txt=[txt obj2ubjson(name,item{i,j},level+(len>1),varargin{:})];
end
if(dim(1)>1) txt=[txt ']']; end
end
if(len>1) txt=[txt ']']; end
%%-------------------------------------------------------------------------
function txt=struct2ubjson(name,item,level,varargin)
txt='';
if(~isstruct(item))
error('input is not a struct');
end
dim=size(item);
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
item=reshape(item,dim(1),numel(item)/dim(1));
dim=size(item);
end
len=numel(item);
if(~isempty(name))
if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
else
if(len>1) txt='['; end
end
for j=1:dim(2)
if(dim(1)>1) txt=[txt '[']; end
for i=1:dim(1)
names = fieldnames(item(i,j));
if(~isempty(name) && len==1)
txt=[txt S_(checkname(name,varargin{:})) '{'];
else
txt=[txt '{'];
end
if(~isempty(names))
for e=1:length(names)
txt=[txt obj2ubjson(names{e},getfield(item(i,j),...
names{e}),level+(dim(1)>1)+1+(len>1),varargin{:})];
end
end
txt=[txt '}'];
end
if(dim(1)>1) txt=[txt ']']; end
end
if(len>1) txt=[txt ']']; end
%%-------------------------------------------------------------------------
function txt=str2ubjson(name,item,level,varargin)
txt='';
if(~ischar(item))
error('input is not a string');
end
item=reshape(item, max(size(item),[1 0]));
len=size(item,1);
if(~isempty(name))
if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
else
if(len>1) txt='['; end
end
isoct=jsonopt('IsOctave',0,varargin{:});
for e=1:len
val=item(e,:);
if(len==1)
obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),''];
if(isempty(name)) obj=['',S_(val),'']; end
txt=[txt,'',obj];
else
txt=[txt,'',['',S_(val),'']];
end
end
if(len>1) txt=[txt ']']; end
%%-------------------------------------------------------------------------
function txt=mat2ubjson(name,item,level,varargin)
if(~isnumeric(item) && ~islogical(item))
error('input is not an array');
end
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
isempty(item) || jsonopt('ArrayToStruct',0,varargin{:}))
cid=I_(uint32(max(size(item))));
if(isempty(name))
txt=['{' S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1)) ];
else
if(isempty(item))
txt=[S_(checkname(name,varargin{:})),'Z'];
return;
else
txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1))];
end
end
else
if(isempty(name))
txt=matdata2ubjson(item,level+1,varargin{:});
else
if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']','');
txt=[S_(checkname(name,varargin{:})) numtxt];
else
txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})];
end
end
return;
end
if(issparse(item))
[ix,iy]=find(item);
data=full(item(find(item)));
if(~isreal(item))
data=[real(data(:)),imag(data(:))];
if(size(item,1)==1)
% Kludge to have data's 'transposedness' match item's.
% (Necessary for complex row vector handling below.)
data=data';
end
txt=[txt,S_('_ArrayIsComplex_'),'T'];
end
txt=[txt,S_('_ArrayIsSparse_'),'T'];
if(size(item,1)==1)
% Row vector, store only column indices.
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson([iy(:),data'],level+2,varargin{:})];
elseif(size(item,2)==1)
% Column vector, store only row indices.
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson([ix,data],level+2,varargin{:})];
else
% General case, store row and column indices.
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson([ix,iy,data],level+2,varargin{:})];
end
else
if(isreal(item))
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson(item(:)',level+2,varargin{:})];
else
txt=[txt,S_('_ArrayIsComplex_'),'T'];
txt=[txt,S_('_ArrayData_'),...
matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
end
end
txt=[txt,'}'];
%%-------------------------------------------------------------------------
function txt=matdata2ubjson(mat,level,varargin)
if(isempty(mat))
txt='Z';
return;
end
if(size(mat,1)==1)
level=level-1;
end
type='';
hasnegtive=(mat<0);
if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
if(isempty(hasnegtive))
if(max(mat(:))<=2^8)
type='U';
end
end
if(isempty(type))
% todo - need to consider negative ones separately
id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]);
if(isempty(find(id)))
error('high-precision data is not yet supported');
end
key='iIlL';
type=key(find(id));
end
txt=[I_a(mat(:),type,size(mat))];
elseif(islogical(mat))
logicalval='FT';
if(numel(mat)==1)
txt=logicalval(mat+1);
else
txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
end
else
if(numel(mat)==1)
txt=['[' D_(mat) ']'];
else
txt=D_a(mat(:),'D',size(mat));
end
end
%txt=regexprep(mat2str(mat),'\s+',',');
%txt=regexprep(txt,';',sprintf('],['));
% if(nargin>=2 && size(mat,1)>1)
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
% end
if(any(isinf(mat(:))))
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
end
if(any(isnan(mat(:))))
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
end
%%-------------------------------------------------------------------------
function newname=checkname(name,varargin)
isunpack=jsonopt('UnpackHex',1,varargin{:});
newname=name;
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
return
end
if(isunpack)
isoct=jsonopt('IsOctave',0,varargin{:});
if(~isoct)
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
else
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
if(isempty(pos)) return; end
str0=name;
pos0=[0 pend(:)' length(name)];
newname='';
for i=1:length(pos)
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
end
if(pos(end)~=length(name))
newname=[newname str0(pos0(end-1)+1:pos0(end))];
end
end
end
%%-------------------------------------------------------------------------
function val=S_(str)
if(length(str)==1)
val=['C' str];
else
val=['S' I_(int32(length(str))) str];
end
%%-------------------------------------------------------------------------
function val=I_(num)
if(~isinteger(num))
error('input is not an integer');
end
if(num>=0 && num<255)
val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
return;
end
key='iIlL';
cid={'int8','int16','int32','int64'};
for i=1:4
if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
return;
end
end
error('unsupported integer');
%%-------------------------------------------------------------------------
function val=D_(num)
if(~isfloat(num))
error('input is not a float');
end
if(isa(num,'single'))
val=['d' data2byte(num,'uint8')];
else
val=['D' data2byte(num,'uint8')];
end
%%-------------------------------------------------------------------------
function data=I_a(num,type,dim,format)
id=find(ismember('iUIlL',type));
if(id==0)
error('unsupported integer array');
end
% based on UBJSON specs, all integer types are stored in big endian format
if(id==1)
data=data2byte(swapbytes(int8(num)),'uint8');
blen=1;
elseif(id==2)
data=data2byte(swapbytes(uint8(num)),'uint8');
blen=1;
elseif(id==3)
data=data2byte(swapbytes(int16(num)),'uint8');
blen=2;
elseif(id==4)
data=data2byte(swapbytes(int32(num)),'uint8');
blen=4;
elseif(id==5)
data=data2byte(swapbytes(int64(num)),'uint8');
blen=8;
end
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
format='opt';
end
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
cid=I_(uint32(max(dim)));
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
else
data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
end
data=['[' data(:)'];
else
data=reshape(data,blen,numel(data)/blen);
data(2:blen+1,:)=data;
data(1,:)=type;
data=data(:)';
data=['[' data(:)' ']'];
end
%%-------------------------------------------------------------------------
function data=D_a(num,type,dim,format)
id=find(ismember('dD',type));
if(id==0)
error('unsupported float array');
end
if(id==1)
data=data2byte(single(num),'uint8');
elseif(id==2)
data=data2byte(double(num),'uint8');
end
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
format='opt';
end
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
cid=I_(uint32(max(dim)));
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
else
data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
end
data=['[' data];
else
data=reshape(data,(id*4),length(data)/(id*4));
data(2:(id*4+1),:)=data;
data(1,:)=type;
data=data(:)';
data=['[' data(:)' ']'];
end
%%-------------------------------------------------------------------------
function bytes=data2byte(varargin)
bytes=typecast(varargin{:});
bytes=bytes(:)';
function opt=varargin2struct(varargin)
%
% opt=varargin2struct('param1',value1,'param2',value2,...)
% or
% opt=varargin2struct(...,optstruct,...)
%
% convert a series of input parameters into a structure
%
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
% date: 2012/12/22
%
% input:
% 'param', value: the input parameters should be pairs of a string and a value
% optstruct: if a parameter is a struct, the fields will be merged to the output struct
%
% output:
% opt: a struct where opt.param1=value1, opt.param2=value2 ...
%
% license:
% BSD, see LICENSE_BSD.txt files for details
%
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
%
len=length(varargin);
opt=struct;
if(len==0) return; end
i=1;
while(i<=len)
if(isstruct(varargin{i}))
opt=mergestruct(opt,varargin{i});
elseif(ischar(varargin{i}) && i<len)
opt=setfield(opt,varargin{i},varargin{i+1});
i=i+1;
else
error('input must be in the form of ...,''name'',value,... pairs or structs');
end
i=i+1;
end
function str = makeValidFieldName(str)
% From MATLAB doc: field names must begin with a letter, which may be
% followed by any combination of letters, digits, and underscores.
% Invalid characters will be converted to underscores, and the prefix
% "x0x[Hex code]_" will be added if the first character is not a letter.
isoct=exist('OCTAVE_VERSION','builtin');
pos=regexp(str,'^[^A-Za-z]','once');
if(~isempty(pos))
if(~isoct)
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
else
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
end
end
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end
if(~isoct)
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
else
pos=regexp(str,'[^0-9A-Za-z_]');
if(isempty(pos)) return; end
str0=str;
pos0=[0 pos(:)' length(str)];
str='';
for i=1:length(pos)
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
end
if(pos(end)~=length(str))
str=[str str0(pos0(end-1)+1:pos0(end))];
end
end
function submitWithConfiguration(conf)
addpath('./lib/jsonlab');
parts = parts(conf);
fprintf('== Submitting solutions | %s...\n', conf.itemName);
tokenFile = 'token.mat';
if exist(tokenFile, 'file')
load(tokenFile);
[email token] = promptToken(email, token, tokenFile);
else
[email token] = promptToken('', '', tokenFile);
end
if isempty(token)
fprintf('!! Submission Cancelled\n');
return
end
try
response = submitParts(conf, email, token, parts);
catch
e = lasterror();
fprintf('\n!! Submission failed: %s\n', e.message);
fprintf('\n\nFunction: %s\nFileName: %s\nLineNumber: %d\n', ...
e.stack(1,1).name, e.stack(1,1).file, e.stack(1,1).line);
fprintf('\nPlease correct your code and resubmit.\n');
return
end
if isfield(response, 'errorMessage')
fprintf('!! Submission failed: %s\n', response.errorMessage);
elseif isfield(response, 'errorCode')
fprintf('!! Submission failed: %s\n', response.message);
else
showFeedback(parts, response);
save(tokenFile, 'email', 'token');
end
end
function [email token] = promptToken(email, existingToken, tokenFile)
if (~isempty(email) && ~isempty(existingToken))
prompt = sprintf( ...
'Use token from last successful submission (%s)? (Y/n): ', ...
email);
reenter = input(prompt, 's');
if (isempty(reenter) || reenter(1) == 'Y' || reenter(1) == 'y')
token = existingToken;
return;
else
delete(tokenFile);
end
end
email = input('Login (email address): ', 's');
token = input('Token: ', 's');
end
function isValid = isValidPartOptionIndex(partOptions, i)
isValid = (~isempty(i)) && (1 <= i) && (i <= numel(partOptions));
end
function response = submitParts(conf, email, token, parts)
body = makePostBody(conf, email, token, parts);
submissionUrl = submissionUrl();
responseBody = getResponse(submissionUrl, body);
jsonResponse = validateResponse(responseBody);
response = loadjson(jsonResponse);
end
function body = makePostBody(conf, email, token, parts)
bodyStruct.assignmentSlug = conf.assignmentSlug;
bodyStruct.submitterEmail = email;
bodyStruct.secret = token;
bodyStruct.parts = makePartsStruct(conf, parts);
opt.Compact = 1;
body = savejson('', bodyStruct, opt);
end
function partsStruct = makePartsStruct(conf, parts)
for part = parts
partId = part{:}.id;
fieldName = makeValidFieldName(partId);
outputStruct.output = conf.output(partId);
partsStruct.(fieldName) = outputStruct;
end
end
function [parts] = parts(conf)
parts = {};
for partArray = conf.partArrays
part.id = partArray{:}{1};
part.sourceFiles = partArray{:}{2};
part.name = partArray{:}{3};
parts{end + 1} = part;
end
end
function showFeedback(parts, response)
fprintf('== \n');
fprintf('== %43s | %9s | %-s\n', 'Part Name', 'Score', 'Feedback');
fprintf('== %43s | %9s | %-s\n', '---------', '-----', '--------');
for part = parts
score = '';
partFeedback = '';
partFeedback = response.partFeedbacks.(makeValidFieldName(part{:}.id));
partEvaluation = response.partEvaluations.(makeValidFieldName(part{:}.id));
score = sprintf('%d / %3d', partEvaluation.score, partEvaluation.maxScore);
fprintf('== %43s | %9s | %-s\n', part{:}.name, score, partFeedback);
end
evaluation = response.evaluation;
totalScore = sprintf('%d / %d', evaluation.score, evaluation.maxScore);
fprintf('== --------------------------------\n');
fprintf('== %43s | %9s | %-s\n', '', totalScore, '');
fprintf('== \n');
end
% use urlread or curl to send submit results to the grader and get a response
function response = getResponse(url, body)
% try using urlread() and a secure connection
params = {'jsonBody', body};
[response, success] = urlread(url, 'post', params);
if (success == 0)
% urlread didn't work, try curl & the peer certificate patch
if ispc
% testing note: use 'jsonBody =' for a test case
json_command = sprintf('echo jsonBody=%s | curl -k -X POST -d @- %s', body, url);
else
% it's linux/OS X, so use the other form
json_command = sprintf('echo ''jsonBody=%s'' | curl -k -X POST -d @- %s', body, url);
end
% get the response body for the peer certificate patch method
[code, response] = system(json_command);
% test the success code
if (code ~= 0)
fprintf('[error] submission with curl() was not successful\n');
end
end
end
% validate the grader's response
function response = validateResponse(resp)
% test if the response is json or an HTML page
isJson = length(resp) > 0 && resp(1) == '{';
isHtml = findstr(lower(resp), '<html');
if (isJson)
response = resp;
elseif (isHtml)
% the response is html, so it's probably an error message
printHTMLContents(resp);
error('Grader response is an HTML message');
else
error('Grader sent no response');
end
end
% parse a HTML response and print it's contents
function printHTMLContents(response)
strippedResponse = regexprep(response, '<[^>]+>', ' ');
strippedResponse = regexprep(strippedResponse, '[\t ]+', ' ');
fprintf(strippedResponse);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Service configuration
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function submissionUrl = submissionUrl()
submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1';
end
function [U, S] = pca(X)
%PCA Run principal component analysis on the dataset X
% [U, S, X] = pca(X) computes eigenvectors of the covariance matrix of X
% Returns the eigenvectors U, the eigenvalues (on diagonal) in S
%
% Useful values
[m, n] = size(X);
% You need to return the following variables correctly.
U = zeros(n);
S = zeros(n);
% ====================== YOUR CODE HERE ======================
% Instructions: You should first compute the covariance matrix. Then, you
% should use the "svd" function to compute the eigenvectors
% and eigenvalues of the covariance matrix.
%
% Note: When computing the covariance matrix, remember to divide by m (the
% number of examples).
%
sigma = (1/m)*(X'*X);
[U,S,V] = svd(sigma);
% =========================================================================
end
function plotDataPoints(X, idx, K)
%PLOTDATAPOINTS plots data points in X, coloring them so that those with the same
%index assignments in idx have the same color
% PLOTDATAPOINTS(X, idx, K) plots data points in X, coloring them so that those
% with the same index assignments in idx have the same color
% Create palette
palette = hsv(K + 1);
colors = palette(idx, :);
% Plot the data
scatter(X(:,1), X(:,2), 15, colors);
end
function plotProgresskMeans(X, centroids, previous, idx, K, i)
%PLOTPROGRESSKMEANS is a helper function that displays the progress of
%k-Means as it is running. It is intended for use only with 2D data.
% PLOTPROGRESSKMEANS(X, centroids, previous, idx, K, i) plots the data
% points with colors assigned to each centroid. With the previous
% centroids, it also plots a line between the previous locations and
% current locations of the centroids.
%
% Plot the examples
plotDataPoints(X, idx, K);
% Plot the centroids as black x's
plot(centroids(:,1), centroids(:,2), 'x', ...
'MarkerEdgeColor','k', ...
'MarkerSize', 10, 'LineWidth', 3);
% Plot the history of the centroids with lines
for j=1:size(centroids,1)
drawLine(centroids(j, :), previous(j, :));
end
% Title
title(sprintf('Iteration number %d', i))
end
function Z = projectData(X, U, K)
%PROJECTDATA Computes the reduced data representation when projecting only
%on to the top k eigenvectors
% Z = projectData(X, U, K) computes the projection of
% the normalized inputs X into the reduced dimensional space spanned by
% the first K columns of U. It returns the projected examples in Z.
%
% You need to return the following variables correctly.
% ====================== YOUR CODE HERE ======================
% Instructions: Compute the projection of the data using only the top K
% eigenvectors in U (first K columns).
% For the i-th example X(i,:), the projection on to the k-th
% eigenvector is given as follows:
% x = X(i, :)';
% projection_k = x' * U(:, k);
%
Z = X*U(:,1:K);
% =============================================================
end
function X_rec = recoverData(Z, U, K)
%RECOVERDATA Recovers an approximation of the original data when using the
%projected data
% X_rec = RECOVERDATA(Z, U, K) recovers an approximation the
% original data that has been reduced to K dimensions. It returns the
% approximate reconstruction in X_rec.
%
% You need to return the following variables correctly.
X_rec = zeros(size(Z, 1), size(U, 1));
% ====================== YOUR CODE HERE ======================
% Instructions: Compute the approximation of the data by projecting back
% onto the original space using the top K eigenvectors in U.
%
% For the i-th example Z(i,:), the (approximate)
% recovered data for dimension j is given as follows:
% v = Z(i, :)';
% recovered_j = v' * U(j, 1:K)';
%
% Notice that U(j, 1:K) is a row vector.
%
X_rec = Z*U(:,1:K)';
% =============================================================
end
function [centroids, idx] = runkMeans(X, initial_centroids, ...
max_iters, plot_progress)
%RUNKMEANS runs the K-Means algorithm on data matrix X, where each row of X
%is a single example
% [centroids, idx] = RUNKMEANS(X, initial_centroids, max_iters, ...
% plot_progress) runs the K-Means algorithm on data matrix X, where each
% row of X is a single example. It uses initial_centroids used as the
% initial centroids. max_iters specifies the total number of interactions
% of K-Means to execute. plot_progress is a true/false flag that
% indicates if the function should also plot its progress as the
% learning happens. This is set to false by default. runkMeans returns
% centroids, a Kxn matrix of the computed centroids and idx, a m x 1
% vector of centroid assignments (i.e. each entry in range [1..K])
%
% Set default value for plot progress
if ~exist('plot_progress', 'var') || isempty(plot_progress)
plot_progress = false;
end
% Plot the data if we are plotting progress
if plot_progress
figure;
hold on;
end
% Initialize values
[m n] = size(X);
K = size(initial_centroids, 1);
centroids = initial_centroids;
previous_centroids = centroids;
idx = zeros(m, 1);
% Run K-Means
for i=1:max_iters
% Output progress
fprintf('K-Means iteration %d/%d...\n', i, max_iters);
if exist('OCTAVE_VERSION')
fflush(stdout);
end
% For each example in X, assign it to the closest centroid
idx = findClosestCentroids(X, centroids);
% Optionally, plot progress here
if plot_progress
plotProgresskMeans(X, centroids, previous_centroids, idx, K, i);
previous_centroids = centroids;
fprintf('Press enter to continue.\n');
pause;
end
% Given the memberships, compute new centroids
centroids = computeCentroids(X, idx, K);
end
% Hold off if we are plotting progress
if plot_progress
hold off;
end
end
function submit()
addpath('./lib');
conf.assignmentSlug = 'k-means-clustering-and-pca';
conf.itemName = 'K-Means Clustering and PCA';
conf.partArrays = { ...
{ ...
'1', ...
{ 'findClosestCentroids.m' }, ...
'Find Closest Centroids (k-Means)', ...
}, ...
{ ...
'2', ...
{ 'computeCentroids.m' }, ...
'Compute Centroid Means (k-Means)', ...
}, ...
{ ...
'3', ...
{ 'pca.m' }, ...
'PCA', ...
}, ...
{ ...
'4', ...
{ 'projectData.m' }, ...
'Project Data (PCA)', ...
}, ...
{ ...
'5', ...
{ 'recoverData.m' }, ...
'Recover Data (PCA)', ...
}, ...
};
conf.output = @output;
submitWithConfiguration(conf);
end
function out = output(partId, auxstring)
% Random Test Cases
X = reshape(sin(1:165), 15, 11);
Z = reshape(cos(1:121), 11, 11);
C = Z(1:5, :);
idx = (1 + mod(1:15, 3))';
if partId == '1'
idx = findClosestCentroids(X, C);
out = sprintf('%0.5f ', idx(:));
elseif partId == '2'
centroids = computeCentroids(X, idx, 3);
out = sprintf('%0.5f ', centroids(:));
elseif partId == '3'
[U, S] = pca(X);
out = sprintf('%0.5f ', abs([U(:); S(:)]));
elseif partId == '4'
X_proj = projectData(X, Z, 5);
out = sprintf('%0.5f ', X_proj(:));
elseif partId == '5'
X_rec = recoverData(X(:,1:5), Z, 5);
out = sprintf('%0.5f ', X_rec(:));
end
end
# Created by Octave 4.4.0, Tue May 29 17:50:35 2018 GMT <unknown@DESKTOP-IBF55GH>
# name: email
# type: sq_string
# elements: 1
# length: 24
shashijgupta@hotmail.com
# name: token
# type: sq_string
# elements: 1
# length: 16
aucrETHhdsX4pYNv
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment