@@ -11,8 +11,7 @@ https://www.coursera.org/learn/machine-learning | |||||
本项目包含课程中的所有课后作业以及笔记,目前正在将手写笔记进行电子化。 | 本项目包含课程中的所有课后作业以及笔记,目前正在将手写笔记进行电子化。 | ||||
1. 笔记(notes)都为中文,为了便于复习和扩充等,尽量会按照视频目录,以及视频内容进行提炼整理。 | 1. 笔记(notes)都为中文,为了便于复习和扩充等,尽量会按照视频目录,以及视频内容进行提炼整理。 | ||||
2. 所有课后作业(assignments)都已提交并通过 Coursera 编程测验。仅供参考,请勿抄袭。 | |||||
2. 遵循[荣誉准则][honor code],现已移除已通过的课后编程作业的源代码,之后会改为指导笔记形式陆续更新。 | |||||
For Andrew Ng's machine learning course on Coursera. | For Andrew Ng's machine learning course on Coursera. | ||||
@@ -26,11 +25,11 @@ You can read it by Typora or any other similar markdown editor. | |||||
1. **在线阅读地址**:http://scruel.gitee.io/ml-andrewng-notes/ | 1. **在线阅读地址**:http://scruel.gitee.io/ml-andrewng-notes/ | ||||
2. 直接在 GitHub Page 上阅读,需安装 Chrome 插件 —— [GitHub with MathJax][1](部分公式仍无法正常解析)。 | |||||
2. 直接在 GitHub Page 上阅读,需安装 Chrome 插件 —— [GitHub with MathJax][GitHub with MathJax](部分公式仍无法正常解析)。 | |||||
3. 下载 .html 网页文件及 笔记图片 image 文件夹,浏览器打开阅读。 | 3. 下载 .html 网页文件及 笔记图片 image 文件夹,浏览器打开阅读。 | ||||
4. 笔记源码(.md)基于支持 LaTeX 的 markdown 编辑器 [Typora][2],其他类似的编辑器也可以阅读及编辑,注意其他编辑器可能会产生排版问题。 | |||||
4. 笔记源码(.md)基于支持 LaTeX 的 markdown 编辑器 [Typora][Typora],其他类似的编辑器也可以阅读及编辑,注意其他编辑器可能会产生排版问题。 | |||||
@@ -39,12 +38,16 @@ You can read it by Typora or any other similar markdown editor. | |||||
方便网络不方便的同学学习 | 方便网络不方便的同学学习 | ||||
[百度网盘下载](https://pan.baidu.com/s/1mkmnRIC) | 密码:fdzc(包含视频,讲义,以及编程作业题原题压缩包) | |||||
[百度网盘下载][baidupan] | 密码:fdzc(包含视频,讲义,以及编程作业题原题压缩包) | |||||
[B站在线中英双语](http://www.bilibili.com/video/av9912938?bbid=F8173D95-FF96-47EF-B7F4-0779D698B8051978infoc) | [B站在线英文版1](https://www.bilibili.com/video/av17624209/?from=search&seid=15848135050308500663) | [B站在线英文版2](https://www.bilibili.com/video/av17624412/?from=search&seid=15848135050308500663) | |||||
[B站在线中英双语][bilibili_zh] | [B站在线英文版1][bilibili_en1] | [B站在线英文版2][bilibili_en2] | |||||
当然,还是建议克服一下困难,最好能上 Coursera 网站学习,官网安排的贴心小测试可以检验你对知识的掌握情况。 | 当然,还是建议克服一下困难,最好能上 Coursera 网站学习,官网安排的贴心小测试可以检验你对知识的掌握情况。 | ||||
如果遇到 Coursera 上提交编程作业失败的问题,以 [submitWithConfiguration.m](https://github.com/scruel/ML-AndrewNg-Notes/blob/master/assignments/submitWithConfiguration.m) 覆盖编程作业中 lib 文件夹下的同名文件即可解决。 | |||||
## Thanks | ## Thanks | ||||
- Coursera 官网 | - Coursera 官网 | ||||
@@ -55,18 +58,24 @@ You can read it by Typora or any other similar markdown editor. | |||||
注:由于手写笔记成稿时间较早,有所参考无法一一致谢,在此统一表示谢意! | 注:由于手写笔记成稿时间较早,有所参考无法一一致谢,在此统一表示谢意! | ||||
## License | ## License | ||||
[][3] | |||||
[][CC BY-NC 4.0] | |||||
This work is licensed under a [Creative Commons Attribution-NonCommercial 4.0 International License][3]. | |||||
This work is licensed under a [Creative Commons Attribution-NonCommercial 4.0 International License][CC BY-NC 4.0]. | |||||
[知乎文章](https://zhuanlan.zhihu.com/p/32781741) | |||||
[知乎文章][zhihu] | |||||
By: Scruel | By: Scruel | ||||
[1]: https://chrome.google.com/webstore/detail/ioemnmodlmafdkllaclgeombjnmnbima | |||||
[2]: https://typora.io/ | |||||
[3]: http://creativecommons.org/licenses/by-nc/4.0/ | |||||
[zhihu]: https://zhuanlan.zhihu.com/p/32781741 | |||||
[baidupan]: https://pan.baidu.com/s/1mkmnRIC | |||||
[bilibili_zh]: http://www.bilibili.com/video/av9912938?bbid=F8173D95-FF96-47EF-B7F4-0779D698B8051978infoc | |||||
[bilibili_en1]: https://www.bilibili.com/video/av17624209/?from=search&seid=15848135050308500663 | |||||
[bilibili_en2]: https://www.bilibili.com/video/av17624412/?from=search&seid=15848135050308500663 | |||||
[GitHub with MathJax]: https://chrome.google.com/webstore/detail/ioemnmodlmafdkllaclgeombjnmnbima | |||||
[Typora]: https://typora.io/ | |||||
[honor code]: https://www.coursera.org/learn/machine-learning/supplement/nh65Z/machine-learning-honor-code | |||||
[CC BY-NC 4.0]: http://creativecommons.org/licenses/by-nc/4.0/ |
@@ -1,99 +0,0 @@ | |||||
% Version 1.000 | |||||
% | |||||
% Code provided by Ruslan Salakhutdinov and Geoff Hinton | |||||
% | |||||
% Permission is granted for anyone to copy, use, modify, or distribute this | |||||
% program and accompanying programs and documents for any purpose, provided | |||||
% this copyright notice is retained and prominently displayed, along with | |||||
% a note saying that the original programs are available from our | |||||
% web page. | |||||
% The programs and documents are distributed without any warranty, express or | |||||
% implied. As the programs were written for research purposes only, they have | |||||
% not been tested to the degree that would be advisable in any important | |||||
% application. All use of these programs is entirely at the user's own risk. | |||||
% This program reads raw MNIST files available at | |||||
% http://yann.lecun.com/exdb/mnist/ | |||||
% and converts them to files in matlab format | |||||
% Before using this program you first need to download files: | |||||
% train-images-idx3-ubyte.gz train-labels-idx1-ubyte.gz | |||||
% t10k-images-idx3-ubyte.gz t10k-labels-idx1-ubyte.gz | |||||
% and gunzip them. You need to allocate some space for this. | |||||
% This program was originally written by Yee Whye Teh | |||||
% Work with test files first | |||||
fprintf(1,'You first need to download files:\n train-images-idx3-ubyte.gz\n train-labels-idx1-ubyte.gz\n t10k-images-idx3-ubyte.gz\n t10k-labels-idx1-ubyte.gz\n from http://yann.lecun.com/exdb/mnist/\n and gunzip them \n'); | |||||
f = fopen('t10k-images-idx3-ubyte','r'); | |||||
[a,count] = fread(f,4,'int32'); | |||||
g = fopen('t10k-labels-idx1-ubyte','r'); | |||||
[l,count] = fread(g,2,'int32'); | |||||
fprintf(1,'Starting to convert Test MNIST images (prints 10 dots) \n'); | |||||
n = 1000; | |||||
Df = cell(1,10); | |||||
for d=0:9, | |||||
Df{d+1} = fopen(['test' num2str(d) '.ascii'],'w'); | |||||
end; | |||||
for i=1:10, | |||||
fprintf('.'); | |||||
rawimages = fread(f,28*28*n,'uchar'); | |||||
rawlabels = fread(g,n,'uchar'); | |||||
rawimages = reshape(rawimages,28*28,n); | |||||
for j=1:n, | |||||
fprintf(Df{rawlabels(j)+1},'%3d ',rawimages(:,j)); | |||||
fprintf(Df{rawlabels(j)+1},'\n'); | |||||
end; | |||||
end; | |||||
fprintf(1,'\n'); | |||||
for d=0:9, | |||||
fclose(Df{d+1}); | |||||
D = load(['test' num2str(d) '.ascii'],'-ascii'); | |||||
fprintf('%5d Digits of class %d\n',size(D,1),d); | |||||
save(['test' num2str(d) '.mat'],'D','-mat'); | |||||
end; | |||||
% Work with trainig files second | |||||
f = fopen('train-images-idx3-ubyte','r'); | |||||
[a,count] = fread(f,4,'int32'); | |||||
g = fopen('train-labels-idx1-ubyte','r'); | |||||
[l,count] = fread(g,2,'int32'); | |||||
fprintf(1,'Starting to convert Training MNIST images (prints 60 dots)\n'); | |||||
n = 1000; | |||||
Df = cell(1,10); | |||||
for d=0:9, | |||||
Df{d+1} = fopen(['digit' num2str(d) '.ascii'],'w'); | |||||
end; | |||||
for i=1:60, | |||||
fprintf('.'); | |||||
rawimages = fread(f,28*28*n,'uchar'); | |||||
rawlabels = fread(g,n,'uchar'); | |||||
rawimages = reshape(rawimages,28*28,n); | |||||
for j=1:n, | |||||
fprintf(Df{rawlabels(j)+1},'%3d ',rawimages(:,j)); | |||||
fprintf(Df{rawlabels(j)+1},'\n'); | |||||
end; | |||||
end; | |||||
fprintf(1,'\n'); | |||||
for d=0:9, | |||||
fclose(Df{d+1}); | |||||
D = load(['digit' num2str(d) '.ascii'],'-ascii'); | |||||
fprintf('%5d Digits of class %d\n',size(D,1),d); | |||||
save(['digit' num2str(d) '.mat'],'D','-mat'); | |||||
end; | |||||
dos('rm *.ascii'); | |||||
@@ -1,21 +0,0 @@ | |||||
function J = computeCost(X, y, theta) | |||||
%COMPUTECOST Compute cost for linear regression | |||||
% J = COMPUTECOST(X, y, theta) computes the cost of using theta as the | |||||
% parameter for linear regression to fit the data points in X and y | |||||
% Initialize some useful values | |||||
m = length(y); % number of training examples | |||||
% You need to return the following variables correctly | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Compute the cost of a particular choice of theta | |||||
% You should set J to the cost. | |||||
J = 1 / 2 / m * sum((X * theta - y) .^ 2); | |||||
%JVal = 1 / 2 / m * (X * theta - y)' * (X * theta -y); | |||||
%gradient = theta - 1 / m * (X' * (X * theta - y)); | |||||
% ========================================================================= | |||||
end |
@@ -1,22 +0,0 @@ | |||||
function J = computeCostMulti(X, y, theta) | |||||
%COMPUTECOSTMULTI Compute cost for linear regression with multiple variables | |||||
% J = COMPUTECOSTMULTI(X, y, theta) computes the cost of using theta as the | |||||
% parameter for linear regression to fit the data points in X and y | |||||
% Initialize some useful values | |||||
m = length(y); % number of training examples | |||||
% You need to return the following variables correctly | |||||
J = 0; | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Compute the cost of a particular choice of theta | |||||
% You should set J to the cost. | |||||
J = 1 / 2 / m * sum((X * theta - y) .^ 2); | |||||
%J = 1 / 2 / m * (X * theta - y)' * (X * theta - y); | |||||
% ========================================================================= | |||||
end |
@@ -1,122 +0,0 @@ | |||||
%% Machine Learning Online Class - Exercise 1: Linear Regression | |||||
% Instructions | |||||
% ------------ | |||||
% | |||||
% This file contains code that helps you get started on the | |||||
% linear exercise. You will need to complete the following functions | |||||
% in this exericse: | |||||
% | |||||
% warmUpExercise.m | |||||
% plotData.m | |||||
% gradientDescent.m | |||||
% computeCost.m | |||||
% gradientDescentMulti.m | |||||
% computeCostMulti.m | |||||
% featureNormalize.m | |||||
% normalEqn.m | |||||
% | |||||
% For this exercise, you will not need to change any code in this file, | |||||
% or any other files other than those mentioned above. | |||||
% | |||||
% x refers to the population size in 10,000s | |||||
% y refers to the profit in $10,000s | |||||
% | |||||
%% Initialization | |||||
clear ; close all; clc | |||||
%% ==================== Part 1: Basic Function ==================== | |||||
% Complete warmUpExercise.m | |||||
fprintf('Running warmUpExercise ... \n'); | |||||
fprintf('5x5 Identity Matrix: \n'); | |||||
warmUpExercise() | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ======================= Part 2: Plotting ======================= | |||||
fprintf('Plotting Data ...\n') | |||||
data = load('ex1data1.txt'); | |||||
X = data(:, 1); y = data(:, 2); | |||||
m = length(y); % number of training examples | |||||
% Plot Data | |||||
% Note: You have to complete the code in plotData.m | |||||
plotData(X, y); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% =================== Part 3: Gradient descent =================== | |||||
fprintf('Running Gradient Descent ...\n') | |||||
X = [ones(m, 1), data(:,1)]; % Add a column of ones to x | |||||
theta = zeros(2, 1); % initialize fitting parameters | |||||
% Some gradient descent settings | |||||
iterations = 1500; | |||||
alpha = 0.01; | |||||
% compute and display initial cost | |||||
computeCost(X, y, theta) | |||||
% run gradient descent | |||||
theta = gradientDescent(X, y, theta, alpha, iterations); | |||||
% print theta to screen | |||||
fprintf('Theta found by gradient descent: '); | |||||
fprintf('%f %f \n', theta(1), theta(2)); | |||||
% Plot the linear fit | |||||
hold on; % keep previous plot visible | |||||
plot(X(:,2), X*theta, '-') | |||||
legend('Training data', 'Linear regression') | |||||
hold off % don't overlay any more plots on this figure | |||||
% Predict values for population sizes of 35,000 and 70,000 | |||||
predict1 = [1, 3.5] *theta; | |||||
fprintf('For population = 35,000, we predict a profit of %f\n',... | |||||
predict1*10000); | |||||
predict2 = [1, 7] * theta; | |||||
fprintf('For population = 70,000, we predict a profit of %f\n',... | |||||
predict2*10000); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ============= Part 4: Visualizing J(theta_0, theta_1) ============= | |||||
fprintf('Visualizing J(theta_0, theta_1) ...\n') | |||||
% Grid over which we will calculate J | |||||
theta0_vals = linspace(-10, 10, 100); | |||||
theta1_vals = linspace(-1, 4, 100);%从-1到4之间取100个数组成一个向量 | |||||
% initialize J_vals to a matrix of 0's | |||||
J_vals = zeros(length(theta0_vals), length(theta1_vals)); | |||||
% Fill out J_vals | |||||
for i = 1:length(theta0_vals) | |||||
for j = 1:length(theta1_vals) | |||||
t = [theta0_vals(i); theta1_vals(j)]; | |||||
J_vals(i,j) = computeCost(X, y, t); | |||||
end | |||||
end | |||||
% Because of the way meshgrids work in the surf command, we need to | |||||
% transpose J_vals before calling surf, or else the axes will be flipped | |||||
J_vals = J_vals'; | |||||
% Surface plot | |||||
figure; | |||||
surf(theta0_vals, theta1_vals, J_vals)%画出三维图形 | |||||
xlabel('\theta_0'); ylabel('\theta_1'); | |||||
% Contour plot 轮廓图 | |||||
figure; | |||||
% Plot J_vals as 15 contours spaced logarithmically between 0.01 and 100 | |||||
contour(theta0_vals, theta1_vals, J_vals, logspace(-2, 3, 20)) | |||||
xlabel('\theta_0'); ylabel('\theta_1'); | |||||
hold on; | |||||
plot(theta(1), theta(2), 'rx', 'MarkerSize', 10, 'LineWidth', 2); |
@@ -1,201 +0,0 @@ | |||||
%% Machine Learning Online Class | |||||
% Exercise 1: Linear regression with multiple variables | |||||
% | |||||
% Instructions | |||||
% ------------ | |||||
% | |||||
% This file contains code that helps you get started on the | |||||
% linear regression exercise. | |||||
% | |||||
% You will need to complete the following functions in this | |||||
% exericse: | |||||
% | |||||
% warmUpExercise.m | |||||
% plotData.m | |||||
% gradientDescent.m | |||||
% computeCost.m | |||||
% gradientDescentMulti.m | |||||
% computeCostMulti.m | |||||
% featureNormalize.m | |||||
% normalEqn.m | |||||
% | |||||
% For this part of the exercise, you will need to change some | |||||
% parts of the code below for various experiments (e.g., changing | |||||
% learning rates). | |||||
% | |||||
%% Initialization | |||||
%% ================ Part 1: Feature Normalization ================ | |||||
%% Clear and Close Figures | |||||
clear ; close all; clc | |||||
fprintf('Loading data ...\n'); | |||||
%% Load Data | |||||
data = load('ex1data2.txt'); | |||||
X = data(:, 1:2); | |||||
y = data(:, 3); | |||||
m = length(y); | |||||
% Print out some data points | |||||
fprintf('First 10 examples from the dataset: \n'); | |||||
fprintf(' x = [%.0f %.0f], y = %.0f \n', [X(1:10,:) y(1:10,:)]'); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
% Scale features and set them to zero mean | |||||
fprintf('Normalizing Features ...\n'); | |||||
[X mu sigma] = featureNormalize(X); | |||||
% Add intercept term to X | |||||
X = [ones(m, 1) X]; | |||||
%% ================ Part 2: Gradient Descent ================ | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: We have provided you with the following starter | |||||
% code that runs gradient descent with a particular | |||||
% learning rate (alpha). | |||||
% | |||||
% Your task is to first make sure that your functions - | |||||
% computeCost and gradientDescent already work with | |||||
% this starter code and support multiple variables. | |||||
% | |||||
% After that, try running gradient descent with | |||||
% different values of alpha and see which one gives | |||||
% you the best result. | |||||
% | |||||
% Finally, you should complete the code at the end | |||||
% to predict the price of a 1650 sq-ft, 3 br house. | |||||
% | |||||
% Hint: By using the 'hold on' command, you can plot multiple | |||||
% graphs on the same figure. | |||||
% | |||||
% Hint: At prediction, make sure you do the same feature normalization. | |||||
% | |||||
fprintf('Running gradient descent ...\n'); | |||||
% Choose some alpha value | |||||
alpha = 0.001; | |||||
num_iters = 4000; | |||||
% Init Theta and Run Gradient Descent | |||||
theta = zeros(3, 1); | |||||
[theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters); | |||||
%[theta, J_history] = gradientDescentMulti(X, y, zeros(3, 1), 0.001, 4000); | |||||
%plot(1:numel(J_history), J_history, '-bc', 'LineWidth', 2); | |||||
%price = theta(1) + (1650 - mu(1)) / sigma(1) * theta(2) + (3 - mu(2)) / sigma(2) * theta(3) % You should change this | |||||
%price = theta(1) + (15 - mu(1)) / sigma(1) * theta(2) + (1 - mu(2)) / sigma(2) * theta(3) + (2 - mu(3)) / sigma(3) * theta(4) % You should change this | |||||
fprintf(['Predicted price of a 1650 sq-ft, 3 br house ' ... | |||||
'(using gradient descent):\n $%f\n'], price); | |||||
% Plot the convergence graph | |||||
figure; | |||||
plot(1:numel(J_history), J_history, '-b', 'LineWidth', 2); | |||||
xlabel('Number of iterations'); | |||||
ylabel('Cost J'); | |||||
% Display gradient descent's result | |||||
fprintf('Theta computed from gradient descent: \n'); | |||||
fprintf(' %f \n', theta); | |||||
fprintf('\n'); | |||||
% Estimate the price of a 1650 sq-ft, 3 br house | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Recall that the first column of X is all-ones. Thus, it does | |||||
% not need to be normalized. | |||||
price = 0; % You should change this | |||||
% ============================================================ | |||||
fprintf(['Predicted price of a 1650 sq-ft, 3 br house ' ... | |||||
'(using gradient descent):\n $%f\n'], price); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ================ Part 3: Normal Equations ================ | |||||
fprintf('Solving with normal equations...\n'); | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: The following code computes the closed form | |||||
% solution for linear regression using the normal | |||||
% equations. You should complete the code in | |||||
% normalEqn.m | |||||
% | |||||
% After doing so, you should complete this code | |||||
% to predict the price of a 1650 sq-ft, 3 br house. | |||||
% | |||||
%% Load Data | |||||
data = csvread('ex1data2.txt'); | |||||
X = data(:, 1:2); | |||||
y = data(:, 3); | |||||
m = length(y); | |||||
% Add intercept term to X | |||||
X = [ones(m, 1) X]; | |||||
% Calculate the parameters from the normal equation | |||||
theta = normalEqn(X, y); | |||||
% Display normal equation's result | |||||
fprintf('Theta computed from the normal equations: \n'); | |||||
fprintf(' %f \n', theta); | |||||
fprintf('\n'); | |||||
% Estimate the price of a 1650 sq-ft, 3 br house | |||||
% ====================== YOUR CODE HERE ====================== | |||||
price = theta(1) + 1650 * theta(2) + 3 * theta(3); % You should change this | |||||
% ============================================================ | |||||
fprintf(['Predicted price of a 1650 sq-ft, 3 br house ' ... | |||||
'(using normal equations):\n $%f\n'], price); | |||||
%% ============= Part 4: Visualizing J(theta_0, theta_1) ============= | |||||
fprintf('Visualizing J(theta_0, theta_1) ...\n') | |||||
% Grid over which we will calculate J | |||||
theta0_vals = linspace(-10, 10, 100); | |||||
theta1_vals = linspace(-1, 4, 100);%从-1到4之间取100个数组成一个向量 | |||||
theta2_vals = linspace(-1, 4, 100);%从-1到4之间取100个数组成一个向量 | |||||
% initialize J_vals to a matrix of 0's | |||||
J_vals = zeros(length(theta0_vals), length(theta1_vals), length(theta1_vals)); | |||||
% Fill out J_vals | |||||
for i = 1:length(theta0_vals) | |||||
for j = 1:length(theta1_vals) | |||||
t = [theta0_vals(i); theta1_vals(j)]; | |||||
J_vals(i,j) = computeCostMulti(X, y, t); | |||||
end | |||||
end | |||||
% Because of the way meshgrids work in the surf command, we need to | |||||
% transpose J_vals before calling surf, or else the axes will be flipped | |||||
J_vals = J_vals'; | |||||
% Surface plot | |||||
figure; | |||||
surf(theta0_vals, theta1_vals, J_vals)%画出三维图形 | |||||
xlabel('\theta_0'); ylabel('\theta_1'); | |||||
% Contour plot 轮廓图 | |||||
figure; | |||||
% Plot J_vals as 15 contours spaced logarithmically between 0.01 and 100 | |||||
contour(theta0_vals, theta1_vals, J_vals, logspace(-2, 3, 20)) | |||||
xlabel('\theta_0'); ylabel('\theta_1'); | |||||
hold on; | |||||
plot(theta(1), theta(2), 'rx', 'MarkerSize', 10, 'LineWidth', 2); |
@@ -1,97 +0,0 @@ | |||||
6.1101,17.592 | |||||
5.5277,9.1302 | |||||
8.5186,13.662 | |||||
7.0032,11.854 | |||||
5.8598,6.8233 | |||||
8.3829,11.886 | |||||
7.4764,4.3483 | |||||
8.5781,12 | |||||
6.4862,6.5987 | |||||
5.0546,3.8166 | |||||
5.7107,3.2522 | |||||
14.164,15.505 | |||||
5.734,3.1551 | |||||
8.4084,7.2258 | |||||
5.6407,0.71618 | |||||
5.3794,3.5129 | |||||
6.3654,5.3048 | |||||
5.1301,0.56077 | |||||
6.4296,3.6518 | |||||
7.0708,5.3893 | |||||
6.1891,3.1386 | |||||
20.27,21.767 | |||||
5.4901,4.263 | |||||
6.3261,5.1875 | |||||
5.5649,3.0825 | |||||
18.945,22.638 | |||||
12.828,13.501 | |||||
10.957,7.0467 | |||||
13.176,14.692 | |||||
22.203,24.147 | |||||
5.2524,-1.22 | |||||
6.5894,5.9966 | |||||
9.2482,12.134 | |||||
5.8918,1.8495 | |||||
8.2111,6.5426 | |||||
7.9334,4.5623 | |||||
8.0959,4.1164 | |||||
5.6063,3.3928 | |||||
12.836,10.117 | |||||
6.3534,5.4974 | |||||
5.4069,0.55657 | |||||
6.8825,3.9115 | |||||
11.708,5.3854 | |||||
5.7737,2.4406 | |||||
7.8247,6.7318 | |||||
7.0931,1.0463 | |||||
5.0702,5.1337 | |||||
5.8014,1.844 | |||||
11.7,8.0043 | |||||
5.5416,1.0179 | |||||
7.5402,6.7504 | |||||
5.3077,1.8396 | |||||
7.4239,4.2885 | |||||
7.6031,4.9981 | |||||
6.3328,1.4233 | |||||
6.3589,-1.4211 | |||||
6.2742,2.4756 | |||||
5.6397,4.6042 | |||||
9.3102,3.9624 | |||||
9.4536,5.4141 | |||||
8.8254,5.1694 | |||||
5.1793,-0.74279 | |||||
21.279,17.929 | |||||
14.908,12.054 | |||||
18.959,17.054 | |||||
7.2182,4.8852 | |||||
8.2951,5.7442 | |||||
10.236,7.7754 | |||||
5.4994,1.0173 | |||||
20.341,20.992 | |||||
10.136,6.6799 | |||||
7.3345,4.0259 | |||||
6.0062,1.2784 | |||||
7.2259,3.3411 | |||||
5.0269,-2.6807 | |||||
6.5479,0.29678 | |||||
7.5386,3.8845 | |||||
5.0365,5.7014 | |||||
10.274,6.7526 | |||||
5.1077,2.0576 | |||||
5.7292,0.47953 | |||||
5.1884,0.20421 | |||||
6.3557,0.67861 | |||||
9.7687,7.5435 | |||||
6.5159,5.3436 | |||||
8.5172,4.2415 | |||||
9.1802,6.7981 | |||||
6.002,0.92695 | |||||
5.5204,0.152 | |||||
5.0594,2.8214 | |||||
5.7077,1.8451 | |||||
7.6366,4.2959 | |||||
5.8707,7.2029 | |||||
5.3054,1.9869 | |||||
8.2934,0.14454 | |||||
13.394,9.0551 | |||||
5.4369,0.61705 |
@@ -1,47 +0,0 @@ | |||||
2104,3,399900 | |||||
1600,3,329900 | |||||
2400,3,369000 | |||||
1416,2,232000 | |||||
3000,4,539900 | |||||
1985,4,299900 | |||||
1534,3,314900 | |||||
1427,3,198999 | |||||
1380,3,212000 | |||||
1494,3,242500 | |||||
1940,4,239999 | |||||
2000,3,347000 | |||||
1890,3,329999 | |||||
4478,5,699900 | |||||
1268,3,259900 | |||||
2300,4,449900 | |||||
1320,2,299900 | |||||
1236,3,199900 | |||||
2609,4,499998 | |||||
3031,4,599000 | |||||
1767,3,252900 | |||||
1888,2,255000 | |||||
1604,3,242900 | |||||
1962,4,259900 | |||||
3890,3,573900 | |||||
1100,3,249900 | |||||
1458,3,464500 | |||||
2526,3,469000 | |||||
2200,3,475000 | |||||
2637,3,299900 | |||||
1839,2,349900 | |||||
1000,1,169900 | |||||
2040,4,314900 | |||||
3137,3,579900 | |||||
1811,4,285900 | |||||
1437,3,249900 | |||||
1239,3,229900 | |||||
2132,4,345000 | |||||
4215,4,549000 | |||||
2162,4,287000 | |||||
1664,2,368500 | |||||
2238,3,329900 | |||||
2567,4,314000 | |||||
1200,3,299000 | |||||
852,2,179900 | |||||
1852,4,299900 | |||||
1203,3,239500 |
@@ -1,47 +0,0 @@ | |||||
2104,3,399900 | |||||
1600,3,329900 | |||||
2400,3,369000 | |||||
1416,2,232000 | |||||
3000,4,539900 | |||||
1985,4,299900 | |||||
1534,3,314900 | |||||
1427,3,198999 | |||||
1380,3,212000 | |||||
1494,3,242500 | |||||
1940,4,239999 | |||||
2000,3,347000 | |||||
1890,3,329999 | |||||
4478,5,699900 | |||||
1268,3,259900 | |||||
2300,4,449900 | |||||
1320,2,299900 | |||||
1236,3,199900 | |||||
2609,4,499998 | |||||
3031,4,599000 | |||||
1767,3,252900 | |||||
1888,2,255000 | |||||
1604,3,242900 | |||||
1962,4,259900 | |||||
3890,3,573900 | |||||
1100,3,249900 | |||||
1458,3,464500 | |||||
2526,3,469000 | |||||
2200,3,475000 | |||||
2637,3,299900 | |||||
1839,2,349900 | |||||
1000,1,169900 | |||||
2040,4,314900 | |||||
3137,3,579900 | |||||
1811,4,285900 | |||||
1437,3,249900 | |||||
1239,3,229900 | |||||
2132,4,345000 | |||||
4215,4,549000 | |||||
2162,4,287000 | |||||
1664,2,368500 | |||||
2238,3,329900 | |||||
2567,4,314000 | |||||
1200,3,299000 | |||||
852,2,179900 | |||||
1852,4,299900 | |||||
1203,3,239500 |
@@ -1,40 +0,0 @@ | |||||
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. | |||||
% You need to set these values correctly | |||||
X_norm = X; | |||||
mu = zeros(1, size(X, 2)); | |||||
sigma = zeros(1, size(X, 2)); | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: First, for each feature dimension, compute the mean | |||||
% of the feature and subtract it from the dataset, | |||||
% storing the mean value in mu. Next, compute the | |||||
% standard deviation of each feature and divide | |||||
% each feature by it's standard deviation, storing | |||||
% the standard deviation in sigma. | |||||
% | |||||
% Note that X is a matrix where each column is a | |||||
% feature and each row is an example. You need | |||||
% to perform the normalization separately for | |||||
% each feature. | |||||
% | |||||
% Hint: You might find the 'mean' and 'std' functions useful. | |||||
% | |||||
mu = mean(X_norm); | |||||
sigma = std(X_norm); | |||||
X_norm = (X_norm .- mu) ./ sigma; | |||||
% ============================================================ | |||||
end |
@@ -1,31 +0,0 @@ | |||||
function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters) | |||||
%GRADIENTDESCENT Performs gradient descent to learn theta | |||||
% theta = GRADIENTDESENT(X, y, theta, alpha, num_iters) updates theta by | |||||
% taking num_iters gradient steps with learning rate alpha | |||||
% Initialize some useful values | |||||
m = length(y); % number of training examples | |||||
J_history = zeros(num_iters, 1); | |||||
for iter = 1:num_iters | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Perform a single gradient step on the parameter vector | |||||
% theta. | |||||
% | |||||
% Hint: While debugging, it can be useful to print out the values | |||||
% of the cost function (computeCost) and gradient here. | |||||
% | |||||
theta = theta - alpha / m * (X' * (X * theta - y)); | |||||
%X * theta 代表了hθ | |||||
%X' (hθ-y)表示将每一个X中的元素(n * m)与(hθ-y)(m * 1)相乘,从而得到新的theta矩阵(n * 1) | |||||
% ============================================================ | |||||
% Save the cost J in every iteration | |||||
J_history(iter) = computeCost(X, y, theta); | |||||
end | |||||
end |
@@ -1,31 +0,0 @@ | |||||
function [theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters) | |||||
%GRADIENTDESCENTMULTI Performs gradient descent to learn theta | |||||
% theta = GRADIENTDESCENTMULTI(x, y, theta, alpha, num_iters) updates theta by | |||||
% taking num_iters gradient steps with learning rate alpha | |||||
% Initialize some useful values | |||||
m = length(y); % number of training examples | |||||
J_history = zeros(num_iters, 1); | |||||
for iter = 1:num_iters | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Perform a single gradient step on the parameter vector | |||||
% theta. | |||||
% | |||||
% Hint: While debugging, it can be useful to print out the values | |||||
% of the cost function (computeCostMulti) and gradient here. | |||||
% | |||||
theta = theta - alpha / m * (X' * (X * theta - y)); | |||||
%X * theta 代表了hθ | |||||
%X' (hθ-y)表示将每一个X中的元素(n * m)与(hθ-y)(m * 1)相乘,从而得到新的theta矩阵(n * 1) | |||||
% ============================================================ | |||||
% Save the cost J in every iteration | |||||
J_history(iter) = computeCostMulti(X, y, theta); | |||||
end | |||||
end |
@@ -1,41 +0,0 @@ | |||||
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 |
@@ -1,74 +0,0 @@ | |||||
============================================================================ | |||||
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 |
@@ -1,25 +0,0 @@ | |||||
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. |
@@ -1,394 +0,0 @@ | |||||
=============================================================================== | |||||
= 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). |
@@ -1,32 +0,0 @@ | |||||
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 | |||||
@@ -1,566 +0,0 @@ | |||||
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 | |||||
@@ -1,528 +0,0 @@ | |||||
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 | |||||
@@ -1,33 +0,0 @@ | |||||
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 | |||||
@@ -1,475 +0,0 @@ | |||||
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 |
@@ -1,504 +0,0 @@ | |||||
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(:)'; |
@@ -1,40 +0,0 @@ | |||||
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 | |||||
@@ -1,30 +0,0 @@ | |||||
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 |
@@ -1,126 +0,0 @@ | |||||
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( ... | |||||
'!! Submission failed: unexpected error: %s\n', ... | |||||
e.message); | |||||
fprintf('!! Please try again later.\n'); | |||||
return | |||||
end | |||||
if isfield(response, 'errorMessage') | |||||
fprintf('!! Submission failed: %s\n', response.errorMessage); | |||||
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(); | |||||
params = {'jsonBody', body}; | |||||
% responseBody = urlread(submissionUrl, 'post', params); | |||||
[code, responseBody] = system(sprintf('echo jsonBody=%s | curl -k -X POST -d @- %s', body, submissionUrl)); | |||||
response = loadjson(responseBody); | |||||
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 | |||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||||
% | |||||
% Service configuration | |||||
% | |||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||||
function submissionUrl = submissionUrl() | |||||
submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1'; | |||||
end |
@@ -1,23 +0,0 @@ | |||||
function [theta] = normalEqn(X, y) | |||||
%NORMALEQN Computes the closed-form solution to linear regression | |||||
% NORMALEQN(X,y) computes the closed-form solution to linear | |||||
% regression using the normal equations. | |||||
theta = zeros(size(X, 2), 1); | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Complete the code to compute the closed form solution | |||||
% to linear regression and put the result in theta. | |||||
% | |||||
% ---------------------- Sample Solution ---------------------- | |||||
theta = pinv(X' * X) * X' * y; | |||||
% ------------------------------------------------------------- | |||||
% ============================================================ | |||||
end |
@@ -1,29 +0,0 @@ | |||||
function plotData(x, y) | |||||
%PLOTDATA Plots the data points x and y into a new figure | |||||
% PLOTDATA(x,y) plots the data points and gives the figure axes labels of | |||||
% population and profit. | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Plot the training data into a figure using the | |||||
% "figure" and "plot" commands. Set the axes labels using | |||||
% the "xlabel" and "ylabel" commands. Assume the | |||||
% population and revenue data have been passed in | |||||
% as the x and y arguments of this function. | |||||
% | |||||
% Hint: You can use the 'rx' option with plot to have the markers | |||||
% appear as red crosses. Furthermore, you can make the | |||||
% markers larger by using plot(..., 'rx', 'MarkerSize', 10); | |||||
figure; % open a new figure window | |||||
plot(x, y, 'rx', 'MarkerSize', 10); | |||||
xlabel('xlabel'); | |||||
ylabel('ylabel'); | |||||
% ============================================================ | |||||
end |
@@ -1,69 +0,0 @@ | |||||
function submit() | |||||
addpath('./lib'); | |||||
conf.assignmentSlug = 'linear-regression'; | |||||
conf.itemName = 'Linear Regression with Multiple Variables'; | |||||
conf.partArrays = { ... | |||||
{ ... | |||||
'1', ... | |||||
{ 'warmUpExercise.m' }, ... | |||||
'Warm-up Exercise', ... | |||||
}, ... | |||||
{ ... | |||||
'2', ... | |||||
{ 'computeCost.m' }, ... | |||||
'Computing Cost (for One Variable)', ... | |||||
}, ... | |||||
{ ... | |||||
'3', ... | |||||
{ 'gradientDescent.m' }, ... | |||||
'Gradient Descent (for One Variable)', ... | |||||
}, ... | |||||
{ ... | |||||
'4', ... | |||||
{ 'featureNormalize.m' }, ... | |||||
'Feature Normalization', ... | |||||
}, ... | |||||
{ ... | |||||
'5', ... | |||||
{ 'computeCostMulti.m' }, ... | |||||
'Computing Cost (for Multiple Variables)', ... | |||||
}, ... | |||||
{ ... | |||||
'6', ... | |||||
{ 'gradientDescentMulti.m' }, ... | |||||
'Gradient Descent (for Multiple Variables)', ... | |||||
}, ... | |||||
{ ... | |||||
'7', ... | |||||
{ 'normalEqn.m' }, ... | |||||
'Normal Equations', ... | |||||
}, ... | |||||
}; | |||||
conf.output = @output; | |||||
submitWithConfiguration(conf); | |||||
end | |||||
function out = output(partId) | |||||
% Random Test Cases | |||||
X1 = [ones(20,1) (exp(1) + exp(2) * (0.1:0.1:2))']; | |||||
Y1 = X1(:,2) + sin(X1(:,1)) + cos(X1(:,2)); | |||||
X2 = [X1 X1(:,2).^0.5 X1(:,2).^0.25]; | |||||
Y2 = Y1.^0.5 + Y1; | |||||
if partId == '1' | |||||
out = sprintf('%0.5f ', warmUpExercise()); | |||||
elseif partId == '2' | |||||
out = sprintf('%0.5f ', computeCost(X1, Y1, [0.5 -0.5]')); | |||||
elseif partId == '3' | |||||
out = sprintf('%0.5f ', gradientDescent(X1, Y1, [0.5 -0.5]', 0.01, 10)); | |||||
elseif partId == '4' | |||||
out = sprintf('%0.5f ', featureNormalize(X2(:,2:4))); | |||||
elseif partId == '5' | |||||
out = sprintf('%0.5f ', computeCostMulti(X2, Y2, [0.1 0.2 0.3 0.4]')); | |||||
elseif partId == '6' | |||||
out = sprintf('%0.5f ', gradientDescentMulti(X2, Y2, [-0.1 -0.2 -0.3 -0.4]', 0.01, 10)); | |||||
elseif partId == '7' | |||||
out = sprintf('%0.5f ', normalEqn(X2, Y2)); | |||||
end | |||||
end |
@@ -1,6 +0,0 @@ | |||||
function [JVal, gradient] = functionCost(theta) | |||||
JVal = theta' * theta; | |||||
gradient = theta; | |||||
% ========================================================================= | |||||
end |
@@ -1,15 +0,0 @@ | |||||
# Created by Octave 4.0.3, Mon Nov 14 10:25:22 2016 GMT <unknown@DESKTOP-1S2UOSP> | |||||
# name: email | |||||
# type: sq_string | |||||
# elements: 1 | |||||
# length: 16 | |||||
scruel@vip.qq.com | |||||
# name: token | |||||
# type: sq_string | |||||
# elements: 1 | |||||
# length: 16 | |||||
A3Wc4pI1qYjCUaRB | |||||
@@ -1,21 +0,0 @@ | |||||
function A = warmUpExercise() | |||||
%WARMUPEXERCISE Example function in octave | |||||
% A = WARMUPEXERCISE() is an example function that returns the 5x5 identity matrix | |||||
A = []; | |||||
% ============= YOUR CODE HERE ============== | |||||
% Instructions: Return the 5x5 identity matrix | |||||
% In octave, we return values by defining which variables | |||||
% represent the return values (at the top of the file) | |||||
% and then set them accordingly. | |||||
A = eye(5); | |||||
% =========================================== | |||||
end |
@@ -1,32 +0,0 @@ | |||||
function [J, grad] = costFunction(theta, X, y) | |||||
%COSTFUNCTION Compute cost and gradient for logistic regression | |||||
% J = COSTFUNCTION(theta, X, y) computes the cost of using theta as the | |||||
% parameter for logistic regression and the gradient of the cost | |||||
% w.r.t. to the parameters. | |||||
% Initialize some useful values | |||||
m = length(y); % number of training examples | |||||
% You need to return the following variables correctly | |||||
J = 0; | |||||
grad = zeros(size(theta)); | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Compute the cost of a particular choice of theta. | |||||
% You should set J to the cost. | |||||
% Compute the partial derivatives and set grad to the partial | |||||
% derivatives of the cost w.r.t. each parameter in theta | |||||
% | |||||
% Note: grad should have the same dimensions as theta | |||||
% | |||||
hx = sigmoid(X * theta); %hypothesis, m * 1 | |||||
J = 1 / m * sum(-y' * log(hx) - (1 .- y)' * log(1 -hx)); | |||||
grad = 1 / m * X' *(hx - y); | |||||
% ============================================================= | |||||
end |
@@ -1,32 +0,0 @@ | |||||
function [J, grad] = costFunctionReg(theta, X, y, lambda) | |||||
%COSTFUNCTIONREG Compute cost and gradient for logistic regression with regularization | |||||
% J = COSTFUNCTIONREG(theta, X, y, lambda) computes the cost of using | |||||
% theta as the parameter for regularized logistic regression and the | |||||
% gradient of the cost w.r.t. to the parameters. | |||||
% Initialize some useful values | |||||
m = length(y); % number of training examples | |||||
% You need to return the following variables correctly | |||||
J = 0; | |||||
grad = zeros(size(theta)); | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Compute the cost of a particular choice of theta. | |||||
% You should set J to the cost. | |||||
% Compute the partial derivatives and set grad to the partial | |||||
% derivatives of the cost w.r.t. each parameter in theta | |||||
hx = sigmoid(X * theta); %hypothesis, m * 1 | |||||
J = 1 / m * sum(-y' * log(hx) - (1 - y)' * log(1 - hx)) + lambda / (2 * m) * theta(2:end)' * theta(2:end); | |||||
gradf = (1 / m) * (X(:, 1)' * (hx - y)); | |||||
gradb = (1 / m) * (X(:, 2:end)' * (hx - y)) + lambda * theta(2:end) / m; | |||||
grad = [gradf;gradb]; | |||||
% ============================================================= | |||||
end |
@@ -1,135 +0,0 @@ | |||||
%% Machine Learning Online Class - Exercise 2: Logistic Regression | |||||
% | |||||
% Instructions | |||||
% ------------ | |||||
% | |||||
% This file contains code that helps you get started on the logistic | |||||
% regression exercise. You will need to complete the following functions | |||||
% in this exericse: | |||||
% | |||||
% sigmoid.m | |||||
% costFunction.m | |||||
% predict.m | |||||
% costFunctionReg.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 | |||||
%% Load Data | |||||
% The first two columns contains the exam scores and the third column | |||||
% contains the label. | |||||
data = load('ex2data1.txt'); | |||||
X = data(:, [1, 2]); y = data(:, 3); | |||||
%% ==================== Part 1: Plotting ==================== | |||||
% We start the exercise by first plotting the data to understand the | |||||
% the problem we are working with. | |||||
fprintf(['Plotting data with + indicating (y = 1) examples and o ' ... | |||||
'indicating (y = 0) examples.\n']); | |||||
plotData(X, y); | |||||
% Put some labels | |||||
hold on; | |||||
% Labels and Legend | |||||
xlabel('Exam 1 score') | |||||
ylabel('Exam 2 score') | |||||
% Specified in plot order | |||||
legend('Admitted', 'Not admitted') | |||||
hold off; | |||||
fprintf('\nProgram paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ============ Part 2: Compute Cost and Gradient ============ | |||||
% In this part of the exercise, you will implement the cost and gradient | |||||
% for logistic regression. You neeed to complete the code in | |||||
% costFunction.m | |||||
% Setup the data matrix appropriately, and add ones for the intercept term | |||||
[m, n] = size(X); | |||||
% Add intercept term to x and X_test | |||||
X = [ones(m, 1) X]; | |||||
% Initialize fitting parameters | |||||
initial_theta = zeros(n + 1, 1); | |||||
% Compute and display initial cost and gradient | |||||
[cost, grad] = costFunction(initial_theta, X, y); | |||||
fprintf('Cost at initial theta (zeros): %f\n', cost); | |||||
fprintf('Gradient at initial theta (zeros): \n'); | |||||
fprintf(' %f \n', grad); | |||||
fprintf('\nProgram paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ============= Part 3: Optimizing using fminunc ============= | |||||
% In this exercise, you will use a built-in function (fminunc) to find the | |||||
% optimal parameters theta. | |||||
% Set options for fminunc | |||||
options = optimset('GradObj', 'on', 'MaxIter', 400); | |||||
% Run fminunc to obtain the optimal theta | |||||
% This function will return theta and the cost | |||||
[theta, cost] = ... | |||||
fminunc(@(t)(costFunction(t, X, y)), initial_theta, options); | |||||
% Print theta to screen | |||||
fprintf('Cost at theta found by fminunc: %f\n', cost); | |||||
fprintf('theta: \n'); | |||||
fprintf(' %f \n', theta); | |||||
% Plot Boundary | |||||
plotDecisionBoundary(theta, X, y); | |||||
% Put some labels | |||||
hold on; | |||||
% Labels and Legend | |||||
xlabel('Exam 1 score') | |||||
ylabel('Exam 2 score') | |||||
% Specified in plot order | |||||
legend('Admitted', 'Not admitted') | |||||
hold off; | |||||
fprintf('\nProgram paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ============== Part 4: Predict and Accuracies ============== | |||||
% After learning the parameters, you'll like to use it to predict the outcomes | |||||
% on unseen data. In this part, you will use the logistic regression model | |||||
% to predict the probability that a student with score 45 on exam 1 and | |||||
% score 85 on exam 2 will be admitted. | |||||
% | |||||
% Furthermore, you will compute the training and test set accuracies of | |||||
% our model. | |||||
% | |||||
% Your task is to complete the code in predict.m | |||||
% Predict probability for a student with score 45 on exam 1 | |||||
% and score 85 on exam 2 | |||||
prob = sigmoid([1 45 85] * theta); | |||||
fprintf(['For a student with scores 45 and 85, we predict an admission ' ... | |||||
'probability of %f\n\n'], prob); | |||||
% Compute accuracy on our training set | |||||
p = predict(theta, X); | |||||
fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100); | |||||
fprintf('\nProgram paused. Press enter to continue.\n'); | |||||
pause; | |||||
@@ -1,116 +0,0 @@ | |||||
%% Machine Learning Online Class - Exercise 2: Logistic Regression | |||||
% | |||||
% Instructions | |||||
% ------------ | |||||
% | |||||
% This file contains code that helps you get started on the second part | |||||
% of the exercise which covers regularization with logistic regression. | |||||
% | |||||
% You will need to complete the following functions in this exericse: | |||||
% | |||||
% sigmoid.m | |||||
% costFunction.m | |||||
% predict.m | |||||
% costFunctionReg.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 | |||||
%% Load Data | |||||
% The first two columns contains the X values and the third column | |||||
% contains the label (y). | |||||
data = load('ex2data2.txt'); | |||||
X = data(:, [1, 2]); y = data(:, 3); | |||||
plotData(X, y); | |||||
% Put some labels | |||||
hold on; | |||||
% Labels and Legend | |||||
xlabel('Microchip Test 1') | |||||
ylabel('Microchip Test 2') | |||||
% Specified in plot order | |||||
legend('y = 1', 'y = 0') | |||||
hold off; | |||||
%% =========== Part 1: Regularized Logistic Regression ============ | |||||
% In this part, you are given a dataset with data points that are not | |||||
% linearly separable. However, you would still like to use logistic | |||||
% regression to classify the data points. | |||||
% | |||||
% To do so, you introduce more features to use -- in particular, you add | |||||
% polynomial features to our data matrix (similar to polynomial | |||||
% regression). | |||||
% | |||||
% Add Polynomial Features | |||||
% Note that mapFeature also adds a column of ones for us, so the intercept | |||||
% term is handled | |||||
X = mapFeature(X(:,1), X(:,2)); | |||||
% Initialize fitting parameters | |||||
initial_theta = zeros(size(X, 2), 1); | |||||
% Set regularization parameter lambda to 1 | |||||
lambda = 1; | |||||
% Compute and display initial cost and gradient for regularized logistic | |||||
% regression | |||||
[cost, grad] = costFunctionReg(initial_theta, X, y, lambda); | |||||
fprintf('Cost at initial theta (zeros): %f\n', cost); | |||||
fprintf('\nProgram paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ============= Part 2: Regularization and Accuracies ============= | |||||
% Optional Exercise: | |||||
% In this part, you will get to try different values of lambda and | |||||
% see how regularization affects the decision coundart | |||||
% | |||||
% Try the following values of lambda (0, 1, 10, 100). | |||||
% | |||||
% How does the decision boundary change when you vary lambda? How does | |||||
% the training set accuracy vary? | |||||
% | |||||
% Initialize fitting parameters | |||||
initial_theta = zeros(size(X, 2), 1); | |||||
% Set regularization parameter lambda to 1 (you should vary this) | |||||
lambda = 100; | |||||
% Set Options | |||||
options = optimset('GradObj', 'on', 'MaxIter', 400); | |||||
% Optimize | |||||
[theta, J, exit_flag] = ... | |||||
fminunc(@(t)(costFunctionReg(t, X, y, 1)), initial_theta, options); | |||||
% Plot Boundary | |||||
plotDecisionBoundary(theta, X, y); | |||||
hold on; | |||||
title(sprintf('lambda = %g', lambda)) | |||||
% Labels and Legend | |||||
xlabel('Microchip Test 1') | |||||
ylabel('Microchip Test 2') | |||||
legend('y = 1', 'y = 0', 'Decision boundary') | |||||
hold off; | |||||
% Compute accuracy on our training set | |||||
p = predict(theta, X); | |||||
fprintf('Train Accuracy: %f\n', mean(double(p == y)) * 100); | |||||
@@ -1,100 +0,0 @@ | |||||
0,34.62365962,78.02469282 | |||||
0,30.28671077,43.89499752 | |||||
0,35.84740877,72.90219803 | |||||
1,60.18259939,86.3085521 | |||||
1,79.03273605,75.34437644 | |||||
0,45.08327748,56.31637178 | |||||
1,61.10666454,96.51142588 | |||||
1,75.02474557,46.55401354 | |||||
1,76.0987867,87.42056972 | |||||
1,84.43281996,43.53339331 | |||||
0,95.86155507,38.22527806 | |||||
0,75.01365839,30.60326323 | |||||
1,82.30705337,76.4819633 | |||||
1,69.36458876,97.71869196 | |||||
0,39.53833914,76.03681085 | |||||
1,53.97105215,89.20735014 | |||||
1,69.07014406,52.74046973 | |||||
0,67.94685548,46.67857411 | |||||
1,70.66150955,92.92713789 | |||||
1,76.97878373,47.57596365 | |||||
0,67.37202755,42.83843832 | |||||
1,89.67677575,65.79936593 | |||||
0,50.53478829,48.85581153 | |||||
0,34.21206098,44.2095286 | |||||
1,77.92409145,68.97235999 | |||||
1,62.27101367,69.95445795 | |||||
1,80.19018075,44.82162893 | |||||
0,93.1143888,38.80067034 | |||||
0,61.83020602,50.25610789 | |||||
0,38.7858038,64.99568096 | |||||
1,61.37928945,72.80788731 | |||||
1,85.40451939,57.05198398 | |||||
0,52.10797973,63.12762377 | |||||
1,52.04540477,69.43286012 | |||||
0,40.23689374,71.16774802 | |||||
0,54.63510555,52.21388588 | |||||
0,33.91550011,98.86943574 | |||||
1,64.17698887,80.90806059 | |||||
0,74.78925296,41.57341523 | |||||
0,34.18364003,75.23772034 | |||||
1,83.90239366,56.30804622 | |||||
0,51.54772027,46.85629026 | |||||
1,94.44336777,65.56892161 | |||||
0,82.36875376,40.61825516 | |||||
0,51.04775177,45.82270146 | |||||
0,62.22267576,52.06099195 | |||||
1,77.19303493,70.4582 | |||||
1,97.77159928,86.72782233 | |||||
1,62.0730638,96.76882412 | |||||
1,91.5649745,88.69629255 | |||||
1,79.94481794,74.16311935 | |||||
1,99.27252693,60.999031 | |||||
1,90.54671411,43.39060181 | |||||
0,34.52451385,60.39634246 | |||||
0,50.28649612,49.80453881 | |||||
0,49.58667722,59.80895099 | |||||
1,97.64563396,68.86157272 | |||||
0,32.57720017,95.59854761 | |||||
1,74.24869137,69.82457123 | |||||
1,71.79646206,78.45356225 | |||||
1,75.39561147,85.75993667 | |||||
0,35.28611282,47.02051395 | |||||
0,56.2538175,39.26147251 | |||||
0,30.05882245,49.59297387 | |||||
0,44.66826172,66.45008615 | |||||
0,66.56089447,41.09209808 | |||||
1,40.45755098,97.53518549 | |||||
0,49.07256322,51.88321182 | |||||
1,80.27957401,92.11606081 | |||||
1,66.74671857,60.99139403 | |||||
0,32.72283304,43.30717306 | |||||
1,64.03932042,78.03168802 | |||||
1,72.34649423,96.22759297 | |||||
1,60.45788574,73.0949981 | |||||
1,58.84095622,75.85844831 | |||||
1,99.8278578,72.36925193 | |||||
1,47.26426911,88.475865 | |||||
1,50.4581598,75.80985953 | |||||
0,60.45555629,42.50840944 | |||||
0,82.22666158,42.71987854 | |||||
1,88.91389642,69.8037889 | |||||
1,94.83450672,45.6943068 | |||||
1,67.31925747,66.58935318 | |||||
1,57.23870632,59.51428198 | |||||
1,80.366756,90.9601479 | |||||
1,68.46852179,85.5943071 | |||||
0,42.07545454,78.844786 | |||||
1,75.47770201,90.424539 | |||||
1,78.63542435,96.64742717 | |||||
0,52.34800399,60.76950526 | |||||
1,94.09433113,77.15910509 | |||||
1,90.44855097,87.50879176 | |||||
0,55.48216114,35.57070347 | |||||
1,74.49269242,84.84513685 | |||||
1,89.84580671,45.35828361 | |||||
1,83.48916274,48.3802858 | |||||
1,42.26170081,87.10385094 | |||||
1,99.31500881,68.77540947 | |||||
1,55.34001756,64.93193801 | |||||
1,74.775893,89.5298129 |
@@ -1,100 +0,0 @@ | |||||
34.62365962451697,78.0246928153624,0 | |||||
30.28671076822607,43.89499752400101,0 | |||||
35.84740876993872,72.90219802708364,0 | |||||
60.18259938620976,86.30855209546826,1 | |||||
79.0327360507101,75.3443764369103,1 | |||||
45.08327747668339,56.3163717815305,0 | |||||
61.10666453684766,96.51142588489624,1 | |||||
75.02474556738889,46.55401354116538,1 | |||||
76.09878670226257,87.42056971926803,1 | |||||
84.43281996120035,43.53339331072109,1 | |||||
95.86155507093572,38.22527805795094,0 | |||||
75.01365838958247,30.60326323428011,0 | |||||
82.30705337399482,76.48196330235604,1 | |||||
69.36458875970939,97.71869196188608,1 | |||||
39.53833914367223,76.03681085115882,0 | |||||
53.9710521485623,89.20735013750205,1 | |||||
69.07014406283025,52.74046973016765,1 | |||||
67.94685547711617,46.67857410673128,0 | |||||
70.66150955499435,92.92713789364831,1 | |||||
76.97878372747498,47.57596364975532,1 | |||||
67.37202754570876,42.83843832029179,0 | |||||
89.67677575072079,65.79936592745237,1 | |||||
50.534788289883,48.85581152764205,0 | |||||
34.21206097786789,44.20952859866288,0 | |||||
77.9240914545704,68.9723599933059,1 | |||||
62.27101367004632,69.95445795447587,1 | |||||
80.1901807509566,44.82162893218353,1 | |||||
93.114388797442,38.80067033713209,0 | |||||
61.83020602312595,50.25610789244621,0 | |||||
38.78580379679423,64.99568095539578,0 | |||||
61.379289447425,72.80788731317097,1 | |||||
85.40451939411645,57.05198397627122,1 | |||||
52.10797973193984,63.12762376881715,0 | |||||
52.04540476831827,69.43286012045222,1 | |||||
40.23689373545111,71.16774802184875,0 | |||||
54.63510555424817,52.21388588061123,0 | |||||
33.91550010906887,98.86943574220611,0 | |||||
64.17698887494485,80.90806058670817,1 | |||||
74.78925295941542,41.57341522824434,0 | |||||
34.1836400264419,75.2377203360134,0 | |||||
83.90239366249155,56.30804621605327,1 | |||||
51.54772026906181,46.85629026349976,0 | |||||
94.44336776917852,65.56892160559052,1 | |||||
82.36875375713919,40.61825515970618,0 | |||||
51.04775177128865,45.82270145776001,0 | |||||
62.22267576120188,52.06099194836679,0 | |||||
77.19303492601364,70.45820000180959,1 | |||||
97.77159928000232,86.7278223300282,1 | |||||
62.07306379667647,96.76882412413983,1 | |||||
91.56497449807442,88.69629254546599,1 | |||||
79.94481794066932,74.16311935043758,1 | |||||
99.2725269292572,60.99903099844988,1 | |||||
90.54671411399852,43.39060180650027,1 | |||||
34.52451385320009,60.39634245837173,0 | |||||
50.2864961189907,49.80453881323059,0 | |||||
49.58667721632031,59.80895099453265,0 | |||||
97.64563396007767,68.86157272420604,1 | |||||
32.57720016809309,95.59854761387875,0 | |||||
74.24869136721598,69.82457122657193,1 | |||||
71.79646205863379,78.45356224515052,1 | |||||
75.3956114656803,85.75993667331619,1 | |||||
35.28611281526193,47.02051394723416,0 | |||||
56.25381749711624,39.26147251058019,0 | |||||
30.05882244669796,49.59297386723685,0 | |||||
44.66826172480893,66.45008614558913,0 | |||||
66.56089447242954,41.09209807936973,0 | |||||
40.45755098375164,97.53518548909936,1 | |||||
49.07256321908844,51.88321182073966,0 | |||||
80.27957401466998,92.11606081344084,1 | |||||
66.74671856944039,60.99139402740988,1 | |||||
32.72283304060323,43.30717306430063,0 | |||||
64.0393204150601,78.03168802018232,1 | |||||
72.34649422579923,96.22759296761404,1 | |||||
60.45788573918959,73.09499809758037,1 | |||||
58.84095621726802,75.85844831279042,1 | |||||
99.82785779692128,72.36925193383885,1 | |||||
47.26426910848174,88.47586499559782,1 | |||||
50.45815980285988,75.80985952982456,1 | |||||
60.45555629271532,42.50840943572217,0 | |||||
82.22666157785568,42.71987853716458,0 | |||||
88.9138964166533,69.80378889835472,1 | |||||
94.83450672430196,45.69430680250754,1 | |||||
67.31925746917527,66.58935317747915,1 | |||||
57.23870631569862,59.51428198012956,1 | |||||
80.36675600171273,90.96014789746954,1 | |||||
68.46852178591112,85.59430710452014,1 | |||||
42.0754545384731,78.84478600148043,0 | |||||
75.47770200533905,90.42453899753964,1 | |||||
78.63542434898018,96.64742716885644,1 | |||||
52.34800398794107,60.76950525602592,0 | |||||
94.09433112516793,77.15910509073893,1 | |||||
90.44855097096364,87.50879176484702,1 | |||||
55.48216114069585,35.57070347228866,0 | |||||
74.49269241843041,84.84513684930135,1 | |||||
89.84580670720979,45.35828361091658,1 | |||||
83.48916274498238,48.38028579728175,1 | |||||
42.2617008099817,87.10385094025457,1 | |||||
99.31500880510394,68.77540947206617,1 | |||||
55.34001756003703,64.9319380069486,1 | |||||
74.77589300092767,89.52981289513276,1 |
@@ -1,118 +0,0 @@ | |||||
0.051267,0.69956,1 | |||||
-0.092742,0.68494,1 | |||||
-0.21371,0.69225,1 | |||||
-0.375,0.50219,1 | |||||
-0.51325,0.46564,1 | |||||
-0.52477,0.2098,1 | |||||
-0.39804,0.034357,1 | |||||
-0.30588,-0.19225,1 | |||||
0.016705,-0.40424,1 | |||||
0.13191,-0.51389,1 | |||||
0.38537,-0.56506,1 | |||||
0.52938,-0.5212,1 | |||||
0.63882,-0.24342,1 | |||||
0.73675,-0.18494,1 | |||||
0.54666,0.48757,1 | |||||
0.322,0.5826,1 | |||||
0.16647,0.53874,1 | |||||
-0.046659,0.81652,1 | |||||
-0.17339,0.69956,1 | |||||
-0.47869,0.63377,1 | |||||
-0.60541,0.59722,1 | |||||
-0.62846,0.33406,1 | |||||
-0.59389,0.005117,1 | |||||
-0.42108,-0.27266,1 | |||||
-0.11578,-0.39693,1 | |||||
0.20104,-0.60161,1 | |||||
0.46601,-0.53582,1 | |||||
0.67339,-0.53582,1 | |||||
-0.13882,0.54605,1 | |||||
-0.29435,0.77997,1 | |||||
-0.26555,0.96272,1 | |||||
-0.16187,0.8019,1 | |||||
-0.17339,0.64839,1 | |||||
-0.28283,0.47295,1 | |||||
-0.36348,0.31213,1 | |||||
-0.30012,0.027047,1 | |||||
-0.23675,-0.21418,1 | |||||
-0.06394,-0.18494,1 | |||||
0.062788,-0.16301,1 | |||||
0.22984,-0.41155,1 | |||||
0.2932,-0.2288,1 | |||||
0.48329,-0.18494,1 | |||||
0.64459,-0.14108,1 | |||||
0.46025,0.012427,1 | |||||
0.6273,0.15863,1 | |||||
0.57546,0.26827,1 | |||||
0.72523,0.44371,1 | |||||
0.22408,0.52412,1 | |||||
0.44297,0.67032,1 | |||||
0.322,0.69225,1 | |||||
0.13767,0.57529,1 | |||||
-0.0063364,0.39985,1 | |||||
-0.092742,0.55336,1 | |||||
-0.20795,0.35599,1 | |||||
-0.20795,0.17325,1 | |||||
-0.43836,0.21711,1 | |||||
-0.21947,-0.016813,1 | |||||
-0.13882,-0.27266,1 | |||||
0.18376,0.93348,0 | |||||
0.22408,0.77997,0 | |||||
0.29896,0.61915,0 | |||||
0.50634,0.75804,0 | |||||
0.61578,0.7288,0 | |||||
0.60426,0.59722,0 | |||||
0.76555,0.50219,0 | |||||
0.92684,0.3633,0 | |||||
0.82316,0.27558,0 | |||||
0.96141,0.085526,0 | |||||
0.93836,0.012427,0 | |||||
0.86348,-0.082602,0 | |||||
0.89804,-0.20687,0 | |||||
0.85196,-0.36769,0 | |||||
0.82892,-0.5212,0 | |||||
0.79435,-0.55775,0 | |||||
0.59274,-0.7405,0 | |||||
0.51786,-0.5943,0 | |||||
0.46601,-0.41886,0 | |||||
0.35081,-0.57968,0 | |||||
0.28744,-0.76974,0 | |||||
0.085829,-0.75512,0 | |||||
0.14919,-0.57968,0 | |||||
-0.13306,-0.4481,0 | |||||
-0.40956,-0.41155,0 | |||||
-0.39228,-0.25804,0 | |||||
-0.74366,-0.25804,0 | |||||
-0.69758,0.041667,0 | |||||
-0.75518,0.2902,0 | |||||
-0.69758,0.68494,0 | |||||
-0.4038,0.70687,0 | |||||
-0.38076,0.91886,0 | |||||
-0.50749,0.90424,0 | |||||
-0.54781,0.70687,0 | |||||
0.10311,0.77997,0 | |||||
0.057028,0.91886,0 | |||||
-0.10426,0.99196,0 | |||||
-0.081221,1.1089,0 | |||||
0.28744,1.087,0 | |||||
0.39689,0.82383,0 | |||||
0.63882,0.88962,0 | |||||
0.82316,0.66301,0 | |||||
0.67339,0.64108,0 | |||||
1.0709,0.10015,0 | |||||
-0.046659,-0.57968,0 | |||||
-0.23675,-0.63816,0 | |||||
-0.15035,-0.36769,0 | |||||
-0.49021,-0.3019,0 | |||||
-0.46717,-0.13377,0 | |||||
-0.28859,-0.060673,0 | |||||
-0.61118,-0.067982,0 | |||||
-0.66302,-0.21418,0 | |||||
-0.59965,-0.41886,0 | |||||
-0.72638,-0.082602,0 | |||||
-0.83007,0.31213,0 | |||||
-0.72062,0.53874,0 | |||||
-0.59389,0.49488,0 | |||||
-0.48445,0.99927,0 | |||||
-0.0063364,0.99927,0 | |||||
0.63265,-0.030612,0 |
@@ -1,118 +0,0 @@ | |||||
0.051267,0.69956,1 | |||||
-0.092742,0.68494,1 | |||||
-0.21371,0.69225,1 | |||||
-0.375,0.50219,1 | |||||
-0.51325,0.46564,1 | |||||
-0.52477,0.2098,1 | |||||
-0.39804,0.034357,1 | |||||
-0.30588,-0.19225,1 | |||||
0.016705,-0.40424,1 | |||||
0.13191,-0.51389,1 | |||||
0.38537,-0.56506,1 | |||||
0.52938,-0.5212,1 | |||||
0.63882,-0.24342,1 | |||||
0.73675,-0.18494,1 | |||||
0.54666,0.48757,1 | |||||
0.322,0.5826,1 | |||||
0.16647,0.53874,1 | |||||
-0.046659,0.81652,1 | |||||
-0.17339,0.69956,1 | |||||
-0.47869,0.63377,1 | |||||
-0.60541,0.59722,1 | |||||
-0.62846,0.33406,1 | |||||
-0.59389,0.005117,1 | |||||
-0.42108,-0.27266,1 | |||||
-0.11578,-0.39693,1 | |||||
0.20104,-0.60161,1 | |||||
0.46601,-0.53582,1 | |||||
0.67339,-0.53582,1 | |||||
-0.13882,0.54605,1 | |||||
-0.29435,0.77997,1 | |||||
-0.26555,0.96272,1 | |||||
-0.16187,0.8019,1 | |||||
-0.17339,0.64839,1 | |||||
-0.28283,0.47295,1 | |||||
-0.36348,0.31213,1 | |||||
-0.30012,0.027047,1 | |||||
-0.23675,-0.21418,1 | |||||
-0.06394,-0.18494,1 | |||||
0.062788,-0.16301,1 | |||||
0.22984,-0.41155,1 | |||||
0.2932,-0.2288,1 | |||||
0.48329,-0.18494,1 | |||||
0.64459,-0.14108,1 | |||||
0.46025,0.012427,1 | |||||
0.6273,0.15863,1 | |||||
0.57546,0.26827,1 | |||||
0.72523,0.44371,1 | |||||
0.22408,0.52412,1 | |||||
0.44297,0.67032,1 | |||||
0.322,0.69225,1 | |||||
0.13767,0.57529,1 | |||||
-0.0063364,0.39985,1 | |||||
-0.092742,0.55336,1 | |||||
-0.20795,0.35599,1 | |||||
-0.20795,0.17325,1 | |||||
-0.43836,0.21711,1 | |||||
-0.21947,-0.016813,1 | |||||
-0.13882,-0.27266,1 | |||||
0.18376,0.93348,0 | |||||
0.22408,0.77997,0 | |||||
0.29896,0.61915,0 | |||||
0.50634,0.75804,0 | |||||
0.61578,0.7288,0 | |||||
0.60426,0.59722,0 | |||||
0.76555,0.50219,0 | |||||
0.92684,0.3633,0 | |||||
0.82316,0.27558,0 | |||||
0.96141,0.085526,0 | |||||
0.93836,0.012427,0 | |||||
0.86348,-0.082602,0 | |||||
0.89804,-0.20687,0 | |||||
0.85196,-0.36769,0 | |||||
0.82892,-0.5212,0 | |||||
0.79435,-0.55775,0 | |||||
0.59274,-0.7405,0 | |||||
0.51786,-0.5943,0 | |||||
0.46601,-0.41886,0 | |||||
0.35081,-0.57968,0 | |||||
0.28744,-0.76974,0 | |||||
0.085829,-0.75512,0 | |||||
0.14919,-0.57968,0 | |||||
-0.13306,-0.4481,0 | |||||
-0.40956,-0.41155,0 | |||||
-0.39228,-0.25804,0 | |||||
-0.74366,-0.25804,0 | |||||
-0.69758,0.041667,0 | |||||
-0.75518,0.2902,0 | |||||
-0.69758,0.68494,0 | |||||
-0.4038,0.70687,0 | |||||
-0.38076,0.91886,0 | |||||
-0.50749,0.90424,0 | |||||
-0.54781,0.70687,0 | |||||
0.10311,0.77997,0 | |||||
0.057028,0.91886,0 | |||||
-0.10426,0.99196,0 | |||||
-0.081221,1.1089,0 | |||||
0.28744,1.087,0 | |||||
0.39689,0.82383,0 | |||||
0.63882,0.88962,0 | |||||
0.82316,0.66301,0 | |||||
0.67339,0.64108,0 | |||||
1.0709,0.10015,0 | |||||
-0.046659,-0.57968,0 | |||||
-0.23675,-0.63816,0 | |||||
-0.15035,-0.36769,0 | |||||
-0.49021,-0.3019,0 | |||||
-0.46717,-0.13377,0 | |||||
-0.28859,-0.060673,0 | |||||
-0.61118,-0.067982,0 | |||||
-0.66302,-0.21418,0 | |||||
-0.59965,-0.41886,0 | |||||
-0.72638,-0.082602,0 | |||||
-0.83007,0.31213,0 | |||||
-0.72062,0.53874,0 | |||||
-0.59389,0.49488,0 | |||||
-0.48445,0.99927,0 | |||||
-0.0063364,0.99927,0 | |||||
0.63265,-0.030612,0 |
@@ -1,5 +0,0 @@ | |||||
0,98.83450677,10.6943068 | |||||
1,65.31925747,65.58935318 | |||||
0,70.23870632,48.51428198 | |||||
1,80.366756,70.9601479 | |||||
0,60.46852179,60.5943071 |
@@ -1,5 +0,0 @@ | |||||
98.83450676630196,10.69430680250754,0 | |||||
65.31925746917527,65.58935317747915,1 | |||||
70.23870631569862,48.51428198012956,0 | |||||
80.36675600171273,70.96014789746954,1 | |||||
60.46852178591112,60.59430710452014,0 |
@@ -1,41 +0,0 @@ | |||||
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 |
@@ -1,74 +0,0 @@ | |||||
============================================================================ | |||||
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 |
@@ -1,25 +0,0 @@ | |||||
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. |
@@ -1,394 +0,0 @@ | |||||
=============================================================================== | |||||
= 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). |
@@ -1,32 +0,0 @@ | |||||
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 | |||||
@@ -1,566 +0,0 @@ | |||||
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 | |||||
@@ -1,528 +0,0 @@ | |||||
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 | |||||
@@ -1,33 +0,0 @@ | |||||
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 | |||||
@@ -1,475 +0,0 @@ | |||||
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 |
@@ -1,504 +0,0 @@ | |||||
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(:)'; |
@@ -1,40 +0,0 @@ | |||||
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 | |||||
@@ -1,30 +0,0 @@ | |||||
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 |
@@ -1,125 +0,0 @@ | |||||
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( ... | |||||
'!! Submission failed: unexpected error: %s\n', ... | |||||
e.message); | |||||
fprintf('!! Please try again later.\n'); | |||||
return | |||||
end | |||||
if isfield(response, 'errorMessage') | |||||
fprintf('!! Submission failed: %s\n', response.errorMessage); | |||||
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(); | |||||
params = {'jsonBody', body}; | |||||
[code, responseBody] = system(sprintf('echo jsonBody=%s | curl -k -X POST -d @- %s', body, submissionUrl)); | |||||
response = loadjson(responseBody); | |||||
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 | |||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||||
% | |||||
% Service configuration | |||||
% | |||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||||
function submissionUrl = submissionUrl() | |||||
submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1'; | |||||
end |
@@ -1,21 +0,0 @@ | |||||
function out = mapFeature(X1, X2) | |||||
% MAPFEATURE Feature mapping function to polynomial features | |||||
% | |||||
% MAPFEATURE(X1, X2) maps the two input features | |||||
% to quadratic features used in the regularization exercise. | |||||
% | |||||
% Returns a new feature array with more features, comprising of | |||||
% X1, X2, X1.^2, X2.^2, X1*X2, X1*X2.^2, etc.. | |||||
% | |||||
% Inputs X1, X2 must be the same size | |||||
% | |||||
degree = 6; | |||||
out = ones(size(X1(:,1))); | |||||
for i = 1:degree | |||||
for j = 0:i | |||||
out(:, end+1) = (X1.^(i-j)).*(X2.^j); | |||||
end | |||||
end | |||||
end |
@@ -1,30 +0,0 @@ | |||||
function plotData(X, y) | |||||
%PLOTDATA Plots the data points X and y into a new figure | |||||
% PLOTDATA(x,y) plots the data points with + for the positive examples | |||||
% and o for the negative examples. X is assumed to be a Mx2 matrix. | |||||
% Create New Figure | |||||
figure; hold on; | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Plot the positive and negative examples on a | |||||
% 2D plot, using the option 'k+' for the positive | |||||
% examples and 'ko' for the negative examples. | |||||
% | |||||
pos = find(y == 1); | |||||
neg = find(y == 0); | |||||
plot(X(pos, 1), X(pos, 2), 'k+' ,'LineWidth', 2, 'MarkerSize', 7); | |||||
plot(X(neg, 1), X(neg, 2), 'ko', 'MarkerFaceColor', 'y', 'MarkerSize', 7); | |||||
% ========================================================================= | |||||
hold off; | |||||
end |
@@ -1,48 +0,0 @@ | |||||
function plotDecisionBoundary(theta, X, y) | |||||
%PLOTDECISIONBOUNDARY Plots the data points X and y into a new figure with | |||||
%the decision boundary defined by theta | |||||
% PLOTDECISIONBOUNDARY(theta, X,y) plots the data points with + for the | |||||
% positive examples and o for the negative examples. X is assumed to be | |||||
% a either | |||||
% 1) Mx3 matrix, where the first column is an all-ones column for the | |||||
% intercept. | |||||
% 2) MxN, N>3 matrix, where the first column is all-ones | |||||
% Plot Data | |||||
plotData(X(:,2:3), y); | |||||
hold on | |||||
if size(X, 2) <= 3 | |||||
% Only need 2 points to define a line, so choose two endpoints | |||||
plot_x = [min(X(:,2))-2, max(X(:,2))+2]; | |||||
% Calculate the decision boundary line | |||||
plot_y = (-1./theta(3)).*(theta(2).*plot_x + theta(1)); | |||||
% Plot, and adjust axes for better viewing | |||||
plot(plot_x, plot_y) | |||||
% Legend, specific for the exercise | |||||
legend('Admitted', 'Not admitted', 'Decision Boundary') | |||||
axis([30, 100, 30, 100]) | |||||
else | |||||
% Here is the grid range | |||||
u = linspace(-1, 1.5, 50); | |||||
v = linspace(-1, 1.5, 50); | |||||
z = zeros(length(u), length(v)); | |||||
% Evaluate z = theta*x over the grid | |||||
for i = 1:length(u) | |||||
for j = 1:length(v) | |||||
z(i,j) = mapFeature(u(i), v(j))*theta; | |||||
end | |||||
end | |||||
z = z'; % important to transpose z before calling contour | |||||
% Plot z = 0 | |||||
% Notice you need to specify the range [0, 0] | |||||
contour(u, v, z, [0, 0], 'LineWidth', 2) | |||||
end | |||||
hold off | |||||
end |
@@ -1,27 +0,0 @@ | |||||
function p = predict(theta, X) | |||||
%PREDICT Predict whether the label is 0 or 1 using learned logistic | |||||
%regression parameters theta | |||||
% p = PREDICT(theta, X) computes the predictions for X using a | |||||
% threshold at 0.5 (i.e., if sigmoid(theta'*x) >= 0.5, predict 1) | |||||
m = size(X, 1); % Number of training examples | |||||
% You need to return the following variables correctly | |||||
p = zeros(m, 1); | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Complete the following code to make predictions using | |||||
% your learned logistic regression parameters. | |||||
% You should set p to a vector of 0's and 1's | |||||
% | |||||
prob = sigmoid(X * theta); | |||||
pos = find(prob >= 0.5); | |||||
p(pos,1) = 1; | |||||
% ========================================================================= | |||||
end |
@@ -1,19 +0,0 @@ | |||||
function g = sigmoid(z) | |||||
%SIGMOID Compute sigmoid functoon | |||||
% J = SIGMOID(z) computes the sigmoid of z. | |||||
% You need to return the following variables correctly | |||||
g = zeros(size(z)); | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Compute the sigmoid of each value of z (z can be a matrix, | |||||
% vector or scalar). | |||||
%g = 1 ./ (1 .+ e .^ -z); | |||||
g = 1.0 ./ (1.0 + exp(-z));%exp(n)-->e的n次方 | |||||
% ============================================================= | |||||
end |
@@ -1,62 +0,0 @@ | |||||
function submit() | |||||
addpath('./lib'); | |||||
conf.assignmentSlug = 'logistic-regression'; | |||||
conf.itemName = 'Logistic Regression'; | |||||
conf.partArrays = { ... | |||||
{ ... | |||||
'1', ... | |||||
{ 'sigmoid.m' }, ... | |||||
'Sigmoid Function', ... | |||||
}, ... | |||||
{ ... | |||||
'2', ... | |||||
{ 'costFunction.m' }, ... | |||||
'Logistic Regression Cost', ... | |||||
}, ... | |||||
{ ... | |||||
'3', ... | |||||
{ 'costFunction.m' }, ... | |||||
'Logistic Regression Gradient', ... | |||||
}, ... | |||||
{ ... | |||||
'4', ... | |||||
{ 'predict.m' }, ... | |||||
'Predict', ... | |||||
}, ... | |||||
{ ... | |||||
'5', ... | |||||
{ 'costFunctionReg.m' }, ... | |||||
'Regularized Logistic Regression Cost', ... | |||||
}, ... | |||||
{ ... | |||||
'6', ... | |||||
{ 'costFunctionReg.m' }, ... | |||||
'Regularized Logistic Regression Gradient', ... | |||||
}, ... | |||||
}; | |||||
conf.output = @output; | |||||
submitWithConfiguration(conf); | |||||
end | |||||
function out = output(partId, auxstring) | |||||
% Random Test Cases | |||||
X = [ones(20,1) (exp(1) * sin(1:1:20))' (exp(0.5) * cos(1:1:20))']; | |||||
y = sin(X(:,1) + X(:,2)) > 0; | |||||
if partId == '1' | |||||
out = sprintf('%0.5f ', sigmoid(X)); | |||||
elseif partId == '2' | |||||
out = sprintf('%0.5f ', costFunction([0.25 0.5 -0.5]', X, y)); | |||||
elseif partId == '3' | |||||
[cost, grad] = costFunction([0.25 0.5 -0.5]', X, y); | |||||
out = sprintf('%0.5f ', grad); | |||||
elseif partId == '4' | |||||
out = sprintf('%0.5f ', predict([0.25 0.5 -0.5]', X)); | |||||
elseif partId == '5' | |||||
out = sprintf('%0.5f ', costFunctionReg([0.25 0.5 -0.5]', X, y, 0.1)); | |||||
elseif partId == '6' | |||||
[cost, grad] = costFunctionReg([0.25 0.5 -0.5]', X, y, 0.1); | |||||
out = sprintf('%0.5f ', grad); | |||||
end | |||||
end |
@@ -1,15 +0,0 @@ | |||||
# Created by Octave 4.2.0, Sat Nov 19 20:17:18 2016 GMT <unknown@unknown> | |||||
# name: email | |||||
# type: sq_string | |||||
# elements: 1 | |||||
# length: 17 | |||||
scruel@vip.qq.com | |||||
# name: token | |||||
# type: sq_string | |||||
# elements: 1 | |||||
# length: 16 | |||||
A3Wc4pI1qYjCUaRB | |||||
@@ -1,59 +0,0 @@ | |||||
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 |
@@ -1,69 +0,0 @@ | |||||
%% Machine Learning Online Class - Exercise 3 | Part 1: One-vs-all | |||||
% Instructions | |||||
% ------------ | |||||
% | |||||
% This file contains code that helps you get started on the | |||||
% linear exercise. You will need to complete the following functions | |||||
% in this exericse: | |||||
% | |||||
% lrCostFunction.m (logistic regression cost function) | |||||
% oneVsAll.m | |||||
% predictOneVsAll.m | |||||
% predict.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 | |||||
%% Setup the parameters you will use for this part of the exercise | |||||
input_layer_size = 400; % 20x20 Input Images of Digits | |||||
num_labels = 10; % 10 labels, from 1 to 10 ~k | |||||
% (note that we have mapped "0" to label 10) | |||||
%% =========== Part 1: Loading and Visualizing Data ============= | |||||
% We start the exercise by first loading and visualizing the dataset. | |||||
% You will be working with a dataset that contains handwritten digits. | |||||
% | |||||
% Load Training Data | |||||
fprintf('Loading and Visualizing Data ...\n') | |||||
load('ex3data1.mat'); % training data stored in arrays X, y | |||||
m = size(X, 1); | |||||
% Randomly select 100 data points to display | |||||
%rand_indices = randperm(m); | |||||
%sel = X(rand_indices(1:100), :); | |||||
%displayData(sel); | |||||
%fprintf('Program paused. Press enter to continue.\n'); | |||||
%pause; | |||||
%% ============ Part 2: Vectorize Logistic Regression ============ | |||||
% In this part of the exercise, you will reuse your logistic regression | |||||
% code from the last exercise. You task here is to make sure that your | |||||
% regularized logistic regression implementation is vectorized. After | |||||
% that, you will implement one-vs-all classification for the handwritten | |||||
% digit dataset. | |||||
% | |||||
fprintf('\nTraining One-vs-All Logistic Regression...\n') | |||||
lambda = 0.1; | |||||
[all_theta] = oneVsAll(X, y, num_labels, lambda); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ================ Part 3: Predict for One-Vs-All ================ | |||||
% After ... | |||||
pred = predictOneVsAll(all_theta, X); | |||||
fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100); | |||||
@@ -1,88 +0,0 @@ | |||||
%% Machine Learning Online Class - Exercise 3 | Part 2: Neural Networks | |||||
% Instructions | |||||
% ------------ | |||||
% | |||||
% This file contains code that helps you get started on the | |||||
% linear exercise. You will need to complete the following functions | |||||
% in this exericse: | |||||
% | |||||
% lrCostFunction.m (logistic regression cost function) | |||||
% oneVsAll.m | |||||
% predictOneVsAll.m | |||||
% predict.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 | |||||
%% Setup the parameters you will use for this exercise | |||||
input_layer_size = 400; % 20x20 Input Images of Digits | |||||
hidden_layer_size = 25; % 25 hidden units | |||||
num_labels = 10; % 10 labels, from 1 to 10 | |||||
% (note that we have mapped "0" to label 10) | |||||
%% =========== Part 1: Loading and Visualizing Data ============= | |||||
% We start the exercise by first loading and visualizing the dataset. | |||||
% You will be working with a dataset that contains handwritten digits. | |||||
% | |||||
% Load Training Data | |||||
fprintf('Loading and Visualizing Data ...\n') | |||||
load('ex3data1.mat'); | |||||
m = size(X, 1); | |||||
% Randomly select 100 data points to display | |||||
sel = randperm(size(X, 1)); | |||||
sel = sel(1:100); | |||||
displayData(X(sel, :)); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ================ Part 2: Loading Pameters ================ | |||||
% In this part of the exercise, we load some pre-initialized | |||||
% neural network parameters. | |||||
fprintf('\nLoading Saved Neural Network Parameters ...\n') | |||||
% Load the weights into variables Theta1 and Theta2 | |||||
load('ex3weights.mat'); | |||||
%% ================= Part 3: Implement Predict ================= | |||||
% After training the neural network, we would like to use it to predict | |||||
% the labels. You will now implement the "predict" function to use the | |||||
% neural network to predict the labels of the training set. This lets | |||||
% you compute the training set accuracy. | |||||
%Theta1,Theta2 = fmincg(@CostFunction, initial_theta, option) | |||||
pred = predict(Theta1, Theta2, X); | |||||
fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
% To give you an idea of the network's output, you can also run | |||||
% through the examples one at the a time to see what it is predicting. | |||||
% Randomly permute examples | |||||
rp = randperm(m); | |||||
for i = 1:m | |||||
% Display | |||||
fprintf('\nDisplaying Example Image\n'); | |||||
displayData(X(rp(i), :)); | |||||
pred = predict(Theta1, Theta2, X(rp(i),:)); | |||||
fprintf('\nNeural Network Prediction: %d (digit %d)\n', pred, mod(pred, 10)); | |||||
% Pause | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
end | |||||
@@ -1,175 +0,0 @@ | |||||
function [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5) | |||||
% Minimize a continuous differentialble multivariate function. Starting point | |||||
% is given by "X" (D by 1), and the function named in the string "f", must | |||||
% return a function value and a vector of partial derivatives. The Polack- | |||||
% Ribiere flavour of conjugate gradients is used to compute search directions, | |||||
% and a line search using quadratic and cubic polynomial approximations and the | |||||
% Wolfe-Powell stopping criteria is used together with the slope ratio method | |||||
% for guessing initial step sizes. Additionally a bunch of checks are made to | |||||
% make sure that exploration is taking place and that extrapolation will not | |||||
% be unboundedly large. The "length" gives the length of the run: if it is | |||||
% positive, it gives the maximum number of line searches, if negative its | |||||
% absolute gives the maximum allowed number of function evaluations. You can | |||||
% (optionally) give "length" a second component, which will indicate the | |||||
% reduction in function value to be expected in the first line-search (defaults | |||||
% to 1.0). The function returns when either its length is up, or if no further | |||||
% progress can be made (ie, we are at a minimum, or so close that due to | |||||
% numerical problems, we cannot get any closer). If the function terminates | |||||
% within a few iterations, it could be an indication that the function value | |||||
% and derivatives are not consistent (ie, there may be a bug in the | |||||
% implementation of your "f" function). The function returns the found | |||||
% solution "X", a vector of function values "fX" indicating the progress made | |||||
% and "i" the number of iterations (line searches or function evaluations, | |||||
% depending on the sign of "length") used. | |||||
% | |||||
% Usage: [X, fX, i] = fmincg(f, X, options, P1, P2, P3, P4, P5) | |||||
% | |||||
% See also: checkgrad | |||||
% | |||||
% Copyright (C) 2001 and 2002 by Carl Edward Rasmussen. Date 2002-02-13 | |||||
% | |||||
% | |||||
% (C) Copyright 1999, 2000 & 2001, Carl Edward Rasmussen | |||||
% | |||||
% Permission is granted for anyone to copy, use, or modify these | |||||
% programs and accompanying documents for purposes of research or | |||||
% education, provided this copyright notice is retained, and note is | |||||
% made of any changes that have been made. | |||||
% | |||||
% These programs and documents are distributed without any warranty, | |||||
% express or implied. As the programs were written for research | |||||
% purposes only, they have not been tested to the degree that would be | |||||
% advisable in any important application. All use of these programs is | |||||
% entirely at the user's own risk. | |||||
% | |||||
% [ml-class] Changes Made: | |||||
% 1) Function name and argument specifications | |||||
% 2) Output display | |||||
% | |||||
% Read options | |||||
if exist('options', 'var') && ~isempty(options) && isfield(options, 'MaxIter') | |||||
length = options.MaxIter; | |||||
else | |||||
length = 100; | |||||
end | |||||
RHO = 0.01; % a bunch of constants for line searches | |||||
SIG = 0.5; % RHO and SIG are the constants in the Wolfe-Powell conditions | |||||
INT = 0.1; % don't reevaluate within 0.1 of the limit of the current bracket | |||||
EXT = 3.0; % extrapolate maximum 3 times the current bracket | |||||
MAX = 20; % max 20 function evaluations per line search | |||||
RATIO = 100; % maximum allowed slope ratio | |||||
argstr = ['feval(f, X']; % compose string used to call function | |||||
for i = 1:(nargin - 3) | |||||
argstr = [argstr, ',P', int2str(i)]; | |||||
end | |||||
argstr = [argstr, ')']; | |||||
if max(size(length)) == 2, red=length(2); length=length(1); else red=1; end | |||||
S=['Iteration ']; | |||||
i = 0; % zero the run length counter | |||||
ls_failed = 0; % no previous line search has failed | |||||
fX = []; | |||||
[f1 df1] = eval(argstr); % get function value and gradient | |||||
i = i + (length<0); % count epochs?! | |||||
s = -df1; % search direction is steepest | |||||
d1 = -s'*s; % this is the slope | |||||
z1 = red/(1-d1); % initial step is red/(|s|+1) | |||||
while i < abs(length) % while not finished | |||||
i = i + (length>0); % count iterations?! | |||||
X0 = X; f0 = f1; df0 = df1; % make a copy of current values | |||||
X = X + z1*s; % begin line search | |||||
[f2 df2] = eval(argstr); | |||||
i = i + (length<0); % count epochs?! | |||||
d2 = df2'*s; | |||||
f3 = f1; d3 = d1; z3 = -z1; % initialize point 3 equal to point 1 | |||||
if length>0, M = MAX; else M = min(MAX, -length-i); end | |||||
success = 0; limit = -1; % initialize quanteties | |||||
while 1 | |||||
while ((f2 > f1+z1*RHO*d1) || (d2 > -SIG*d1)) && (M > 0) | |||||
limit = z1; % tighten the bracket | |||||
if f2 > f1 | |||||
z2 = z3 - (0.5*d3*z3*z3)/(d3*z3+f2-f3); % quadratic fit | |||||
else | |||||
A = 6*(f2-f3)/z3+3*(d2+d3); % cubic fit | |||||
B = 3*(f3-f2)-z3*(d3+2*d2); | |||||
z2 = (sqrt(B*B-A*d2*z3*z3)-B)/A; % numerical error possible - ok! | |||||
end | |||||
if isnan(z2) || isinf(z2) | |||||
z2 = z3/2; % if we had a numerical problem then bisect | |||||
end | |||||
z2 = max(min(z2, INT*z3),(1-INT)*z3); % don't accept too close to limits | |||||
z1 = z1 + z2; % update the step | |||||
X = X + z2*s; | |||||
[f2 df2] = eval(argstr); | |||||
M = M - 1; i = i + (length<0); % count epochs?! | |||||
d2 = df2'*s; | |||||
z3 = z3-z2; % z3 is now relative to the location of z2 | |||||
end | |||||
if f2 > f1+z1*RHO*d1 || d2 > -SIG*d1 | |||||
break; % this is a failure | |||||
elseif d2 > SIG*d1 | |||||
success = 1; break; % success | |||||
elseif M == 0 | |||||
break; % failure | |||||
end | |||||
A = 6*(f2-f3)/z3+3*(d2+d3); % make cubic extrapolation | |||||
B = 3*(f3-f2)-z3*(d3+2*d2); | |||||
z2 = -d2*z3*z3/(B+sqrt(B*B-A*d2*z3*z3)); % num. error possible - ok! | |||||
if ~isreal(z2) || isnan(z2) || isinf(z2) || z2 < 0 % num prob or wrong sign? | |||||
if limit < -0.5 % if we have no upper limit | |||||
z2 = z1 * (EXT-1); % the extrapolate the maximum amount | |||||
else | |||||
z2 = (limit-z1)/2; % otherwise bisect | |||||
end | |||||
elseif (limit > -0.5) && (z2+z1 > limit) % extraplation beyond max? | |||||
z2 = (limit-z1)/2; % bisect | |||||
elseif (limit < -0.5) && (z2+z1 > z1*EXT) % extrapolation beyond limit | |||||
z2 = z1*(EXT-1.0); % set to extrapolation limit | |||||
elseif z2 < -z3*INT | |||||
z2 = -z3*INT; | |||||
elseif (limit > -0.5) && (z2 < (limit-z1)*(1.0-INT)) % too close to limit? | |||||
z2 = (limit-z1)*(1.0-INT); | |||||
end | |||||
f3 = f2; d3 = d2; z3 = -z2; % set point 3 equal to point 2 | |||||
z1 = z1 + z2; X = X + z2*s; % update current estimates | |||||
[f2 df2] = eval(argstr); | |||||
M = M - 1; i = i + (length<0); % count epochs?! | |||||
d2 = df2'*s; | |||||
end % end of line search | |||||
if success % if line search succeeded | |||||
f1 = f2; fX = [fX' f1]'; | |||||
fprintf('%s %4i | Cost: %4.6e\r', S, i, f1); | |||||
s = (df2'*df2-df1'*df2)/(df1'*df1)*s - df2; % Polack-Ribiere direction | |||||
tmp = df1; df1 = df2; df2 = tmp; % swap derivatives | |||||
d2 = df1'*s; | |||||
if d2 > 0 % new slope must be negative | |||||
s = -df1; % otherwise use steepest direction | |||||
d2 = -s'*s; | |||||
end | |||||
z1 = z1 * min(RATIO, d1/(d2-realmin)); % slope ratio but max RATIO | |||||
d1 = d2; | |||||
ls_failed = 0; % this line search did not fail | |||||
else | |||||
X = X0; f1 = f0; df1 = df0; % restore point from before failed line search | |||||
if ls_failed || i > abs(length) % line search failed twice in a row | |||||
break; % or we ran out of time, so we give up | |||||
end | |||||
tmp = df1; df1 = df2; df2 = tmp; % swap derivatives | |||||
s = -df1; % try steepest | |||||
d1 = -s'*s; | |||||
z1 = 1/(1-d1); | |||||
ls_failed = 1; % this line search failed | |||||
end | |||||
if exist('OCTAVE_VERSION') | |||||
fflush(stdout); | |||||
end | |||||
end | |||||
fprintf('\n'); |
@@ -1,41 +0,0 @@ | |||||
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 |
@@ -1,74 +0,0 @@ | |||||
============================================================================ | |||||
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 |
@@ -1,25 +0,0 @@ | |||||
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. |
@@ -1,394 +0,0 @@ | |||||
=============================================================================== | |||||
= 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). |
@@ -1,32 +0,0 @@ | |||||
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 | |||||
@@ -1,566 +0,0 @@ | |||||
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 | |||||
@@ -1,528 +0,0 @@ | |||||
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 | |||||
@@ -1,33 +0,0 @@ | |||||
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 | |||||
@@ -1,475 +0,0 @@ | |||||
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 |
@@ -1,504 +0,0 @@ | |||||
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(:)'; |
@@ -1,40 +0,0 @@ | |||||
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 | |||||
@@ -1,30 +0,0 @@ | |||||
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 |
@@ -1,125 +0,0 @@ | |||||
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( ... | |||||
'!! Submission failed: unexpected error: %s\n', ... | |||||
e.message); | |||||
fprintf('!! Please try again later.\n'); | |||||
return | |||||
end | |||||
if isfield(response, 'errorMessage') | |||||
fprintf('!! Submission failed: %s\n', response.errorMessage); | |||||
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(); | |||||
params = {'jsonBody', body}; | |||||
[code, responseBody] = system(sprintf('echo jsonBody=%s | curl -k -X POST -d @- %s', body, submissionUrl)); | |||||
response = loadjson(responseBody); | |||||
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 | |||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||||
% | |||||
% Service configuration | |||||
% | |||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |||||
function submissionUrl = submissionUrl() | |||||
submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1'; | |||||
end |
@@ -1,58 +0,0 @@ | |||||
function [J, grad] = lrCostFunction(theta, X, y, lambda) | |||||
%LRCOSTFUNCTION Compute cost and gradient for logistic regression with | |||||
%regularization | |||||
% J = LRCOSTFUNCTION(theta, X, y, lambda) computes the cost of using | |||||
% theta as the parameter for regularized logistic regression and the | |||||
% gradient of the cost w.r.t. to the parameters. | |||||
% Initialize some useful values | |||||
m = length(y); % number of training examples | |||||
% You need to return the following variables correctly | |||||
J = 0; | |||||
grad = zeros(size(theta)); | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Compute the cost of a particular choice of theta. | |||||
% You should set J to the cost. | |||||
% Compute the partial derivatives and set grad to the partial | |||||
% derivatives of the cost w.r.t. each parameter in theta | |||||
% | |||||
hx = sigmoid(X * theta); %hypothesis, m * 1 | |||||
% Hint: The computation of the cost function and gradients can be | |||||
% efficiently vectorized. For example, consider the computation | |||||
% | |||||
% sigmoid(X * theta) | |||||
% | |||||
% Each row of the resulting matrix will contain the value of the | |||||
% prediction for that example. You can make use of this to vectorize | |||||
% the cost function and gradient computations. | |||||
% | |||||
J = 1 / m * sum(-y' * log(hx) - (1 - y)' * log(1 - hx)) + lambda / (2 * m) * theta(2:end)' * theta(2:end); | |||||
% Hint: When computing the gradient of the regularized cost function, | |||||
% there're many possible vectorized solutions, but one solution | |||||
% looks like: | |||||
% grad = (unregularized gradient for logistic regression) | |||||
% temp = theta; | |||||
% temp(1) = 0; % because we don't add anything for j = 0 | |||||
% grad = grad + YOUR_CODE_HERE (using the temp variable) | |||||
% | |||||
gradf = (1 / m) * (X(:, 1)' * (hx - y)); | |||||
gradb = (1 / m) * (X(:, 2:end)' * (hx - y)) + lambda * theta(2:end) / m; | |||||
grad = [gradf;gradb]; | |||||
size(grad) | |||||
% ============================================================= | |||||
grad = grad(:); | |||||
end |
@@ -1,74 +0,0 @@ | |||||
function [all_theta] = oneVsAll(X, y, num_labels, lambda) | |||||
%ONEVSALL trains multiple logistic regression classifiers and returns all | |||||
%the classifiers in a matrix all_theta, where the i-th row of all_theta | |||||
%corresponds to the classifier for label i | |||||
% [all_theta] = ONEVSALL(X, y, num_labels, lambda) trains num_labels | |||||
% logisitc regression classifiers and returns each of these classifiers | |||||
% in a matrix all_theta, where the i-th row of all_theta corresponds | |||||
% to the classifier for label i | |||||
% num_labels --> k | |||||
% Some useful variables | |||||
m = size(X, 1); | |||||
n = size(X, 2); | |||||
% You need to return the following variables correctly | |||||
all_theta = zeros(num_labels, n + 1); | |||||
% Add ones to the X data matrix | |||||
X = [ones(m, 1) X]; | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: You should complete the following code to train num_labels | |||||
% logistic regression classifiers with regularization | |||||
% parameter lambda. | |||||
% | |||||
% Hint: theta(:) will return a column vector. | |||||
% | |||||
% Hint: You can use y == c to obtain a vector of 1's and 0's that tell use | |||||
% whether the ground truth is true/false for this class. | |||||
% | |||||
% Note: For this assignment, we recommend using fmincg to optimize the cost | |||||
% function. It is okay to use a for-loop (for c = 1:num_labels) to | |||||
% loop over the different classes. | |||||
% | |||||
% fmincg works similarly to fminunc, but is more efficient when we | |||||
% are dealing with large number of parameters. | |||||
% | |||||
% Example Code for fmincg: | |||||
% | |||||
% % Set Initial theta | |||||
% initial_theta = zeros(n + 1, 1); | |||||
% | |||||
% % Set options for fminunc | |||||
% options = optimset('GradObj', 'on', 'MaxIter', 50); | |||||
% | |||||
% % Run fmincg to obtain the optimal theta | |||||
% % This function will return theta and the cost | |||||
% [theta] = ... | |||||
% fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ... | |||||
% initial_theta, options); | |||||
% | |||||
options = optimset('GradObj', 'on', 'MaxIter', 50); | |||||
for c = 1 : num_labels | |||||
initial_theta = zeros(n + 1, 1); | |||||
all_theta(c,:)= fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ... | |||||
initial_theta, options); | |||||
size(all_theta(c,:)) | |||||
end | |||||
%size(all_theta) | |||||
%initial_theta = zeros(n + 1, num_labels); | |||||
%all_theta= fmincg (@(t)(lrCostFunction(t, X, y, lambda)), ... | |||||
% initial_theta, options); | |||||
% ========================================================================= | |||||
end |
@@ -1,37 +0,0 @@ | |||||
function p = predict(Theta1, Theta2, X) | |||||
%PREDICT Predict the label of an input given a trained neural network | |||||
% p = PREDICT(Theta1, Theta2, X) outputs the predicted label of X given the | |||||
% trained weights of a neural network (Theta1, Theta2) | |||||
% Useful values | |||||
m = size(X, 1); | |||||
num_labels = size(Theta2, 1); | |||||
% You need to return the following variables correctly | |||||
p = zeros(size(X, 1), 1); | |||||
X = [ones(m,1), X]; | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Complete the following code to make predictions using | |||||
% your learned neural network. You should set p to a | |||||
% vector containing labels between 1 to num_labels. | |||||
% | |||||
% Hint: The max function might come in useful. In particular, the max | |||||
% function can also return the index of the max element, for more | |||||
% information see 'help max'. If your examples are in rows, then, you | |||||
% can use max(A, [], 2) to obtain the max for each row. | |||||
% | |||||
a2 = sigmoid(X * Theta1'); | |||||
a2 = [ones(size(a2,1), 1), a2]; | |||||
p = sigmoid(a2 *Theta2'); | |||||
[temp_p,p] = max(p, [], 2); | |||||
% ========================================================================= | |||||
end |
@@ -1,44 +0,0 @@ | |||||
function p = predictOneVsAll(all_theta, X) | |||||
%PREDICT Predict the label for a trained one-vs-all classifier. The labels | |||||
%are in the range 1..K, where K = size(all_theta, 1). | |||||
% p = PREDICTONEVSALL(all_theta, X) will return a vector of predictions | |||||
% for each example in the matrix X. Note that X contains the examples in | |||||
% rows. all_theta is a matrix where the i-th row is a trained logistic | |||||
% regression theta vector for the i-th class. You should set p to a vector | |||||
% of values from 1..K (e.g., p = [1; 3; 1; 2] predicts classes 1, 3, 1, 2 | |||||
% for 4 examples) | |||||
m = size(X, 1); | |||||
num_labels = size(all_theta, 1); | |||||
% You need to return the following variables correctly | |||||
p = zeros(size(X, 1), 1); | |||||
% Add ones to the X data matrix | |||||
X = [ones(m, 1) X]; | |||||
% ====================== YOUR CODE HERE ====================== | |||||
% Instructions: Complete the following code to make predictions using | |||||
% your learned logistic regression parameters (one-vs-all). | |||||
% You should set p to a vector of predictions (from 1 to | |||||
% num_labels). | |||||
% | |||||
% Hint: This code can be done all vectorized using the max function. | |||||
% In particular, the max function can also return the index of the | |||||
% max element, for more information see 'help max'. If your examples | |||||
% are in rows, then, you can use max(A, [], 2) to obtain the max | |||||
% for each row. | |||||
% | |||||
p = X * all_theta'; | |||||
[temp_p,p] = max(p, [], 2); | |||||
%p(find(p == 10)) = 0; | |||||
% ========================================================================= | |||||
end |
@@ -1,6 +0,0 @@ | |||||
function g = sigmoid(z) | |||||
%SIGMOID Compute sigmoid functoon | |||||
% J = SIGMOID(z) computes the sigmoid of z. | |||||
g = 1.0 ./ (1.0 + exp(-z)); | |||||
end |
@@ -1,56 +0,0 @@ | |||||
function submit() | |||||
addpath('./lib'); | |||||
conf.assignmentSlug = 'multi-class-classification-and-neural-networks'; | |||||
conf.itemName = 'Multi-class Classification and Neural Networks'; | |||||
conf.partArrays = { ... | |||||
{ ... | |||||
'1', ... | |||||
{ 'lrCostFunction.m' }, ... | |||||
'Regularized Logistic Regression', ... | |||||
}, ... | |||||
{ ... | |||||
'2', ... | |||||
{ 'oneVsAll.m' }, ... | |||||
'One-vs-All Classifier Training', ... | |||||
}, ... | |||||
{ ... | |||||
'3', ... | |||||
{ 'predictOneVsAll.m' }, ... | |||||
'One-vs-All Classifier Prediction', ... | |||||
}, ... | |||||
{ ... | |||||
'4', ... | |||||
{ 'predict.m' }, ... | |||||
'Neural Network Prediction Function' ... | |||||
}, ... | |||||
}; | |||||
conf.output = @output; | |||||
submitWithConfiguration(conf); | |||||
end | |||||
function out = output(partId, auxdata) | |||||
% Random Test Cases | |||||
X = [ones(20,1) (exp(1) * sin(1:1:20))' (exp(0.5) * cos(1:1:20))']; | |||||
y = sin(X(:,1) + X(:,2)) > 0; | |||||
Xm = [ -1 -1 ; -1 -2 ; -2 -1 ; -2 -2 ; ... | |||||
1 1 ; 1 2 ; 2 1 ; 2 2 ; ... | |||||
-1 1 ; -1 2 ; -2 1 ; -2 2 ; ... | |||||
1 -1 ; 1 -2 ; -2 -1 ; -2 -2 ]; | |||||
ym = [ 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 ]'; | |||||
t1 = sin(reshape(1:2:24, 4, 3)); | |||||
t2 = cos(reshape(1:2:40, 4, 5)); | |||||
if partId == '1' | |||||
[J, grad] = lrCostFunction([0.25 0.5 -0.5]', X, y, 0.1); | |||||
out = sprintf('%0.5f ', J); | |||||
out = [out sprintf('%0.5f ', grad)]; | |||||
elseif partId == '2' | |||||
out = sprintf('%0.5f ', oneVsAll(Xm, ym, 4, 0.1)); | |||||
elseif partId == '3' | |||||
out = sprintf('%0.5f ', predictOneVsAll(t1, Xm)); | |||||
elseif partId == '4' | |||||
out = sprintf('%0.5f ', predict(t1, t2, Xm)); | |||||
end | |||||
end |
@@ -1,15 +0,0 @@ | |||||
# Created by Octave 4.2.0, Sun Nov 27 12:41:13 2016 GMT <unknown@unknown> | |||||
# name: email | |||||
# type: sq_string | |||||
# elements: 1 | |||||
# length: 17 | |||||
scruel@vip.qq.com | |||||
# name: token | |||||
# type: sq_string | |||||
# elements: 1 | |||||
# length: 16 | |||||
CPfDADNFz0Hd0Qgk | |||||
@@ -1,50 +0,0 @@ | |||||
function checkNNGradients(lambda) | |||||
%CHECKNNGRADIENTS Creates a small neural network to check the | |||||
%backpropagation gradients | |||||
% CHECKNNGRADIENTS(lambda) Creates a small neural network to check the | |||||
% backpropagation gradients, it will output the analytical gradients | |||||
% produced by your backprop code and the numerical gradients (computed | |||||
% using computeNumericalGradient). These two gradient computations should | |||||
% result in very similar values. | |||||
% | |||||
if ~exist('lambda', 'var') || isempty(lambda) | |||||
lambda = 0; | |||||
end | |||||
input_layer_size = 3; | |||||
hidden_layer_size = 5; | |||||
num_labels = 3; | |||||
m = 5; | |||||
% We generate some 'random' test data | |||||
Theta1 = debugInitializeWeights(hidden_layer_size, input_layer_size); | |||||
Theta2 = debugInitializeWeights(num_labels, hidden_layer_size); | |||||
% Reusing debugInitializeWeights to generate X | |||||
X = debugInitializeWeights(m, input_layer_size - 1); | |||||
y = 1 + mod(1:m, num_labels)'; | |||||
% Unroll parameters | |||||
nn_params = [Theta1(:) ; Theta2(:)]; | |||||
% Short hand for cost function | |||||
costFunc = @(p) nnCostFunction(p, input_layer_size, hidden_layer_size, ... | |||||
num_labels, X, y, lambda); | |||||
[cost, grad] = costFunc(nn_params); | |||||
numgrad = computeNumericalGradient(costFunc, nn_params); | |||||
% Visually examine the two gradient computations. The two columns | |||||
% you get should be very similar. | |||||
disp([numgrad grad]); | |||||
fprintf(['The above two columns you get should be very similar.\n' ... | |||||
'(Left-Your Numerical Gradient, Right-Analytical Gradient)\n\n']); | |||||
% Evaluate the norm of the difference between two solutions. | |||||
% If you have a correct implementation, and assuming you used EPSILON = 0.0001 | |||||
% in computeNumericalGradient.m, then diff below should be less than 1e-9 | |||||
diff = norm(numgrad-grad)/norm(numgrad+grad); | |||||
fprintf(['If your backpropagation implementation is correct, then \n' ... | |||||
'the relative difference will be small (less than 1e-9). \n' ... | |||||
'\nRelative Difference: %g\n'], diff); | |||||
end |
@@ -1,29 +0,0 @@ | |||||
function numgrad = computeNumericalGradient(J, theta) | |||||
%COMPUTENUMERICALGRADIENT Computes the gradient using "finite differences" | |||||
%and gives us a numerical estimate of the gradient. | |||||
% numgrad = COMPUTENUMERICALGRADIENT(J, theta) computes the numerical | |||||
% gradient of the function J around theta. Calling y = J(theta) should | |||||
% return the function value at theta. | |||||
% Notes: The following code implements numerical gradient checking, and | |||||
% returns the numerical gradient.It sets numgrad(i) to (a numerical | |||||
% approximation of) the partial derivative of J with respect to the | |||||
% i-th input argument, evaluated at theta. (i.e., numgrad(i) should | |||||
% be the (approximately) the partial derivative of J with respect | |||||
% to theta(i).) | |||||
% | |||||
numgrad = zeros(size(theta)); | |||||
perturb = zeros(size(theta)); | |||||
e = 1e-4; | |||||
for p = 1:numel(theta) | |||||
% Set perturbation vector | |||||
perturb(p) = e; | |||||
loss1 = J(theta - perturb); | |||||
loss2 = J(theta + perturb); | |||||
% Compute Numerical Gradient | |||||
numgrad(p) = (loss2 - loss1) / (2*e); | |||||
perturb(p) = 0; | |||||
end | |||||
end |
@@ -1,22 +0,0 @@ | |||||
function W = debugInitializeWeights(fan_out, fan_in) | |||||
%DEBUGINITIALIZEWEIGHTS Initialize the weights of a layer with fan_in | |||||
%incoming connections and fan_out outgoing connections using a fixed | |||||
%strategy, this will help you later in debugging | |||||
% W = DEBUGINITIALIZEWEIGHTS(fan_in, fan_out) initializes the weights | |||||
% of a layer with fan_in incoming connections and fan_out outgoing | |||||
% connections using a fix set of values | |||||
% | |||||
% Note that W should be set to a matrix of size(1 + fan_in, fan_out) as | |||||
% the first row of W handles the "bias" terms | |||||
% | |||||
% Set W to zeros | |||||
W = zeros(fan_out, 1 + fan_in); | |||||
% Initialize W using "sin", this ensures that W is always of the same | |||||
% values and will be useful for debugging | |||||
W = reshape(sin(1:numel(W)), size(W)) / 10; | |||||
% ========================================================================= | |||||
end |
@@ -1,59 +0,0 @@ | |||||
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 |
@@ -1,250 +0,0 @@ | |||||
%% Machine Learning Online Class - Exercise 4 Neural Network Learning | |||||
% Instructions | |||||
% ------------ | |||||
% | |||||
% This file contains code that helps you get started on the | |||||
% linear exercise. You will need to complete the following functions | |||||
% in this exericse: | |||||
% | |||||
% sigmoidGradient.m | |||||
% randInitializeWeights.m | |||||
% nnCostFunction.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 | |||||
%% Setup the parameters you will use for this exercise | |||||
input_layer_size = 400; % 20x20 Input Images of Digits | |||||
hidden_layer_size = 25; % 25 hidden units | |||||
num_labels = 10; % 10 labels, from 1 to 10 | |||||
% (note that we have mapped "0" to label 10) | |||||
%% =========== Part 1: Loading and Visualizing Data ============= | |||||
% We start the exercise by first loading and visualizing the dataset. | |||||
% You will be working with a dataset that contains handwritten digits. | |||||
% | |||||
% Load Training Data | |||||
fprintf('Loading and Visualizing Data ...\n') | |||||
load('ex4data1.mat'); | |||||
m = size(X, 1); | |||||
% Randomly select 100 data points to display | |||||
sel = randperm(size(X, 1)); | |||||
sel = sel(1:100); | |||||
displayData(X(sel, :)); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ================ Part 2: Loading Parameters ================ | |||||
% In this part of the exercise, we load some pre-initialized | |||||
% neural network parameters. | |||||
fprintf('\nLoading Saved Neural Network Parameters ...\n') | |||||
% Load the weights into variables Theta1 and Theta2 | |||||
load('ex4weights.mat'); | |||||
% Unroll parameters | |||||
nn_params = [Theta1(:) ; Theta2(:)]; | |||||
%% ================ Part 3: Compute Cost (Feedforward) ================ | |||||
% To the neural network, you should first start by implementing the | |||||
% feedforward part of the neural network that returns the cost only. You | |||||
% should complete the code in nnCostFunction.m to return cost. After | |||||
% implementing the feedforward to compute the cost, you can verify that | |||||
% your implementation is correct by verifying that you get the same cost | |||||
% as us for the fixed debugging parameters. | |||||
% | |||||
% We suggest implementing the feedforward cost *without* regularization | |||||
% first so that it will be easier for you to debug. Later, in part 4, you | |||||
% will get to implement the regularized cost. | |||||
% | |||||
fprintf('\nFeedforward Using Neural Network ...\n') | |||||
% Weight regularization parameter (we set this to 0 here). | |||||
lambda = 0; | |||||
J = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, ... | |||||
num_labels, X, y, lambda); | |||||
fprintf(['Cost at parameters (loaded from ex4weights): %f '... | |||||
'\n(this value should be about 0.287629)\n'], J); | |||||
fprintf('\nProgram paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% =============== Part 4: Implement Regularization =============== | |||||
% Once your cost function implementation is correct, you should now | |||||
% continue to implement the regularization with the cost. | |||||
% | |||||
fprintf('\nChecking Cost Function (w/ Regularization) ... \n') | |||||
% Weight regularization parameter (we set this to 1 here). | |||||
lambda = 1; | |||||
J = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, ... | |||||
num_labels, X, y, lambda); | |||||
fprintf(['Cost at parameters (loaded from ex4weights): %f '... | |||||
'\n(this value should be about 0.383770)\n'], J); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ================ Part 5: Sigmoid Gradient ================ | |||||
% Before you start implementing the neural network, you will first | |||||
% implement the gradient for the sigmoid function. You should complete the | |||||
% code in the sigmoidGradient.m file. | |||||
% | |||||
fprintf('\nEvaluating sigmoid gradient...\n') | |||||
g = sigmoidGradient([1 -0.5 0 0.5 1]); | |||||
fprintf('Sigmoid gradient evaluated at [1 -0.5 0 0.5 1]:\n '); | |||||
fprintf('%f ', g); | |||||
fprintf('\n\n'); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ================ Part 6: Initializing Pameters ================ | |||||
% In this part of the exercise, you will be starting to implment a two | |||||
% layer neural network that classifies digits. You will start by | |||||
% implementing a function to initialize the weights of the neural network | |||||
% (randInitializeWeights.m) | |||||
fprintf('\nInitializing Neural Network Parameters ...\n') | |||||
initial_Theta1 = randInitializeWeights(input_layer_size, hidden_layer_size); | |||||
initial_Theta2 = randInitializeWeights(hidden_layer_size, num_labels); | |||||
% Unroll parameters | |||||
initial_nn_params = [initial_Theta1(:) ; initial_Theta2(:)]; | |||||
%% =============== Part 7: Implement Backpropagation =============== | |||||
% Once your cost matches up with ours, you should proceed to implement the | |||||
% backpropagation algorithm for the neural network. You should add to the | |||||
% code you've written in nnCostFunction.m to return the partial | |||||
% derivatives of the parameters. | |||||
% | |||||
fprintf('\nChecking Backpropagation... \n'); | |||||
% Check gradients by running checkNNGradients | |||||
checkNNGradients; | |||||
fprintf('\nProgram paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% =============== Part 8: Implement Regularization =============== | |||||
% Once your backpropagation implementation is correct, you should now | |||||
% continue to implement the regularization with the cost and gradient. | |||||
% | |||||
fprintf('\nChecking Backpropagation (w/ Regularization) ... \n') | |||||
% Check gradients by running checkNNGradients | |||||
lambda = 3; | |||||
checkNNGradients(lambda); | |||||
% Also output the costFunction debugging values | |||||
debug_J = nnCostFunction(nn_params, input_layer_size, ... | |||||
hidden_layer_size, num_labels, X, y, lambda); | |||||
fprintf(['\n\nCost at (fixed) debugging parameters (w/ lambda = 10): %f ' ... | |||||
'\n(this value should be about 0.576051)\n\n'], debug_J); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% =================== Part 8: Training NN =================== | |||||
% You have now implemented all the code necessary to train a neural | |||||
% network. To train your neural network, we will now use "fmincg", which | |||||
% is a function which works similarly to "fminunc". Recall that these | |||||
% advanced optimizers are able to train our cost functions efficiently as | |||||
% long as we provide them with the gradient computations. | |||||
% | |||||
fprintf('\nTraining Neural Network... \n') | |||||
% After you have completed the assignment, change the MaxIter to a larger | |||||
% value to see how more training helps. | |||||
options = optimset('MaxIter', 400); | |||||
% You should also try different values of lambda | |||||
lambda = 1; | |||||
% Create "short hand" for the cost function to be minimized | |||||
costFunction = @(p) nnCostFunction(p, ... | |||||
input_layer_size, ... | |||||
hidden_layer_size, ... | |||||
num_labels, X, y, lambda); | |||||
% Now, costFunction is a function that takes in only one argument (the | |||||
% neural network parameters) | |||||
[nn_params, cost] = fmincg(costFunction, initial_nn_params, options); | |||||
% Obtain Theta1 and Theta2 back from nn_params | |||||
disp("test") | |||||
Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ... | |||||
hidden_layer_size, (input_layer_size + 1)); | |||||
Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ... | |||||
num_labels, (hidden_layer_size + 1)); | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ================= Part 9: Visualize Weights ================= | |||||
% You can now "visualize" what the neural network is learning by | |||||
% displaying the hidden units to see what features they are capturing in | |||||
% the data. | |||||
fprintf('\nVisualizing Neural Network... \n') | |||||
displayData(Theta1(:, 2:end)); | |||||
fprintf('\nProgram paused. Press enter to continue.\n'); | |||||
pause; | |||||
%% ================= Part 10: Implement Predict ================= | |||||
% After training the neural network, we would like to use it to predict | |||||
% the labels. You will now implement the "predict" function to use the | |||||
% neural network to predict the labels of the training set. This lets | |||||
% you compute the training set accuracy. | |||||
pred = predict(Theta1, Theta2, X); | |||||
fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100); | |||||
% Randomly permute examples | |||||
rp = randperm(m); | |||||
for i = 1:m | |||||
% Display | |||||
fprintf('\nDisplaying Example Image\n'); | |||||
displayData(X(rp(i), :)); | |||||
pred = predict(Theta1, Theta2, X(rp(i),:)); | |||||
fprintf('\nNeural Network Prediction: %d (digit %d)\n', pred, mod(pred, 10)); | |||||
% Pause | |||||
fprintf('Program paused. Press enter to continue.\n'); | |||||
pause; | |||||
end |