%% Generate Code for Fuzzy System Using MATLAB Coder
% You can generate code for evaluating a fuzzy inference system using MATLAB® Coder™. For more information on generating code, see docid:coder_doccenter#bs2r9ti-1.
% To generate code for evaluating fuzzy systems, you must first create a fuzzy inference system (FIS). For more information, see docid:fuzzy#FP37900 and docid:fuzzy#FP243DUP9.
% While this example generates code for a type-1 Mamdani fuzzy inference system, the workflow also applies to Sugeno and type-2 fuzzy systems.
% Generating code using MATLAB Coder does not support fuzzy FIS objects (mamfis, sugfis, mamfistype2, sugfistype2). To generate code for evaluating fuzzy systems, you must convert your fuzzy inference system objects into homogeneous structures using the docid:fuzzy#mw_07ae4b0e-df7c-4350-9899-2708a0e5fb18 function.
%% Embed FIS Data in Generated Code
% You can embed the data for your fuzzy inference system within the generated code. Use this option if you do not want to change the FIS data after compilation.
% First, create a fuzzy system, or load a fuzzy system from a .fis file. For this example, load the fuzzy system from tipper.fis.

fisObject = readfis("tipper.fis");

%
% To use this FIS for code generation, convert it to a homogeneous structure.

fis = getFISCodeGenerationData(fisObject);

% By default, getFISCodeGenerationData assumes that the FIS object is a type-1 system. To generate code for a type-2 system, you must indicate the system type using getFISCodeGenerationData(fisObject,"type2").
%
% Create a function for evaluating the fuzzy system fis for a given input vector x. Within this function, you can specify options for the evalfis function using evalfisOptions.
% function y = evaluatefis1(fis,x)
%     %#codegen
%     opt = evalfisOptions('NumSamplePoints',51);
%     y = evalfis(fis,x,opt);
% end
%
% Generate code for evaluatefis1, specifying that the fis input argument is constant. You can specify different targets for your build, such as a static library, an executable, or a MEX file. For this example, generate a MEX file.

codegen('evaluatefis1','-args',{coder.Constant(fis),[0 0]},'-config:mex')

%
% To verify the execution of the MEX file:
% Evaluate the MEX file for one or more input values. When you call the MEX file, specify the same FIS structure that you used at compile time.
% Evaluate the original FIS for the same input values using evalfis. When evaluating using evalfis, use the same homogeneous FIS structure.
% Compare the evaluation results.

mexOutput1 = evaluatefis1_mex(fis,[7 9])
opt = evalfisOptions('NumSamplePoints',51);
evalfisOutput = evalfis(fis,[7 9],opt)

% The MEX file output matches the evalfis output.
%
% Alternatively, you can embed the FIS data in the generated code by reading the FIS data from a file at code generation time. Specify a function for evaluating a fuzzy system for given input vector x. Within this function, read the FIS data from the file tipper.fis.
% function y = evaluatefis2(x)
%     %#codegen
%     fis = getFISCodeGenerationData('tipper.fis');
%     opt = evalfisOptions('NumSamplePoints',51);
%     y = evalfis(fis,x,opt);
% end
%
% Generate code for evaluatefis2.

codegen('evaluatefis2','-args',{[0 0]},'-config:mex')

%
% Verify the execution of the MEX file using the same input values for x. In this case, you do not have to specify the original FIS structure used at compile time.

mexOutput2 = evaluatefis2_mex([7 9])
evalfisOutput

%
%% Generate Code for Loading FIS Data at Run Time
% You can generate code for evaluating a FIS that is read from a .fis file specified at run time. In this case, the FIS data is not embedded in the generated code. Specify a function for evaluating the fuzzy system defined in the specified file fileName for a given input vector x.
% function y = evaluatefis3(fileName,x)
%     %#codegen
%     fis = getFISCodeGenerationData(fileName);
%     opt = evalfisOptions('NumSamplePoints',51);
%     y = evalfis(fis,x,opt);
% end
%
% Define input data types for this function.

fileName = coder.newtype('char',[1 Inf],[false true]);
x = coder.newtype('double',[1 Inf],[false true]);

%
% Generate code for evaluatefis3.

codegen('evaluatefis3','-args',{fileName,x},'-config:mex')

%
% Verify the execution of the MEX file using the same input values for x. In this case, you specify the name of the .fis file.

mexOutput3 = evaluatefis3_mex('tipper.fis',[7 9])
evalfisOutput

%
% Each time you run evaluatefis3, it reloads the fuzzy system from the file. For computational efficiency, you can create a function that only loads the FIS when a new file name is specified.
% function y = evaluatefis4(fileName,x)
%     %#codegen
%     %#internal
%
%     persistent fisName fis
%     if isempty(fisName)
%         [fisName,fis] = loadFIS(fileName);
%     elseif ~strcmp(fisName,fileName)
%         [fisName,fis] = loadFIS(fileName);
%     end
%
%     opt = evalfisOptions('NumSamplePoints',51);
%     y = evalfis(fis,x,opt);
% end
%
% function [fisName,fis] = loadFIS(fileName)
%     fisName = fileName;
%     fis = getFISCodeGenerationData(fisName);
% end
%
% Generate code evaluatefis4. The input data types for this function are the same as for evaluatefis3.

codegen('evaluatefis4','-args',{fileName,x},'-config:mex')

%
% Verify the execution of the MEX file using the same input values file name.

mexOutput4 = evaluatefis4_mex('tipper.fis',[7 9])
evalfisOutput

%
%% Generate Code for Single-Precision Data
% The preceding examples generated code for double-precision data. To generate code for single-precision data, specify the data type of the input values as single. For example, generate code for evaluatefis2 using single-precision data.

codegen('evaluatefis2','-args',{single([0 0])},'-config:mex')

%
% Verify the MEX file execution, passing in single-precision input values.

mexOutputSingle = evaluatefis2_mex(single([7 9]))
evalfisOutput

% Copyright 2018 The MathWorks, Inc.