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