Repository: xtensor-stack/xtensor (language: python)

Issue:
Fix linspace endpoint bug
# Checklist

- [x] The title and commit message(s) are descriptive.
- [x] Small commits made to fix your PR have been squashed to avoid history pollution.
- [x] Tests have been added for new features or bug fixes.
- [ ] API of new functions and classes are documented.

# Description

<!---
Give any relevant description here. 
If your PR fixes an issue, please include "Fixes #ISSUE" (substituting the relevant issue ID).
-->

Fix #2304


Discussion / hints:
@JohanMabille Could you please review it when you have time? Thank you! If there is a concern that this may affect the performance of `arange`, maybe we could separate the implementation of `arange` and `linspace` since `arange` does not need to deal with the endpoint issue.
I'm not sure this would really impact the performance of arange, so let's merge!

Fix patch:
diff --git a/include/xtensor/xbuilder.hpp b/include/xtensor/xbuilder.hpp
index 5658558b9..ee668282b 100644
--- a/include/xtensor/xbuilder.hpp
+++ b/include/xtensor/xbuilder.hpp
@@ -214,7 +214,7 @@ namespace xt
             {
                 buf[i] = static_cast<R>(start + step * mult_type(i));
             }
-            if (num > 0 && endpoint)
+            if (endpoint && num > 1)
             {
                 buf[num-1] = static_cast<R>(stop);
             }


Test patch:
diff --git a/test/test_xbuilder.cpp b/test/test_xbuilder.cpp
index d9e415eb1..0aa86cf16 100644
--- a/test/test_xbuilder.cpp
+++ b/test/test_xbuilder.cpp
@@ -246,7 +246,10 @@ namespace xt
         xt::xarray<double> c = linspace<double>(0., 2., 1, true);
         EXPECT_EQ(c.dimension(), size_t(1));
         EXPECT_EQ(c.shape(), expected_shape);
-        EXPECT_EQ(0., b(0));
+        EXPECT_EQ(0., c(0));
+
+        auto d = linspace<double>(0., 2., 1, true);
+        EXPECT_EQ(c, d);
     }
 
     TEST(xbuilder, linspace_n_samples_endpoint)
@@ -286,6 +289,15 @@ namespace xt
         ASSERT_TRUE(all(equal(ls, expected)));
     }
 
+    TEST(xbuilder, linspace_double)
+    {
+        // access_imp will also be tested here
+        double at_end = 99.78730976641236;
+        xt::xarray<double> a = xt::linspace(0., at_end, 100);
+        auto b = xt::linspace(0., at_end, 100);
+        EXPECT_EQ(a, b);
+    }
+
     TEST(xbuilder, logspace)
     {
         auto ls = logspace<double>(2., 3., 4);
@@ -690,13 +702,4 @@ namespace xt
         b = std::is_same<decltype(ed3), xarray<double>>::value;
         EXPECT_TRUE(b);
     }
-
-    TEST(xbuilder, linspace_double)
-    {
-        // access_imp will also be tested here
-        double at_end = 99.78730976641236;
-        xt::xarray<double> a = xt::linspace(0., at_end, 100);
-        auto b = xt::linspace(0., at_end, 100);
-        EXPECT_EQ(a, b);
-    }
 }