Skip to main content
The Angular PWA Demo includes machine learning capabilities with linear regression implementations in both TensorFlow (Python) and native C++.

Overview

Linear regression

Predict Apollo mission durations

TensorFlow

Python/TensorFlow backend

C++ ML

Native C++ least squares method

Visualization

Interactive Chart.js graphs

Linear regression

The application demonstrates linear regression with a real-world dataset: Apollo mission durations. Users can predict mission times based on historical data.

Apollo mission predictor

Predict the total mission time and duration for Apollo missions using two different ML approaches:
The predictor uses historical Apollo mission data (missions 8-17) to train a linear regression model and predict future mission durations.Historical data:
  • Apollo 8: 147 hours
  • Apollo 10: 193 hours
  • Apollo 11: 195 hours
  • Apollo 12: 244 hours
  • Apollo 13: 142 hours (aborted)
  • Apollo 14: 217 hours
  • Apollo 15: 295 hours
  • Apollo 16: 265 hours
  • Apollo 17: 301 hours

TensorFlow implementation

The Python/TensorFlow backend uses gradient descent for iterative optimization.

Service interface

Service
// src/app/_services/__AI/TensorflowService/tensor-flow.service.ts

export interface PredictionRequest {
  mission_number: number;
}

export interface PredictionResponse {
  input_mission_number: number;
  predicted_total_time_hours: number;
  predicted_duration_days: number;
}

@Injectable({
  providedIn: 'root'
})
export class TensorFlowService extends BaseService {
  constructor(private http: HttpClient, public _configService: ConfigService) {
    super();
  }
  
  predictTime_tensorflow_python(missionNumber: number): Observable<PredictionResponse> {
    let apiUrl_tensorflow_python = `${this.getConfigValue('baseUrlDjangoPythonTF')}predict/`;
    
    const body: PredictionRequest = { mission_number: missionNumber };
    const headers = new HttpHeaders({
      'Content-Type': 'application/json'
    });
    
    return this.http.post<PredictionResponse>(apiUrl_tensorflow_python, body, { headers });
  }
}

How it works

1

Data preparation

The backend receives mission number and prepares the input tensor.
2

Model training

TensorFlow trains a linear regression model using gradient descent on the historical Apollo mission data.
3

Prediction

The trained model predicts the mission duration based on the input mission number.
4

Response

Returns predicted hours and days in JSON format.
TensorFlow approach: Uses iterative optimization (gradient descent) to find an approximate solution. This approach is more flexible and can be extended to non-linear models.

C++ implementation

The C++ backend implements the least squares method for exact linear regression.

Service method

C++ Service
predictTime_netcore_cpp(missionNumber: number): Observable<PredictionResponse> {
  let apiUrl_netcore_cpp = `${this.getConfigValue('baseUrlNetCoreCPPEntry')}api/linearregression/predict?missionNumberToPredict=${missionNumber}`;
  
  const headers = new HttpHeaders({
    'Content-Type': 'application/json'
  });
  
  return this.http.get<PredictionResponse>(apiUrl_netcore_cpp, { headers });
}

Mathematical approach

The C++ implementation uses the least squares formula:
For linear regression y = mx + b:

m = (n∑xy - ∑x∑y) / (n∑x² - (∑x)²)
b = (∑y - m∑x) / n

Where:
- n = number of data points
- x = mission numbers
- y = mission durations
- m = slope
- b = y-intercept
C++ approach: Uses the closed-form least squares solution for exact computation. This is faster for simple linear models but less flexible than TensorFlow.

Chart visualization

The application uses Chart.js to visualize predictions alongside historical data.

Chart configuration

import { ChartData, ChartConfiguration, ChartType } from 'chart.js';
import { BaseChartDirective, NgChartsModule } from 'ng2-charts';

@ViewChild(BaseChartDirective) chart?: BaseChartDirective;

public chartType: ChartType = 'line';

public chartOptions: ChartConfiguration['options'] = {
  responsive: true,
  maintainAspectRatio: false,
  scales: {
    x: {
      title: {
        display: true,
        text: 'Mission Number'
      }
    },
    y: {
      title: {
        display: true,
        text: 'Total Mission Time (Hours)'
      }
    }
  },
  plugins: {
    title: {
      display: true,
      text: 'Apollo Mission Duration Prediction'
    }
  }
};

