From 4620fe865262858e280ef01255fe45b441b2f9d6 Mon Sep 17 00:00:00 2001 From: mjjo53 Date: Sun, 28 May 2017 16:07:48 +0900 Subject: [PATCH] initial commit --- ex5.pdf | Bin 0 -> 187357 bytes ex5/ex5.m | 220 ++++++++++++ ex5/ex5data1.mat | Bin 0 -> 1321 bytes ex5/featureNormalize.m | 17 + ex5/fmincg.m | 175 +++++++++ ex5/learningCurve.m | 66 ++++ ex5/lib/jsonlab/AUTHORS.txt | 41 +++ ex5/lib/jsonlab/ChangeLog.txt | 74 ++++ ex5/lib/jsonlab/LICENSE_BSD.txt | 25 ++ ex5/lib/jsonlab/README.txt | 394 +++++++++++++++++++++ ex5/lib/jsonlab/jsonopt.m | 32 ++ ex5/lib/jsonlab/loadjson.m | 566 ++++++++++++++++++++++++++++++ ex5/lib/jsonlab/loadubjson.m | 528 ++++++++++++++++++++++++++++ ex5/lib/jsonlab/mergestruct.m | 33 ++ ex5/lib/jsonlab/savejson.m | 475 +++++++++++++++++++++++++ ex5/lib/jsonlab/saveubjson.m | 504 ++++++++++++++++++++++++++ ex5/lib/jsonlab/varargin2struct.m | 40 +++ ex5/lib/makeValidFieldName.m | 30 ++ ex5/lib/submitWithConfiguration.m | 179 ++++++++++ ex5/linearRegCostFunction.m | 37 ++ ex5/plotFit.m | 28 ++ ex5/polyFeatures.m | 25 ++ ex5/submit.m | 63 ++++ ex5/trainLinearReg.m | 21 ++ ex5/validationCurve.m | 53 +++ 25 files changed, 3626 insertions(+) create mode 100644 ex5.pdf create mode 100644 ex5/ex5.m create mode 100644 ex5/ex5data1.mat create mode 100644 ex5/featureNormalize.m create mode 100644 ex5/fmincg.m create mode 100644 ex5/learningCurve.m create mode 100644 ex5/lib/jsonlab/AUTHORS.txt create mode 100644 ex5/lib/jsonlab/ChangeLog.txt create mode 100644 ex5/lib/jsonlab/LICENSE_BSD.txt create mode 100644 ex5/lib/jsonlab/README.txt create mode 100644 ex5/lib/jsonlab/jsonopt.m create mode 100644 ex5/lib/jsonlab/loadjson.m create mode 100644 ex5/lib/jsonlab/loadubjson.m create mode 100644 ex5/lib/jsonlab/mergestruct.m create mode 100644 ex5/lib/jsonlab/savejson.m create mode 100644 ex5/lib/jsonlab/saveubjson.m create mode 100644 ex5/lib/jsonlab/varargin2struct.m create mode 100644 ex5/lib/makeValidFieldName.m create mode 100644 ex5/lib/submitWithConfiguration.m create mode 100644 ex5/linearRegCostFunction.m create mode 100644 ex5/plotFit.m create mode 100644 ex5/polyFeatures.m create mode 100644 ex5/submit.m create mode 100644 ex5/trainLinearReg.m create mode 100644 ex5/validationCurve.m diff --git a/ex5.pdf b/ex5.pdf new file mode 100644 index 0000000000000000000000000000000000000000..31ad5081a242801e2809d0ee0ca132ada30883b9 GIT binary patch literal 187357 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

