Add project 1 with the corresponding source code and report.
This commit is contained in:
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
echo "Cleaning up old results..."
|
||||
rm -f poisson_solution.csv numerical_solution_*.csv rel_errors.txt timing_results_100_iterations.csv
|
||||
rm -f poisson_solver poisson_timing poisson
|
||||
rm -f ../../projects/project1/include/*.pdf
|
||||
|
||||
echo "Compiling the C++ code..."
|
||||
g++ -o poisson_solver poisson_solver.cpp src/*
|
||||
g++ -o poisson_timing poisson_timing.cpp src/*
|
||||
g++ -o poisson poisson.cpp
|
||||
echo "Compilation finished."
|
||||
|
||||
echo "Generating reference solution..."
|
||||
./poisson
|
||||
uv run python/poisson_plotter.py --filename "poisson_solution.csv"
|
||||
|
||||
for power in 1 2 3 4 5 6 7; do
|
||||
N=$((10 ** power))
|
||||
if [ $power -lt 5 ]; then
|
||||
output_to_file=true
|
||||
else
|
||||
output_to_file=false
|
||||
fi
|
||||
echo "Running simulation for N=$N (output: $output_to_file)"
|
||||
./poisson_solver $N $output_to_file | tee >(awk '
|
||||
/Running Poisson solver/ { N=$7 }
|
||||
/Max relative error/ { print N"&"$4"\\\\" >> "rel_errors.txt" }
|
||||
')
|
||||
if [ "$output_to_file" = true ]; then
|
||||
uv run python/poisson_plotter.py --filename "numerical_solution_$N.csv"
|
||||
uv run python/poisson_plotter.py --filename "numerical_solution_$N.csv" --reference "poisson_solution.csv"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Creating Summary Plot..."
|
||||
uv run python/poisson_plotter.py --reference "poisson_solution.csv" --filename "numerical_solution_*.csv"
|
||||
|
||||
echo "Timing the algorithm variations..."
|
||||
./poisson_timing
|
||||
uv run python/timing_plotter.py "timing_results_100_iterations.csv"
|
||||
|
||||
echo "All done!"
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
double f(double x);
|
||||
std::vector<double> get_g(const std::vector<double>& x);
|
||||
std::vector<double> get_x(int N);
|
||||
std::vector<double> analytical_solution(const std::vector<double>& x);
|
||||
double relative_error(const std::vector<double>& v, const std::vector<double>& u);
|
||||
void debug_print(const std::vector<double>& v, const std::string& name);
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <vector>
|
||||
|
||||
std::vector<double> general_algorithm(const std::vector<double>& a, const std::vector<double>& b, const std::vector<double>& c, const std::vector<double>& g);
|
||||
std::vector<double> special_algorithm(const std::vector<double>& g);
|
||||
std::vector<double> optimal_algorithm_opt(const std::vector<double>& g);
|
||||
std::vector<double> add_boundaries(const std::vector<double>& v);
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(){
|
||||
const double dx = 1.0/1000000;
|
||||
const double xmin = 0;
|
||||
const double xmax = 1;
|
||||
const int decimals = 14;
|
||||
|
||||
string output_file = "poisson_solution.csv";
|
||||
ofstream ofs(output_file);
|
||||
ofs << "x,u(x)\n";
|
||||
|
||||
for(double x = xmin; x <= xmax; x += dx){
|
||||
double u = 1 - (1 - exp(-10))*x - exp(-10*x);
|
||||
ofs << fixed << setprecision(decimals) << x << "," << u << "\n";
|
||||
}
|
||||
ofs.close();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
#include "include/solvers.hpp"
|
||||
#include "include/helpers.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[]){
|
||||
const int decimal_places = 14;
|
||||
int N; // !! Number of steps between the discretization points (= N_points - 1)
|
||||
if (argc > 1) { // Get number of steps from command line argument
|
||||
N = atoi(argv[1]);
|
||||
} else {
|
||||
N = 1000;
|
||||
}
|
||||
|
||||
bool output_to_file = true;
|
||||
if (argc > 2) { // Get output preference from command line argument (use "true" or "false", default is true)
|
||||
output_to_file = (strcmp(argv[2], "true") == 0);
|
||||
}
|
||||
|
||||
const double delta_x = 1.0 / N;
|
||||
vector<double> a(N-1, -1.0);
|
||||
vector<double> b(N-1, 2.0);
|
||||
vector<double> c(N-1, -1.0);
|
||||
vector<double> g(N-1, 0.0);
|
||||
|
||||
cout << "Running Poisson solver with N = " << N << endl;
|
||||
for (int i = 1; i < N; i++) {
|
||||
double x = i * delta_x;
|
||||
g[i-1] = delta_x * delta_x * f(x);
|
||||
}
|
||||
|
||||
vector<double> solution = add_boundaries(general_algorithm(a, b, c, g));
|
||||
vector<double> x = get_x(N);
|
||||
vector<double> u = analytical_solution(x);
|
||||
double max_rel_error = relative_error(solution, u);
|
||||
cout << "Max relative error: " << max_rel_error << endl;
|
||||
|
||||
if (output_to_file) {
|
||||
// Output the solution
|
||||
string filename = "numerical_solution_" + to_string(N) + ".csv";
|
||||
ofstream ofs(filename);
|
||||
ofs << "x,u(x)" << endl;
|
||||
for (int i = 0; i <= N; i++) {
|
||||
ofs << fixed << setprecision(decimal_places) << scientific << x[i] << "," << solution[i] << endl;
|
||||
}
|
||||
ofs.close();
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "include/helpers.hpp"
|
||||
#include "include/solvers.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
vector<double> appl_general_algorithm(const vector<double>& g){
|
||||
int N = g.size() + 1;
|
||||
vector<double> a(N-1, -1.0);
|
||||
vector<double> b(N-1, 2.0);
|
||||
vector<double> c(N-1, -1.0);
|
||||
return general_algorithm(a, b, c, g);
|
||||
}
|
||||
|
||||
double time_function(const vector<double>& g, vector<double> (*func)(const vector<double>&), const int n_iter=100){
|
||||
auto start = chrono::high_resolution_clock::now();
|
||||
for(int i = 0; i < n_iter; i++){
|
||||
func(g);
|
||||
}
|
||||
auto end = chrono::high_resolution_clock::now();
|
||||
chrono::duration<double> elapsed = end - start;
|
||||
return elapsed.count() / n_iter;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int n_iter = 100;
|
||||
if (argc > 1) { // Get number of iterations from command line argument
|
||||
n_iter = atoi(argv[1]);
|
||||
}
|
||||
|
||||
int N = 1000;
|
||||
vector<double> g = get_g(get_x(N));
|
||||
cout << "Relative error between solvers: " << relative_error(special_algorithm(g), appl_general_algorithm(g)) << endl;
|
||||
cout << "Relative error between solvers (optimized): " << relative_error(optimal_algorithm_opt(g), appl_general_algorithm(g)) << endl;
|
||||
|
||||
string filename = "timing_results_" + to_string(n_iter) + "_iterations.csv";
|
||||
ofstream outfile(filename);
|
||||
outfile << "N,Time (Special),Time (Optimized),Time (General)\n";
|
||||
for(int power = 1; power <= 6; power++){
|
||||
N = pow(10, power);
|
||||
g = get_g(get_x(N));
|
||||
double time_optimal = time_function(g, special_algorithm, n_iter);
|
||||
double time_optimal_opt = time_function(g, optimal_algorithm_opt, n_iter);
|
||||
double time_general = time_function(g, appl_general_algorithm, n_iter);
|
||||
cout << "Average time for specialized algorithm over " << N << " values: " << time_optimal << " seconds" << endl;
|
||||
cout << "Average time for optimized algorithm over " << N << " values: " << time_optimal_opt << " seconds" << endl;
|
||||
cout << "Average time for general algorithm over " << N << " values: " << time_general << " seconds" << endl;
|
||||
|
||||
outfile << N << "," << scientific << setprecision(10) << time_optimal << "," << time_optimal_opt << "," << time_general << endl;
|
||||
}
|
||||
outfile.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
from importlib.resources import files
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import argparse
|
||||
import os
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--filename", type=str, default="src/project1/poisson_solution.csv")
|
||||
parser.add_argument("--reference", type=str, default=None)
|
||||
args = parser.parse_args()
|
||||
|
||||
FILENAME = args.filename
|
||||
REFERENCE = args.reference
|
||||
|
||||
def singular_plot():
|
||||
df = pd.read_csv(FILENAME)
|
||||
fig, ax = plt.subplots(figsize=(6,3))
|
||||
ax.plot(df["x"], df["u(x)"])
|
||||
ax.set_xlabel(r"$x$")
|
||||
ax.set_ylabel(r"$u(x)$")
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
output_directory = os.path.abspath(os.path.join(__file__, "../../../../projects/project1/include"))
|
||||
output_file = os.path.basename(FILENAME).replace(".csv", ".pdf")
|
||||
fig.savefig(os.path.join(output_directory, output_file))
|
||||
|
||||
def reference_plot():
|
||||
df = pd.read_csv(FILENAME).sort_values("x")
|
||||
df_ref = pd.read_csv(REFERENCE).sort_values("x")
|
||||
|
||||
fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True, height_ratios=[3, 1], figsize=(4, 8))
|
||||
ax1.plot(df["x"], df["u(x)"], label="Numerical Solution")
|
||||
ax1.plot(df_ref["x"], df_ref["u(x)"], label="Reference Solution", linestyle="--")
|
||||
ax1.set_xlabel(r"$x$")
|
||||
ax1.set_ylabel(r"$u(x)$")
|
||||
ax1.legend()
|
||||
|
||||
combined_df = pd.merge_asof(df, df_ref, on="x", suffixes=("_num", "_ref"))
|
||||
ratio = (combined_df["u(x)_num"] - combined_df["u(x)_ref"]) / combined_df["u(x)_ref"]
|
||||
|
||||
ax2.plot(combined_df["x"], ratio.abs())
|
||||
ax2.set_xlabel(r"$x$")
|
||||
ax2.set_ylabel(r"$|\frac{u(x)_{num} - u(x)_{ref}}{u(x)_{ref}}|$")
|
||||
ax2.axhline(y=1, color="gray", linestyle="--")
|
||||
ax2.set_yscale("log")
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
output_directory = os.path.abspath(os.path.join(__file__, "../../../../projects/project1/include"))
|
||||
output_file = os.path.basename(FILENAME).replace(".csv", "_ref.pdf")
|
||||
fig.savefig(os.path.join(output_directory, output_file))
|
||||
|
||||
def multiple_reference_plot():
|
||||
# Filename is wildcard -> Find files
|
||||
import glob
|
||||
files = glob.glob(FILENAME)
|
||||
files.sort()
|
||||
fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True, height_ratios=[3, 1], figsize=(6,5))
|
||||
df_ref = pd.read_csv(REFERENCE).sort_values("x")
|
||||
|
||||
|
||||
for file in files:
|
||||
df = pd.read_csv(file).sort_values("x")
|
||||
label = f"Num. (N = {os.path.basename(file).replace(".csv", "").split("_")[-1]})"
|
||||
ax1.plot(df["x"], df["u(x)"], label=label)
|
||||
|
||||
combined_df = pd.merge_asof(df, df_ref, on="x", suffixes=("_num", "_ref"))
|
||||
ratio = (combined_df["u(x)_num"] - combined_df["u(x)_ref"]) / combined_df["u(x)_ref"]
|
||||
ax2.plot(combined_df["x"], ratio.abs(), label=label)
|
||||
|
||||
ax1.plot(df_ref["x"], df_ref["u(x)"], label="Reference Solution", linestyle="--", color="gray")
|
||||
ax1.set_xlabel(r"$x$")
|
||||
ax1.set_ylabel(r"$u(x)$")
|
||||
ax1.legend()
|
||||
ax2.axhline(y=1, color="gray", linestyle="--")
|
||||
ax2.set_xlabel(r"$x$")
|
||||
ax2.set_ylabel(r"$|\frac{u(x)_{num} - u(x)_{ref}}{u(x)_{ref}}|$")
|
||||
ax2.set_yscale("log")
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
output_directory = os.path.abspath(os.path.join(__file__, "../../../../projects/project1/include"))
|
||||
output_file = "big_ref_plot.pdf"
|
||||
fig.savefig(os.path.join(output_directory, output_file))
|
||||
|
||||
|
||||
def error_plots():
|
||||
abs_error_plot()
|
||||
rel_error_plot()
|
||||
|
||||
|
||||
def abs_error_plot():
|
||||
import glob
|
||||
files = glob.glob(FILENAME)
|
||||
files.sort()
|
||||
|
||||
df_ref = pd.read_csv(REFERENCE).sort_values("x")
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6,3))
|
||||
for file in files:
|
||||
df = pd.read_csv(file).sort_values("x")
|
||||
combined_df = pd.merge_asof(df, df_ref, on="x", suffixes=("_num", "_ref"))
|
||||
log_abs_err = np.log10((combined_df["u(x)_num"] - combined_df["u(x)_ref"]).abs())
|
||||
ax.plot(combined_df["x"], log_abs_err, label=f"N={os.path.basename(file).replace('.csv','').split('_')[-1]}")
|
||||
|
||||
ax.set_xlabel(r"$x$")
|
||||
ax.set_ylabel(r"$\log_{10}(|u(x)_{num} - u(x)_{ref}|)$")
|
||||
ax.legend()
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
output_directory = os.path.abspath(os.path.join(__file__, "../../../../projects/project1/include"))
|
||||
output_file = "abs_error_plot.pdf"
|
||||
fig.savefig(os.path.join(output_directory, output_file))
|
||||
|
||||
|
||||
def rel_error_plot():
|
||||
import glob
|
||||
files = glob.glob(FILENAME)
|
||||
files.sort()
|
||||
|
||||
df_ref = pd.read_csv(REFERENCE).sort_values("x")
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6,3))
|
||||
for file in files:
|
||||
df = pd.read_csv(file).sort_values("x")
|
||||
combined_df = pd.merge_asof(df, df_ref, on="x", suffixes=("_num", "_ref"))
|
||||
# Drop rows where u(x)_ref is zero
|
||||
combined_df = combined_df[combined_df["u(x)_ref"].abs() > 1e-10]
|
||||
log_rel_err = np.log10((combined_df["u(x)_num"] - combined_df["u(x)_ref"]).abs() / combined_df["u(x)_ref"].abs())
|
||||
ax.plot(combined_df["x"], log_rel_err, label=f"N={os.path.basename(file).replace('.csv','').split('_')[-1]}")
|
||||
|
||||
ax.set_xlabel(r"$x$")
|
||||
ax.set_ylabel(r"$\log_{10}(|\frac{u(x)_{num} - u(x)_{ref}}{u(x)_{ref}}|)$")
|
||||
ax.legend()
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
output_directory = os.path.abspath(os.path.join(__file__, "../../../../projects/project1/include"))
|
||||
output_file = "rel_error_plot.pdf"
|
||||
fig.savefig(os.path.join(output_directory, output_file))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if REFERENCE:
|
||||
if "*" in FILENAME:
|
||||
multiple_reference_plot()
|
||||
abs_error_plot()
|
||||
rel_error_plot()
|
||||
else:
|
||||
reference_plot()
|
||||
else:
|
||||
singular_plot()
|
||||
@@ -0,0 +1,30 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
import argparse
|
||||
import os
|
||||
|
||||
parser = argparse.ArgumentParser(description="Plot timing results from CSV file.")
|
||||
parser.add_argument("csv_file", help="Path to the CSV file containing timing results.")
|
||||
args = parser.parse_args()
|
||||
|
||||
df = pd.read_csv(args.csv_file)
|
||||
for column in df.columns[1:]:
|
||||
df[column] = df[column] / df["N"] # Normalize by N
|
||||
|
||||
fig, ax = plt.subplots(figsize=(6,3))
|
||||
x = np.arange(len(df))
|
||||
bar_width = 0.2
|
||||
for i, column in enumerate(df.columns[1:]):
|
||||
ax.bar(x + i * bar_width, df[column], width=bar_width, label=column)
|
||||
ax.set_xticks(x + bar_width / 2)
|
||||
ax.set_xticklabels(df["N"])
|
||||
ax.set_xlabel("N (number of values)")
|
||||
ax.set_ylabel("Time (seconds) per N")
|
||||
ax.legend(ncol=3)
|
||||
|
||||
fig.tight_layout()
|
||||
|
||||
output_directory = os.path.abspath(os.path.join(__file__, "../../../../projects/project1/include"))
|
||||
output_file = os.path.basename(args.csv_file).replace(".csv", ".pdf")
|
||||
fig.savefig(os.path.join(output_directory, output_file))
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "../include/helpers.hpp"
|
||||
|
||||
double f(double x){
|
||||
return 100*exp(-10*x);
|
||||
}
|
||||
|
||||
std::vector<double> get_x(int N){
|
||||
std::vector<double> x;
|
||||
for (int i = 0; i <= N; i++) {
|
||||
x.push_back(i * (1.0 / N));
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
std::vector<double> get_g(const std::vector<double>& x){
|
||||
std::vector<double> g;
|
||||
double delta_x = x[1] - x[0];
|
||||
for (int i = 1; i < x.size() - 1; i++) {
|
||||
double x_i = x[i];
|
||||
g.push_back(delta_x * delta_x * f(x_i));
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
std::vector<double> analytical_solution(const std::vector<double>& x){
|
||||
std::vector<double> u;
|
||||
for(int i = 0; i < x.size(); i++){
|
||||
double x_i = x.at(i);
|
||||
double u_i = 1.0 - (1.0 - exp(-10.0))*x_i - exp(-10.0*x_i);
|
||||
u.push_back(u_i);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
double relative_error(const std::vector<double>& v, const std::vector<double>& u){
|
||||
if (v.size() != u.size()) {
|
||||
std::cerr << "Error: Vectors must be of the same size." << std::endl << "Found sizes: " << v.size() << " and " << u.size() << std::endl;
|
||||
return -1.0;
|
||||
}
|
||||
const double eps = 1e-14;
|
||||
double max_rel_error = 0.0;
|
||||
for(int i = 0; i < v.size(); i++){
|
||||
if (fabs(u[i]) > eps) { // Avoid division by zero
|
||||
double rel_error = fabs((v[i] - u[i]) / u[i]);
|
||||
if (rel_error > max_rel_error) {
|
||||
max_rel_error = rel_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return max_rel_error;
|
||||
}
|
||||
|
||||
void debug_print(const std::vector<double>& v, const std::string& name){
|
||||
for (int i = 0; i < v.size(); i++){
|
||||
std::cout << name << "[" << i << "] = " << v[i] << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "../include/solvers.hpp"
|
||||
#include<iostream>
|
||||
|
||||
std::vector<double> general_algorithm(const std::vector<double>& a, const std::vector<double>& b, const std::vector<double>& c, const std::vector<double>& g) {
|
||||
int n = g.size();
|
||||
std::vector<double> c_prime(n-1, 0.0);
|
||||
std::vector<double> g_prime(n, 0.0);
|
||||
|
||||
// Forward elimination
|
||||
c_prime[0] = c[0] / b[0];
|
||||
for(int i = 1; i < n - 1; i++){
|
||||
c_prime[i] = c[i] / (b[i] - a[i] * c_prime[i - 1]);
|
||||
}
|
||||
g_prime[0] = g[0] / b[0];
|
||||
for (int i = 1; i < n; i++) {
|
||||
g_prime[i] = (g[i] - a[i] * g_prime[i - 1]) / (b[i] - a[i] * c_prime[i - 1]);
|
||||
}
|
||||
|
||||
// Back substitution
|
||||
std::vector<double> v(n, 0.0);
|
||||
v[n - 1] = g_prime[n - 1];
|
||||
for (int i = n - 2; i >= 0; i--) {
|
||||
v[i] = g_prime[i] - c_prime[i] * v[i + 1];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<double> special_algorithm(const std::vector<double>& g){
|
||||
int n = g.size();
|
||||
std::vector<double> v(n, 0.0);
|
||||
std::vector<double> g_tilde(n, 0.0);
|
||||
|
||||
g_tilde[0] = g[0] / 2.0;
|
||||
for(int i = 1; i <= n - 1; i++){
|
||||
g_tilde[i] = (g[i] + g_tilde[i - 1]) * double(i + 1) / double(i + 2);
|
||||
}
|
||||
v[n - 1] = g_tilde[n - 1];
|
||||
for(int i = n - 2; i >= 0; i--){
|
||||
v[i] = g_tilde[i] + double(i + 1) / double(i + 2) * v[i + 1];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<double> optimal_algorithm_opt(const std::vector<double>& g) {
|
||||
// Trying to shave off the last few bits here and there
|
||||
|
||||
const int n = static_cast<int>(g.size());
|
||||
std::vector<double> v(n);
|
||||
|
||||
// Use g_tilde in-place (reuse v as workspace to save one allocation)
|
||||
double prev = g[0] * 0.5;
|
||||
v[0] = prev;
|
||||
|
||||
// Forward sweep
|
||||
for (int i = 1; i < n; i++) {
|
||||
const double factor = double(i + 1) / double(i + 2);
|
||||
prev = (g[i] + prev) * factor;
|
||||
v[i] = prev;
|
||||
}
|
||||
|
||||
// Backward sweep
|
||||
double next = v[n - 1];
|
||||
for (int i = n - 2; i >= 0; i--) {
|
||||
const double factor = double(i + 1) / double(i + 2);
|
||||
next = v[i] + factor * next;
|
||||
v[i] = next;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
std::vector<double> add_boundaries(const std::vector<double>& v){
|
||||
std::vector<double> v_ast;
|
||||
// Add 0.0 to the beginning and end
|
||||
v_ast.push_back(0.0);
|
||||
for (int i = 0; i < v.size(); i++){
|
||||
v_ast.push_back(v[i]);
|
||||
}
|
||||
v_ast.push_back(0.0);
|
||||
return v_ast;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user