fiaccel set fi numeric type based on input

5 views (last 30 days)
I have stumble across an issue that doesnt allow "flexible" coding, and I am trying to find ways to work around it. I got the following script as example example_fi.m.
function [outputArg1] = example_fi(M)
U2_0 = numerictype(0, 2, 0);
U3_0 = numerictype(0, 3, 0);
U4_0 = numerictype(0, 4, 0);
if M == 2
outputArg1 = fi(0, U2_0, 'RoundingMethod', 'Floor', 'OverflowAction', 'Saturate');
elseif M == 3
outputArg1 = fi(0, U3_0, 'RoundingMethod', 'Floor', 'OverflowAction', 'Saturate');
else
outputArg1 = fi(0, U4_0, 'RoundingMethod', 'Floor', 'OverflowAction', 'Saturate');
end
end
Trying to convert it to a mex using following,
fiaccel example_fi -args {coder.typeof(0, 1,1)} -o example_fi_mex
I get this error: ??? Type mismatch: embedded.fi {ufix2} ~= embedded.fi {ufix3}.
It looks like fiaccel doesnt like initialise the same variable under different numeric types. I also tried using switch instead of if, but I get the same error.
Is there a way to work around this or simply always intialise with the highest numeric type?

Accepted Answer

Andy Bartlett
Andy Bartlett on 8 Nov 2022
Edited: Andy Bartlett on 8 Nov 2022
When using MATLAB Code with MATLAB Coder, MATLAB Function Block, or fiaccel, the numeric type of a variable is not allowed to change under any circumstance.
Your code sets variable outputArg1 to 3 distinct numeric types which is not allowed in code generation.
However, an error can be avoided if MATLAB Coder can analyze the code and the codegen arguments and from that determine that only 1 of the three distinct type assignments is reachable.
To determine that a path is unreachable, MATLAB Coder must be able to determine that control flow variables are constant.
There are two common techniques to getting MATLAB Coder to understand that a variable is constant.
Use coder.Constant
One way is to use coder.Constant on input arguments.
fiaccel example_fi -args {coder.Constant(2)}
This will allow fiaccel to succeed, but the type of outputArg1 is always the same in the generated mex.
example_fi_mex(2)
ans =
0
numerictype(0,2,0)
RoundingMethod: Floor
OverflowAction: Saturate
ProductMode: FullPrecision
SumMode: FullPrecision
Use constant variable properties for control flow
The other mechanism is to extract a property from a variable that will be constant at code generation time. The numeric type of a variable is property that as previously mentioned is constant in a (successful) code generation situation. For example.
function [outputArg1] = example_fi_two(M)
U2_0 = numerictype(0, 2, 0);
U3_0 = numerictype(0, 3, 0);
U4_0 = numerictype(0, 4, 0);
if strcmp(class(M),'double')
outputArg1 = fi(0, U2_0, 'RoundingMethod', 'Floor', 'OverflowAction', 'Saturate');
else
ntM = fixed.extractNumericType(M);
if ntM.WordLength >= 17
outputArg1 = fi(0, U3_0, 'RoundingMethod', 'Floor', 'OverflowAction', 'Saturate');
else
outputArg1 = fi(0, U4_0, 'RoundingMethod', 'Floor', 'OverflowAction', 'Saturate');
end
end
This will support fiaccel even if the variable M is not constant.
fiaccel example_fi_two -args {fi(pi,1,10,7)}
example_fi_two_mex(fi(3,1,10,7))
ans =
0
numerictype(0,4,0)
RoundingMethod: Floor
OverflowAction: Saturate
ProductMode: FullPrecision
SumMode: FullPrecision
Use multiple variables and cast to common output
Another approach is to redesign your algorithm to use separately named variables for each of the types you want to support. But you will need to cast those to some common type if you want to pass that to the output.
This function shows the general concept. And makes use of the very helpful cast-like concept.
function y = sneaky_pair_of_casts(toggle,a,b,c)
% Force final output to a common type.
% The value assigned here does not matter. It will be overwritten.
%
% Such as to single
% y = zeros(size(a),'single');
%
% Or use fi's default full-precision sum behavior
% to get a type more than big enough to hold a's type
% and b's type
%
y = repmat( b(1) + c(1), size(a) );
if toggle
a_cast_to_b_type = cast(a,'like',b);
%
% assign to y with colon trick to avoid type change
%
y(:) = a_cast_to_b_type;
else
a_cast_to_c_type = cast(a,'like',c);
%
% assign to y with colon trick to avoid type change
%
y(:) = a_cast_to_c_type;
end
end
This supports fiaccel and code generation.
fiaccel sneaky_pair_of_casts -args {true, rand(5,1), fi(pi,1,11,6), fi(pi,0,5,2) }
And will internally cast to either of two types depending on the value of the frist input argument toggle.
u = [
0.70604608801960878
0.031832846377420676
0.27692298496088996
0.046171390631153941
0.097131781235847536
];
sneaky_pair_of_casts_mex(true, u, fi(pi,1,11,6), fi(pi,0,5,2) )
ans =
0.703125
0.03125
0.28125
0.046875
0.09375
numerictype(1,13,6)
sneaky_pair_of_casts_mex(false, u, fi(pi,1,11,6), fi(pi,0,5,2) )
ans =
0.75
0
0.25
0
0
numerictype(1,13,6)

More Answers (0)

Tags

Products


Release

R2020a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!