1
2 /* ----------------------------------------------------------------------
3 * Project: CMSIS DSP Library
4 * Title: arm_braycurtis_distance_f32.c
5 * Description: Bray-Curtis distance between two vectors
6 *
7 *
8 * Target Processor: Cortex-M cores
9 * -------------------------------------------------------------------- */
10 /*
11 * Copyright (C) 2010-2019 ARM Limited or its affiliates. All rights reserved.
12 *
13 * SPDX-License-Identifier: Apache-2.0
14 *
15 * Licensed under the Apache License, Version 2.0 (the License); you may
16 * not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 * www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
23 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 */
27
28 #include "arm_math.h"
29 #include <limits.h>
30 #include <math.h>
31
32
33
34 /**
35 * @ingroup groupDistance
36 * @{
37 */
38
39 /**
40 * @defgroup FloatDist Float Distances
41 *
42 * Distances between two vectors of float values.
43 */
44
45 /**
46 @addtogroup FloatDist
47 @{
48 */
49
50
51 /**
52 * @brief Bray-Curtis distance between two vectors
53 * @param[in] pA First vector
54 * @param[in] pB Second vector
55 * @param[in] blockSize vector length
56 * @return distance
57 *
58 */
59 #if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)
60
61 #include "arm_helium_utils.h"
62
arm_braycurtis_distance_f32(const float32_t * pA,const float32_t * pB,uint32_t blockSize)63 float32_t arm_braycurtis_distance_f32(const float32_t *pA,const float32_t *pB, uint32_t blockSize)
64 {
65 float32_t accumDiff = 0.0f, accumSum = 0.0f;
66 uint32_t blkCnt;
67 f32x4_t a, b, c, accumDiffV, accumSumV;
68
69
70 accumDiffV = vdupq_n_f32(0.0f);
71 accumSumV = vdupq_n_f32(0.0f);
72
73 blkCnt = blockSize >> 2;
74 while (blkCnt > 0) {
75 a = vld1q(pA);
76 b = vld1q(pB);
77
78 c = vabdq(a, b);
79 accumDiffV = vaddq(accumDiffV, c);
80
81 c = vaddq_f32(a, b);
82 c = vabsq_f32(c);
83 accumSumV = vaddq(accumSumV, c);
84
85 pA += 4;
86 pB += 4;
87 blkCnt--;
88 }
89
90 blkCnt = blockSize & 3;
91 if (blkCnt > 0U) {
92 mve_pred16_t p0 = vctp32q(blkCnt);
93
94 a = vldrwq_z_f32(pA, p0);
95 b = vldrwq_z_f32(pB, p0);
96
97 c = vabdq(a, b);
98 accumDiffV = vaddq_m(accumDiffV, accumDiffV, c, p0);
99
100 c = vaddq_f32(a, b);
101 c = vabsq_f32(c);
102 accumSumV = vaddq_m(accumSumV, accumSumV, c, p0);
103 }
104
105 accumDiff = vecAddAcrossF32Mve(accumDiffV);
106 accumSum = vecAddAcrossF32Mve(accumSumV);
107
108 /*
109 It is assumed that accumSum is not zero. Since it is the sum of several absolute
110 values it would imply that all of them are zero. It is very unlikely for long vectors.
111 */
112 return (accumDiff / accumSum);
113 }
114 #else
115 #if defined(ARM_MATH_NEON)
116
117 #include "NEMath.h"
118
arm_braycurtis_distance_f32(const float32_t * pA,const float32_t * pB,uint32_t blockSize)119 float32_t arm_braycurtis_distance_f32(const float32_t *pA,const float32_t *pB, uint32_t blockSize)
120 {
121 float32_t accumDiff=0.0f, accumSum=0.0f;
122 uint32_t blkCnt;
123 float32x4_t a,b,c,accumDiffV, accumSumV;
124 float32x2_t accumV2;
125
126 accumDiffV = vdupq_n_f32(0.0f);
127 accumSumV = vdupq_n_f32(0.0f);
128
129 blkCnt = blockSize >> 2;
130 while(blkCnt > 0)
131 {
132 a = vld1q_f32(pA);
133 b = vld1q_f32(pB);
134
135 c = vabdq_f32(a,b);
136 accumDiffV = vaddq_f32(accumDiffV,c);
137
138 c = vaddq_f32(a,b);
139 c = vabsq_f32(c);
140 accumSumV = vaddq_f32(accumSumV,c);
141
142 pA += 4;
143 pB += 4;
144 blkCnt --;
145 }
146 accumV2 = vpadd_f32(vget_low_f32(accumDiffV),vget_high_f32(accumDiffV));
147 accumDiff = vget_lane_f32(accumV2, 0) + vget_lane_f32(accumV2, 1);
148
149 accumV2 = vpadd_f32(vget_low_f32(accumSumV),vget_high_f32(accumSumV));
150 accumSum = vget_lane_f32(accumV2, 0) + vget_lane_f32(accumV2, 1);
151
152 blkCnt = blockSize & 3;
153 while(blkCnt > 0)
154 {
155 accumDiff += fabsf(*pA - *pB);
156 accumSum += fabsf(*pA++ + *pB++);
157 blkCnt --;
158 }
159 /*
160
161 It is assumed that accumSum is not zero. Since it is the sum of several absolute
162 values it would imply that all of them are zero. It is very unlikely for long vectors.
163
164 */
165 return(accumDiff / accumSum);
166 }
167
168 #else
arm_braycurtis_distance_f32(const float32_t * pA,const float32_t * pB,uint32_t blockSize)169 float32_t arm_braycurtis_distance_f32(const float32_t *pA,const float32_t *pB, uint32_t blockSize)
170 {
171 float32_t accumDiff=0.0f, accumSum=0.0f, tmpA, tmpB;
172
173 while(blockSize > 0)
174 {
175 tmpA = *pA++;
176 tmpB = *pB++;
177 accumDiff += fabsf(tmpA - tmpB);
178 accumSum += fabsf(tmpA + tmpB);
179 blockSize --;
180 }
181 /*
182
183 It is assumed that accumSum is not zero. Since it is the sum of several absolute
184 values it would imply that all of them are zero. It is very unlikely for long vectors.
185
186 */
187 return(accumDiff / accumSum);
188 }
189 #endif
190 #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */
191
192
193 /**
194 * @} end of FloatDist group
195 */
196
197 /**
198 * @} end of groupDistance group
199 */
200