• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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