o~tv- 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�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 literal 0 HcmV?d00001 diff --git a/ex5/ex5.m b/ex5/ex5.m new file mode 100644 index 0000000..be31c64 --- /dev/null +++ b/ex5/ex5.m @@ -0,0 +1,220 @@ +%% Machine Learning Online Class +% Exercise 5 | Regularized Linear Regression and Bias-Variance +% +% Instructions +% ------------ +% +% This file contains code that helps you get started on the +% exercise. You will need to complete the following functions: +% +% linearRegCostFunction.m +% learningCurve.m +% validationCurve.m +% +% For this exercise, you will not need to change any code in this file, +% or any other files other than those mentioned above. +% + +%% Initialization +clear ; close all; clc + +%% =========== Part 1: Loading and Visualizing Data ============= +% We start the exercise by first loading and visualizing the dataset. +% The following code will load the dataset into your environment and plot +% the data. +% + +% Load Training Data +fprintf('Loading and Visualizing Data ...\n') + +% Load from ex5data1: +% You will have X, y, Xval, yval, Xtest, ytest in your environment +load ('ex5data1.mat'); + +% m = Number of examples +m = size(X, 1); + +% Plot training data +plot(X, y, 'rx', 'MarkerSize', 10, 'LineWidth', 1.5); +xlabel('Change in water level (x)'); +ylabel('Water flowing out of the dam (y)'); + +fprintf('Program paused. Press enter to continue.\n'); +pause; + +%% =========== Part 2: Regularized Linear Regression Cost ============= +% You should now implement the cost function for regularized linear +% regression. +% + +theta = [1 ; 1]; +J = linearRegCostFunction([ones(m, 1) X], y, theta, 1); + +fprintf(['Cost at theta = [1 ; 1]: %f '... + '\n(this value should be about 303.993192)\n'], J); + +fprintf('Program paused. Press enter to continue.\n'); +pause; + +%% =========== Part 3: Regularized Linear Regression Gradient ============= +% You should now implement the gradient for regularized linear +% regression. +% + +theta = [1 ; 1]; +[J, grad] = linearRegCostFunction([ones(m, 1) X], y, theta, 1); + +fprintf(['Gradient at theta = [1 ; 1]: [%f; %f] '... + '\n(this value should be about [-15.303016; 598.250744])\n'], ... + grad(1), grad(2)); + +fprintf('Program paused. Press enter to continue.\n'); +pause; + + +%% =========== Part 4: Train Linear Regression ============= +% Once you have implemented the cost and gradient correctly, the +% trainLinearReg function will use your cost function to train +% regularized linear regression. +% +% Write Up Note: The data is non-linear, so this will not give a great +% fit. +% + +% Train linear regression with lambda = 0 +lambda = 0; +[theta] = trainLinearReg([ones(m, 1) X], y, lambda); + +% Plot fit over the data +plot(X, y, 'rx', 'MarkerSize', 10, 'LineWidth', 1.5); +xlabel('Change in water level (x)'); +ylabel('Water flowing out of the dam (y)'); +hold on; +plot(X, [ones(m, 1) X]*theta, '--', 'LineWidth', 2) +hold off; + +fprintf('Program paused. Press enter to continue.\n'); +pause; + + +%% =========== Part 5: Learning Curve for Linear Regression ============= +% Next, you should implement the learningCurve function. +% +% Write Up Note: Since the model is underfitting the data, we expect to +% see a graph with "high bias" -- Figure 3 in ex5.pdf +% + +lambda = 0; +[error_train, error_val] = ... + learningCurve([ones(m, 1) X], y, ... + [ones(size(Xval, 1), 1) Xval], yval, ... + lambda); + +plot(1:m, error_train, 1:m, error_val); +title('Learning curve for linear regression') +legend('Train', 'Cross Validation') +xlabel('Number of training examples') +ylabel('Error') +axis([0 13 0 150]) + +fprintf('# Training Examples\tTrain Error\tCross Validation Error\n'); +for i = 1:m + fprintf(' \t%d\t\t%f\t%f\n', i, error_train(i), error_val(i)); +end + +fprintf('Program paused. Press enter to continue.\n'); +pause; + +%% =========== Part 6: Feature Mapping for Polynomial Regression ============= +% One solution to this is to use polynomial regression. You should now +% complete polyFeatures to map each example into its powers +% + +p = 8; + +% Map X onto Polynomial Features and Normalize +X_poly = polyFeatures(X, p); +[X_poly, mu, sigma] = featureNormalize(X_poly); % Normalize +X_poly = [ones(m, 1), X_poly]; % Add Ones + +% Map X_poly_test and normalize (using mu and sigma) +X_poly_test = polyFeatures(Xtest, p); +X_poly_test = bsxfun(@minus, X_poly_test, mu); +X_poly_test = bsxfun(@rdivide, X_poly_test, sigma); +X_poly_test = [ones(size(X_poly_test, 1), 1), X_poly_test]; % Add Ones + +% Map X_poly_val and normalize (using mu and sigma) +X_poly_val = polyFeatures(Xval, p); +X_poly_val = bsxfun(@minus, X_poly_val, mu); +X_poly_val = bsxfun(@rdivide, X_poly_val, sigma); +X_poly_val = [ones(size(X_poly_val, 1), 1), X_poly_val]; % Add Ones + +fprintf('Normalized Training Example 1:\n'); +fprintf(' %f \n', X_poly(1, :)); + +fprintf('\nProgram paused. Press enter to continue.\n'); +pause; + + + +%% =========== Part 7: Learning Curve for Polynomial Regression ============= +% Now, you will get to experiment with polynomial regression with multiple +% values of lambda. The code below runs polynomial regression with +% lambda = 0. You should try running the code with different values of +% lambda to see how the fit and learning curve change. +% + +lambda = 0; +[theta] = trainLinearReg(X_poly, y, lambda); + +% Plot training data and fit +figure(1); +plot(X, y, 'rx', 'MarkerSize', 10, 'LineWidth', 1.5); +plotFit(min(X), max(X), mu, sigma, theta, p); +xlabel('Change in water level (x)'); +ylabel('Water flowing out of the dam (y)'); +title (sprintf('Polynomial Regression Fit (lambda = %f)', lambda)); + +figure(2); +[error_train, error_val] = ... + learningCurve(X_poly, y, X_poly_val, yval, lambda); +plot(1:m, error_train, 1:m, error_val); + +title(sprintf('Polynomial Regression Learning Curve (lambda = %f)', lambda)); +xlabel('Number of training examples') +ylabel('Error') +axis([0 13 0 100]) +legend('Train', 'Cross Validation') + +fprintf('Polynomial Regression (lambda = %f)\n\n', lambda); +fprintf('# Training Examples\tTrain Error\tCross Validation Error\n'); +for i = 1:m + fprintf(' \t%d\t\t%f\t%f\n', i, error_train(i), error_val(i)); +end + +fprintf('Program paused. Press enter to continue.\n'); +pause; + +%% =========== Part 8: Validation for Selecting Lambda ============= +% You will now implement validationCurve to test various values of +% lambda on a validation set. You will then use this to select the +% "best" lambda value. +% + +[lambda_vec, error_train, error_val] = ... + validationCurve(X_poly, y, X_poly_val, yval); + +close all; +plot(lambda_vec, error_train, lambda_vec, error_val); +legend('Train', 'Cross Validation'); +xlabel('lambda'); +ylabel('Error'); + +fprintf('lambda\t\tTrain Error\tValidation Error\n'); +for i = 1:length(lambda_vec) + fprintf(' %f\t%f\t%f\n', ... + lambda_vec(i), error_train(i), error_val(i)); +end + +fprintf('Program paused. Press enter to continue.\n'); +pause; diff --git a/ex5/ex5data1.mat b/ex5/ex5data1.mat new file mode 100644 index 0000000000000000000000000000000000000000..5a17abdbb0c1ff969b288e6fae7b795a309f40b1 GIT binary patch literal 1321 zcmeZu4DoSvQZUssQ1EpO(M`+DN!3vZ$Vn_o%P-2cQgHY2i*PhE(NSnFH=x3Q7|&HGBUR^GE*=zFf>#k5il@%`tma{FmwZP#hk~<2?;Y8j^sF; zVO;9iAbRRKW0IReT1p4Qr8y3B7>*Qw^OBoa9{=A#D)~>4Z|QC3G(WDcb3%T66VopL z|9k)WlZ5H1`!>(L``F>)_Zi7K{UZE19CMG@)vlX&_^!Up`pb)C_+u{mSAW0!Y4%^M zW!UHF`|f(7EFKXrdjHXZ8WtC}V3 zzuw~4$$xC?S6wfUb#LFGeR7lEO+UVE`Dkaa?u^Q ziz<);Nt`vwO@pn|b;=U4=?s~E3UQ1_Y_{vUx`3Xh+>^3dh&qYvp)dh9VK=DKBKS8X@EnYZ?-Q8_#N>FcNeKbwE0 zXvXG8vDafY&D+gc`6nCM*uDM#(BS#&LwskM_shE${7EV<;do*gZ&=;8x!LjH5%sy3 z|KIk1I9qO=?fq*Dmmhu=b}s8P^URtz;X7|k;S1^1i<TyIqFgWlqKZ z3zI@`GBPCAhMR)?cmtmwL#HA9*uU+M*N@u=pFUXl^V`<1C4ubCxu=fb&#_5(f7Wj0 znMW&HoR>vx{841++%7+l?Yx>_ZRY*g+EL4lC!bYRc(qOId5tu?|1(WJ{vEusPEYrQ z_L^5&PdPJx!!6T*1BxFOemQeUkCpxOje^_Sj^Ft9znymah)-b|hsFC3m3#Y|oFhW? z-52+?HYYU~y!z99hHrVzTP32_hIvE zw4@&wImACb@V&QZ9=p?3-*+i#QgQ*_v%i(x6O(Ii;WB^PS0LHWdd6pUXviJeU1fPc zg0fe>W?;C;6|xBA!Rz=uxIzc!!BgFvYR;E3@im=ayi0BehlP*P=iayhvW()`|62d&ENEU?cyXs~UK$?{&;B*jj5fTVZu8sg zXL@tz;ZE=VeEWT;pDR=(uPgCfv#~k+PWH|DvWNKIi~Y6OeLmpq!o;2Ky?@`2F@~|PPWQ1^zZ+D#A@ugN%UeAUHa=b2zcZq1I&-zd=AYMdqxcv~ InY~{C067#^{r~^~ literal 0 HcmV?d00001 diff --git a/ex5/featureNormalize.m b/ex5/featureNormalize.m new file mode 100644 index 0000000..da03bee --- /dev/null +++ b/ex5/featureNormalize.m @@ -0,0 +1,17 @@ +function [X_norm, mu, sigma] = featureNormalize(X) +%FEATURENORMALIZE Normalizes the features in X +% FEATURENORMALIZE(X) returns a normalized version of X where +% the mean value of each feature is 0 and the standard deviation +% is 1. This is often a good preprocessing step to do when +% working with learning algorithms. + +mu = mean(X); +X_norm = bsxfun(@minus, X, mu); + +sigma = std(X_norm); +X_norm = bsxfun(@rdivide, X_norm, sigma); + + +% ============================================================ + +end diff --git a/ex5/fmincg.m b/ex5/fmincg.m new file mode 100644 index 0000000..47a8816 --- /dev/null +++ b/ex5/fmincg.m @@ -0,0 +1,175 @@ +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'); diff --git a/ex5/learningCurve.m b/ex5/learningCurve.m new file mode 100644 index 0000000..6ea4333 --- /dev/null +++ b/ex5/learningCurve.m @@ -0,0 +1,66 @@ +function [error_train, error_val] = ... + learningCurve(X, y, Xval, yval, lambda) +%LEARNINGCURVE Generates the train and cross validation set errors needed +%to plot a learning curve +% [error_train, error_val] = ... +% LEARNINGCURVE(X, y, Xval, yval, lambda) returns the train and +% cross validation set errors for a learning curve. In particular, +% it returns two vectors of the same length - error_train and +% error_val. Then, error_train(i) contains the training error for +% i examples (and similarly for error_val(i)). +% +% In this function, you will compute the train and test errors for +% dataset sizes from 1 up to m. In practice, when working with larger +% datasets, you might want to do this in larger intervals. +% + +% Number of training examples +m = size(X, 1); + +% You need to return these values correctly +error_train = zeros(m, 1); +error_val = zeros(m, 1); + +% ====================== YOUR CODE HERE ====================== +% Instructions: Fill in this function to return training errors in +% error_train and the cross validation errors in error_val. +% i.e., error_train(i) and +% error_val(i) should give you the errors +% obtained after training on i examples. +% +% Note: You should evaluate the training error on the first i training +% examples (i.e., X(1:i, :) and y(1:i)). +% +% For the cross-validation error, you should instead evaluate on +% the _entire_ cross validation set (Xval and yval). +% +% Note: If you are using your cost function (linearRegCostFunction) +% to compute the training and cross validation error, you should +% call the function with the lambda argument set to 0. +% Do note that you will still need to use lambda when running +% the training to obtain the theta parameters. +% +% Hint: You can loop over the examples with the following: +% +% for i = 1:m +% % Compute train/cross validation errors using training examples +% % X(1:i, :) and y(1:i), storing the result in +% % error_train(i) and error_val(i) +% .... +% +% end +% + +% ---------------------- Sample Solution ---------------------- + + + + + + + +% ------------------------------------------------------------- + +% ========================================================================= + +end diff --git a/ex5/lib/jsonlab/AUTHORS.txt b/ex5/lib/jsonlab/AUTHORS.txt new file mode 100644 index 0000000..9dd3fc7 --- /dev/null +++ b/ex5/lib/jsonlab/AUTHORS.txt @@ -0,0 +1,41 @@ +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: or + + +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 + part of revision 341 + +- Niclas Borlin + 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 + patches for svn revision 415. + - savejson saves an empty cell array as [] instead of null + - loadjson differentiates an empty struct from an empty array diff --git a/ex5/lib/jsonlab/ChangeLog.txt b/ex5/lib/jsonlab/ChangeLog.txt new file mode 100644 index 0000000..07824f5 --- /dev/null +++ b/ex5/lib/jsonlab/ChangeLog.txt @@ -0,0 +1,74 @@ +============================================================================ + + 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 == + + 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 == + + 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 == + + 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 == + + 2014/01/22 use binary read and write in saveubjson and loadubjson + +== JSONlab 0.9.8-1 (codename: Optimus - alpha update 1), FangQ == + + 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 == + 2013/08/23 *universal Binary JSON (UBJSON) support, including both saveubjson and loadubjson + +== JSONlab 0.9.1 (codename: Rodimus, update 1), FangQ == + 2012/12/18 *handling of various empty and sparse matrices (fixes submitted by Niclas Borlin) + +== JSONlab 0.9.0 (codename: Rodimus), FangQ == + + 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 == + + 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 == + + 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 == + + 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 == + + 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 diff --git a/ex5/lib/jsonlab/LICENSE_BSD.txt b/ex5/lib/jsonlab/LICENSE_BSD.txt new file mode 100644 index 0000000..32d66cb --- /dev/null +++ b/ex5/lib/jsonlab/LICENSE_BSD.txt @@ -0,0 +1,25 @@ +Copyright 2011-2015 Qianqian Fang . 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. diff --git a/ex5/lib/jsonlab/README.txt b/ex5/lib/jsonlab/README.txt new file mode 100644 index 0000000..7b4f732 --- /dev/null +++ b/ex5/lib/jsonlab/README.txt @@ -0,0 +1,394 @@ +=============================================================================== += JSONLab = += An open-source MATLAB/Octave JSON encoder and decoder = +=============================================================================== + +*Copyright (C) 2011-2015 Qianqian Fang +*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 === +

+  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 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)
+
+ +=== savejson.m === + +
+  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 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')
+ 
+ +=== loadubjson.m === + +
+  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 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)
+
+ +=== saveubjson.m === + +
+  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 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')
+
+ + +=== 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). diff --git a/ex5/lib/jsonlab/jsonopt.m b/ex5/lib/jsonlab/jsonopt.m new file mode 100644 index 0000000..0bebd8d --- /dev/null +++ b/ex5/lib/jsonlab/jsonopt.m @@ -0,0 +1,32 @@ +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 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 + diff --git a/ex5/lib/jsonlab/loadjson.m b/ex5/lib/jsonlab/loadjson.m new file mode 100644 index 0000000..42798c0 --- /dev/null +++ b/ex5/lib/jsonlab/loadjson.m @@ -0,0 +1,566 @@ +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 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)) '' 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(pos1 && 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 + diff --git a/ex5/lib/jsonlab/loadubjson.m b/ex5/lib/jsonlab/loadubjson.m new file mode 100644 index 0000000..0155115 --- /dev/null +++ b/ex5/lib/jsonlab/loadubjson.m @@ -0,0 +1,528 @@ +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 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)) '' 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(pos1 && 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 + diff --git a/ex5/lib/jsonlab/mergestruct.m b/ex5/lib/jsonlab/mergestruct.m new file mode 100644 index 0000000..6de6100 --- /dev/null +++ b/ex5/lib/jsonlab/mergestruct.m @@ -0,0 +1,33 @@ +function s=mergestruct(s1,s2) +% +% s=mergestruct(s1,s2) +% +% merge two struct objects into one +% +% authors:Qianqian Fang (fangq 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 + diff --git a/ex5/lib/jsonlab/savejson.m b/ex5/lib/jsonlab/savejson.m new file mode 100644 index 0000000..7e84076 --- /dev/null +++ b/ex5/lib/jsonlab/savejson.m @@ -0,0 +1,475 @@ +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 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(i1) txt=sprintf('%s%s%s]',txt,nl,padding2); end + if(j1) 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(e1) txt=sprintf('%s%s%s]',txt,nl,padding2); end + if(j1) 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 diff --git a/ex5/lib/jsonlab/saveubjson.m b/ex5/lib/jsonlab/saveubjson.m new file mode 100644 index 0000000..eaec433 --- /dev/null +++ b/ex5/lib/jsonlab/saveubjson.m @@ -0,0 +1,504 @@ +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 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(:)'; diff --git a/ex5/lib/jsonlab/varargin2struct.m b/ex5/lib/jsonlab/varargin2struct.m new file mode 100644 index 0000000..9a5c2b6 --- /dev/null +++ b/ex5/lib/jsonlab/varargin2struct.m @@ -0,0 +1,40 @@ +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 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 0 && resp(1) == '{'; + isHtml = findstr(lower(resp), ']+>', ' '); + strippedResponse = regexprep(strippedResponse, '[\t ]+', ' '); + fprintf(strippedResponse); +end + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Service configuration +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function submissionUrl = submissionUrl() + submissionUrl = 'https://www-origin.coursera.org/api/onDemandProgrammingImmediateFormSubmissions.v1'; +end diff --git a/ex5/linearRegCostFunction.m b/ex5/linearRegCostFunction.m new file mode 100644 index 0000000..6addf6b --- /dev/null +++ b/ex5/linearRegCostFunction.m @@ -0,0 +1,37 @@ +function [J, grad] = linearRegCostFunction(X, y, theta, lambda) +%LINEARREGCOSTFUNCTION Compute cost and gradient for regularized linear +%regression with multiple variables +% [J, grad] = LINEARREGCOSTFUNCTION(X, y, theta, lambda) computes the +% cost of using theta as the parameter for linear regression to fit the +% data points in X and y. Returns the cost in J and the gradient in grad + +% 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 and gradient of regularized linear +% regression for a particular choice of theta. +% +% You should set J to the cost and grad to the gradient. +% + + + + + + + + + + + + +% ========================================================================= + +grad = grad(:); + +end diff --git a/ex5/plotFit.m b/ex5/plotFit.m new file mode 100644 index 0000000..8dba7cf --- /dev/null +++ b/ex5/plotFit.m @@ -0,0 +1,28 @@ +function plotFit(min_x, max_x, mu, sigma, theta, p) +%PLOTFIT Plots a learned polynomial regression fit over an existing figure. +%Also works with linear regression. +% PLOTFIT(min_x, max_x, mu, sigma, theta, p) plots the learned polynomial +% fit with power p and feature normalization (mu, sigma). + +% Hold on to the current figure +hold on; + +% We plot a range slightly bigger than the min and max values to get +% an idea of how the fit will vary outside the range of the data points +x = (min_x - 15: 0.05 : max_x + 25)'; + +% Map the X values +X_poly = polyFeatures(x, p); +X_poly = bsxfun(@minus, X_poly, mu); +X_poly = bsxfun(@rdivide, X_poly, sigma); + +% Add ones +X_poly = [ones(size(x, 1), 1) X_poly]; + +% Plot +plot(x, X_poly * theta, '--', 'LineWidth', 2) + +% Hold off to the current figure +hold off + +end diff --git a/ex5/polyFeatures.m b/ex5/polyFeatures.m new file mode 100644 index 0000000..f496f48 --- /dev/null +++ b/ex5/polyFeatures.m @@ -0,0 +1,25 @@ +function [X_poly] = polyFeatures(X, p) +%POLYFEATURES Maps X (1D vector) into the p-th power +% [X_poly] = POLYFEATURES(X, p) takes a data matrix X (size m x 1) and +% maps each example into its polynomial features where +% X_poly(i, :) = [X(i) X(i).^2 X(i).^3 ... X(i).^p]; +% + + +% You need to return the following variables correctly. +X_poly = zeros(numel(X), p); + +% ====================== YOUR CODE HERE ====================== +% Instructions: Given a vector X, return a matrix X_poly where the p-th +% column of X contains the values of X to the p-th power. +% +% + + + + + + +% ========================================================================= + +end diff --git a/ex5/submit.m b/ex5/submit.m new file mode 100644 index 0000000..e129567 --- /dev/null +++ b/ex5/submit.m @@ -0,0 +1,63 @@ +function submit() + addpath('./lib'); + + conf.assignmentSlug = 'regularized-linear-regression-and-bias-variance'; + conf.itemName = 'Regularized Linear Regression and Bias/Variance'; + conf.partArrays = { ... + { ... + '1', ... + { 'linearRegCostFunction.m' }, ... + 'Regularized Linear Regression Cost Function', ... + }, ... + { ... + '2', ... + { 'linearRegCostFunction.m' }, ... + 'Regularized Linear Regression Gradient', ... + }, ... + { ... + '3', ... + { 'learningCurve.m' }, ... + 'Learning Curve', ... + }, ... + { ... + '4', ... + { 'polyFeatures.m' }, ... + 'Polynomial Feature Mapping', ... + }, ... + { ... + '5', ... + { 'validationCurve.m' }, ... + 'Validation Curve', ... + }, ... + }; + conf.output = @output; + + submitWithConfiguration(conf); +end + +function out = output(partId, auxstring) + % Random Test Cases + X = [ones(10,1) sin(1:1.5:15)' cos(1:1.5:15)']; + y = sin(1:3:30)'; + Xval = [ones(10,1) sin(0:1.5:14)' cos(0:1.5:14)']; + yval = sin(1:10)'; + if partId == '1' + [J] = linearRegCostFunction(X, y, [0.1 0.2 0.3]', 0.5); + out = sprintf('%0.5f ', J); + elseif partId == '2' + [J, grad] = linearRegCostFunction(X, y, [0.1 0.2 0.3]', 0.5); + out = sprintf('%0.5f ', grad); + elseif partId == '3' + [error_train, error_val] = ... + learningCurve(X, y, Xval, yval, 1); + out = sprintf('%0.5f ', [error_train(:); error_val(:)]); + elseif partId == '4' + [X_poly] = polyFeatures(X(2,:)', 8); + out = sprintf('%0.5f ', X_poly); + elseif partId == '5' + [lambda_vec, error_train, error_val] = ... + validationCurve(X, y, Xval, yval); + out = sprintf('%0.5f ', ... + [lambda_vec(:); error_train(:); error_val(:)]); + end +end diff --git a/ex5/trainLinearReg.m b/ex5/trainLinearReg.m new file mode 100644 index 0000000..eb89860 --- /dev/null +++ b/ex5/trainLinearReg.m @@ -0,0 +1,21 @@ +function [theta] = trainLinearReg(X, y, lambda) +%TRAINLINEARREG Trains linear regression given a dataset (X, y) and a +%regularization parameter lambda +% [theta] = TRAINLINEARREG (X, y, lambda) trains linear regression using +% the dataset (X, y) and regularization parameter lambda. Returns the +% trained parameters theta. +% + +% Initialize Theta +initial_theta = zeros(size(X, 2), 1); + +% Create "short hand" for the cost function to be minimized +costFunction = @(t) linearRegCostFunction(X, y, t, lambda); + +% Now, costFunction is a function that takes in only one argument +options = optimset('MaxIter', 200, 'GradObj', 'on'); + +% Minimize using fmincg +theta = fmincg(costFunction, initial_theta, options); + +end diff --git a/ex5/validationCurve.m b/ex5/validationCurve.m new file mode 100644 index 0000000..24b56bc --- /dev/null +++ b/ex5/validationCurve.m @@ -0,0 +1,53 @@ +function [lambda_vec, error_train, error_val] = ... + validationCurve(X, y, Xval, yval) +%VALIDATIONCURVE Generate the train and validation errors needed to +%plot a validation curve that we can use to select lambda +% [lambda_vec, error_train, error_val] = ... +% VALIDATIONCURVE(X, y, Xval, yval) returns the train +% and validation errors (in error_train, error_val) +% for different values of lambda. You are given the training set (X, +% y) and validation set (Xval, yval). +% + +% Selected values of lambda (you should not change this) +lambda_vec = [0 0.001 0.003 0.01 0.03 0.1 0.3 1 3 10]'; + +% You need to return these variables correctly. +error_train = zeros(length(lambda_vec), 1); +error_val = zeros(length(lambda_vec), 1); + +% ====================== YOUR CODE HERE ====================== +% Instructions: Fill in this function to return training errors in +% error_train and the validation errors in error_val. The +% vector lambda_vec contains the different lambda parameters +% to use for each calculation of the errors, i.e, +% error_train(i), and error_val(i) should give +% you the errors obtained after training with +% lambda = lambda_vec(i) +% +% Note: You can loop over lambda_vec with the following: +% +% for i = 1:length(lambda_vec) +% lambda = lambda_vec(i); +% % Compute train / val errors when training linear +% % regression with regularization parameter lambda +% % You should store the result in error_train(i) +% % and error_val(i) +% .... +% +% end +% +% + + + + + + + + + + +% ========================================================================= + +end