Initialization

Init
initializeChart(): void {
  const labels = this.historicalData.map(item => `Apollo ${item.mission}`);
  const actualTimes = this.historicalData.map(item => item.time);
  
  this.chartData.labels = labels;
  this.chartData.datasets[0].data = actualTimes; // Actual times dataset
  this.chartData.datasets[1].data = []; // Prediction dataset (empty initially)
  
  // Update chart if already rendered
  if (this.chart) {
    this.chart.update();
  }
}

Backend version information

The service can query version information from the backends:
Versions
// TensorFlow API version
_GetTensorFlowAPIVersion(): Observable<string> {
  let p_url = `${this._configService.getConfigValue('baseUrlNetCoreCPPEntry')}api/Tensorflow/GetAPIVersion`;
  return this.http.get<string>(p_url, this.HTTPOptions_Text);
}

// Application version
_GetTensorFlowAPPVersion(): Observable<string> {
  let p_url = `${this._configService.getConfigValue('baseUrlNetCoreCPPEntry')}api/Tensorflow/GetAPPVersion`;
  return this.http.get<string>(p_url, this.HTTPOptions_Text);
}

// C++ standard version
_TensorFlow_GetCPPSTDVersion(): Observable<string> {
  let p_url = `${this._configService.getConfigValue('baseUrlNetCoreCPPEntry')}api/Tensorflow/GetCPPSTDVersion`;
  return this.http.get<string>(p_url, this.HTTPOptions_Text);
}

Comparison: TensorFlow vs C++

Advantages:
  • Flexible and extensible to complex models
  • Built-in support for neural networks
  • Easy to add features (polynomial, multi-variable)
  • Great ecosystem and libraries
Disadvantages:
  • Slower for simple linear regression
  • Requires Python runtime and dependencies
  • Approximate solution (depends on convergence)
  • Higher memory usage
Best for:
  • Complex models
  • Non-linear relationships
  • Large datasets
  • Future ML expansion

Response format

Both backends return the same response structure:
Response
export interface PredictionResponse {
  input_mission_number: number;        // The mission number provided
  predicted_total_time_hours: number;  // Predicted time in hours
  predicted_duration_days: number;     // Predicted time in days
}

// Example response:
{
  "input_mission_number": 18,
  "predicted_total_time_hours": 305.42,
  "predicted_duration_days": 12.73
}

Machine learning workflow

Error handling

Error Handling
predict(): void {
  if (this.inputMissionNumber === null || this.inputMissionNumber < 1) {
    this.errorMessage = 'Please enter a valid mission number (1 or higher).';
    this.predictionResult = null;
    return;
  }
  
  this.errorMessage = null;
  this.isLoading = true;
  
  this.predictService.predictTime_netcore_cpp(this.inputMissionNumber).subscribe({
    next: (response) => {
      this.predictionResult = response;
      this.updateChart(response.input_mission_number, response.predicted_total_time_hours);
    },
    error: (error) => {
      console.error('API Error:', error);
      this.errorMessage = `Error calling API: ${error.message || 'Unknown error'}`;
      this.status_message.set(this.errorMessage);
      this.predictionResult = null;
    },
    complete: () => {
      this.isLoading = false;
    }
  });
}

Best practices

  • Use C++ for simple linear relationships with known patterns
  • Use TensorFlow when you need flexibility or plan to extend the model
  • Consider data size: TensorFlow scales better with large datasets
  • Evaluate latency requirements: C++ is faster for real-time predictions
  • Normalize input features for better TensorFlow convergence
  • Validate input ranges to prevent extrapolation errors
  • Handle missing data gracefully
  • Use appropriate precision (float vs double) based on requirements
  • Show both historical and predicted data clearly
  • Use different colors/shapes for actual vs predicted points
  • Include confidence intervals when available
  • Update charts reactively using Angular signals
  • Validate backend availability before requests
  • Show loading states during computation
  • Provide clear error messages to users
  • Implement fallback to alternative backend if one fails

Computer vision

Image processing and OCR

Algorithms

Algorithm visualizations

Charts

Chart generation and export

Build docs developers (and LLMs) love