Tag: .NET

  • Getting started with TypeScript in Visual Studio Code

    Some instructions that distill how one may get started with using TypeScript in Visual Studio Code.

    Step 1: Set up your development environment

    Download and run the installer for Visual Studio Code from the following link:

    https://code.visualstudio.com/download

    Step 2: Install node.js

    Download and run the installer for node.js from the following link:

    https://nodejs.org/

    Step 3: Install TypeScript

    Once node.js has been installed you can install TypeScript.

    Close VS Code if opened and open a command prompt and run the command:

    npm install -g typescript
    

    (Use the -g to ensure typescript is installed globally, not just for the folder you are in.)

    Step 4: Set up an example project

    Open VS Code.

    Create a new Terminal by selecting Terminal > New Terminal.

    Create a directory for your project using the mkdir command and navigate to that folder:

    Close the terminal and open the folder you just created by selecting File > Open Folder:

    Step 5: Create a new typescript.json file

    Run the command:

    tsc --init
    

    Alternatively you can create your own tsconfig.json file:

    {
        "compilerOptions": {
            "target": "es5",
            "module": "commonjs",
            "sourceMap": true
        }
    }
    

    Step 6: Create and transpile example helloworld.ts code:

    let message : string = "Hello World";
    console.log(message);
    

    Compile it using the terminal command:

    tsc helloworld.tsc
    

    This will generate the file helloworld.js:

    var message = "Hello World";
    console.log(message);
    

    Step 7: Make TypeScript automatically look for and transpile your changes

    Select Ctrl + Shift + B

    Select tsc:build:

    This will automatically trigger the transpilation of ts to js files each time the ts file is changed.

  • Applying the 2-opt algorithm to travelling salesman problems in C# / WPF

    For the Java equivalent see this link:

    https://www.technical-recipes.com/2017/applying-the-2-opt-algorithm-to-traveling-salesman-problems-in-java/

    For the C++ equivalent see this link:

    https://www.technical-recipes.com/2012/applying-c-implementations-of-2-opt-to-travelling-salesman-problems/

    This post demonstrates how to apply the 2-opt algorithm to a number of standard test problems in C# while displaying the
    results in a WPF style window, while using the MVVM design pattern.

    See this link for an overview of the two opt algorithm.

    http://en.wikipedia.org/wiki/2-opt

    But essentially the 2-opt link swapping heuristic can be summarised by the following steps:

    The actual 2-opt heuristic can be summarised by the following pseudocode steps, repeating for all feasible combinations of I and k:

    1. take route[1] to route[i-1] and add them in order to new_route
    2. take route[i] to route[k] and add them in reverse order to new_route
    3. take route[k+1] to end and add them in order to new_route       
    4. return the new_route;  
    

    Architecture

    This application is designed around the Model View ViewModel architecture (MVVM). I find that MVVM allows for a nice clean separation between the graphical
    display, the business logic and data handling.

    https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel

    As with the Java and C++ versions, the user interface is a simple window with buttons for opening the test problem (*.tsp file) and a run button to execute the algorithm(which causes the
    display to get updated and re-draw the tour links each time a better tour is found)

    Building the User Interface in XAML

    I use standard WPF / XAML for the user interface components and the canvas in which to draw the city nodes, tour links etc:

    MainWindow.xaml

    <Window x:Class="TwoOpt.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:twoOpt="clr-namespace:TwoOpt"
            mc:Ignorable="d"        
            Title="{Binding Title}" 
            Height="620" Width="600">
        
        <Window.DataContext>
            <twoOpt:MainWindowViewModel />
        </Window.DataContext>
            
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="70" />
                <RowDefinition Height="5" />
                <RowDefinition Height="*" />
                <RowDefinition Height="5" />
            </Grid.RowDefinitions>
            
            <StackPanel 
                Orientation="Horizontal">
                <Button 
                    Command="{Binding OpenCommand}"
                    Width="110" 
                    Content="Open" 
                    Margin="10" />
                
                <Button 
                    Width="110" 
                    Command="{Binding RunCommand}"
                    Content="Run" 
                    Margin="10"/>
                
                <Grid VerticalAlignment="Center" Width="200" Margin="10">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="25" />
                        <RowDefinition Height="25" />
                    </Grid.RowDefinitions>
                    
                    <Label 
                        VerticalContentAlignment="Center"
                        Name="BestLabel"
                        VerticalAlignment="Center"/>
                    
                    <Label 
                        VerticalContentAlignment="Center"
                        Name="IterationLabel"                    
                        Grid.Row="1" />
                </Grid>
            </StackPanel>
    
            <Grid               
                Grid.Row="2">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="10" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="10" />
                </Grid.ColumnDefinitions>
    
                <Grid.RowDefinitions>
                    <RowDefinition Height="5" />
                    <RowDefinition Height="*" />
                    <RowDefinition Height="5" />
                </Grid.RowDefinitions>
    
                <Grid Name="DisplayGrid" Grid.Column="1" Grid.Row="1">
                    <Canvas Name="CanvasGrid">
                    </Canvas>
                </Grid>
            </Grid>
        </Grid>
    </Window>
    

    The ViewModel class

    This class I use for handling the business logic and the responding to the button press events from the main user interface.

    MainWindowViewModel.cs

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Windows.Forms;
    using System.Windows.Input;
    
    namespace TwoOpt
    {
       public class MainWindowViewModel : BaseViewModel
       {
          private readonly Model _model;
          private ICommand _openCommand;
          private ICommand _runCommand;    
    
          public MainWindowViewModel()
          {
             _model = new Model();
             _model.TourUpdated += ModelOnTourUpdated;
          }
    
          public IMainWindow MainWindow { get; set; }
    
          public string Title
          {
             get { return _model.Title; }
             set
             {
                _model.Title = value;
                OnPropertyChanged("Title");
             }
          }
    
          public ICommand OpenCommand
          {
             get
             {
                return _openCommand ?? (_openCommand = new RelayCommand(
                          x =>
                          {
                             var openFileDialog1 = new OpenFileDialog
                             {
                                InitialDirectory = "c:\\",
                                Filter = @"txt files (*.tsp)|*.tsp|All files (*.*)|*.*",
                                FilterIndex = 2,
                                RestoreDirectory = true
                             };
    
                             if (openFileDialog1.ShowDialog() != DialogResult.OK) return;
    
                             try
                             {
                                Stream stream;
                                // ReSharper disable once ConditionIsAlwaysTrueOrFalse
                                if ((stream = openFileDialog1.OpenFile()) == null) return;
    
                                var height = MainWindow.GridHeight();
                                var width = MainWindow.GridWidth();
    
                                _model.CancelJobs();
                                _model.InitMatrix(stream, height, width);
                                Title = _model.Title;
                                DisplayNodes();
                                MainWindow.UpdateIteration(0, 0, null);
                             }
                             catch (Exception ex)
                             {
                                MessageBox.Show(@"Error: Could not read file from disk. Original error: " + ex.Message);
                             }
                          }));
             }
          }
    
          public ICommand RunCommand
          {
             get
             {
                return _runCommand ?? (_runCommand = new RelayCommand(
                          x => { _model.Run(); }));
             }
          }
    
          public List<Pair> Lines => _model.TourCoords;
    
          private void ModelOnTourUpdated(object sender, EventArgs<Tuple<double, int>> eventArgs)
          {
             var iter = eventArgs.Value.Item2;
             var best = eventArgs.Value.Item1;
    
             Update(best, iter);
          }
    
          public IEnumerable<string> ReadLines(Func<Stream> streamProvider,
             Encoding encoding)
          {
             using (var stream = streamProvider())
             {
                using (var reader = new StreamReader(stream, encoding))
                {
                   string line;
                   while ((line = reader.ReadLine()) != null)
                      yield return line;
                }
             }
          }
    
          private void DisplayNodes()
          {
             MainWindow?.PlotNodes(_model.DisplayCoords);
          }
    
          private void Update(double best, int iter)
          {
             MainWindow.UpdateIteration(best, iter, _model.TourCoords);
          }
       }
    }
    

    Within this code I also make use of the Supervisor Controlling Pattern as means of accessing the View controls from within the ViewModel class.

    It does this by allowing MainWindow.xaml.cs to inherits from the IMainWindow interface, which provide the functions to plot the nodes and draw the links:

    IMainWindow.cs

    using System.Collections.Generic;
    
    namespace TwoOpt
    {
       public interface IMainWindow
       {
          void UpdateIteration(double best, int iter, List<Pair> tourCoords);
          void PlotNodes(List<Pair> displayCoords);
      
          double GridHeight();
          double GridWidth();
       }
    }
    

    MainWindow.xaml.cs

    using System.Collections.Generic;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    
    namespace TwoOpt
    {
       /// <summary>
       ///    Interaction logic for MainWindow.xaml
       /// </summary>
       public partial class MainWindow : IMainWindow
       {
          public MainWindow()
          {
             InitializeComponent();
    
             var mainWindowViewModel = DataContext as MainWindowViewModel;
    
             if (mainWindowViewModel != null)
                mainWindowViewModel.MainWindow = this;
          }
    
          public void PlotNodes(List<Pair> displayCoords)
          {
             CanvasGrid.Children.Clear();
    
             InvalidateVisual();
    
             foreach (var coord in displayCoords)
             {
                var ellipse = new Ellipse
                {
                   Width = 4,
                   Height = 4,
                   Fill = Brushes.Blue
                };
    
                Canvas.SetLeft(ellipse, coord.X());
                Canvas.SetTop(ellipse, coord.Y());
    
                CanvasGrid.Children.Add(ellipse);
             }
          }    
    
          public double GridHeight()
          {
             return DisplayGrid.ActualHeight;
          }
    
          public double GridWidth()
          {
             return DisplayGrid.ActualWidth;
          }
    
          public void UpdateIteration(double best, int iter, List<Pair> tourCoords)
          {
             Dispatcher.Invoke(() =>
             {
                IterationLabel.Content = "Iteration: " + iter;
                BestLabel.Content = "Best distance: " + (int)best;
    
                if (tourCoords == null) return;          
    
                var size = tourCoords.Count;
                var startCoord = tourCoords[0];
                CanvasGrid.Children.Clear();
    
                for (var i = 1; i < size; ++i)
                {
                   var endCoord = tourCoords[i];
    
                   var link = new Line
                   {
                      X1 = startCoord.X() + 2,
                      Y1 = startCoord.Y() + 2,
                      X2 = endCoord.X() + 2,
                      Y2 = endCoord.Y() + 2,
    
                      Stroke = Brushes.Blue
                   };
    
                   CanvasGrid.Children.Add(link);
                   startCoord = tourCoords[i];
                }
    
                var finalLink = new Line
                {
                   X1 = tourCoords[0].X() + 2,
                   Y1 = tourCoords[0].Y() + 2,
                   X2 = tourCoords[size - 1].X() + 2,               
                   Y2 = tourCoords[size - 1].Y() + 2,
                   Stroke = Brushes.Blue
                };
    
                CanvasGrid.Children.Add(finalLink);
             });         
          }
       }
    }
    

    C# implementation of the 2-opt algorithm

    // Do all 2-opt combinations
          private void TwoOpt()
          {
             // Get tour size
             var size = _tour.TourSize();
    
             //CHECK THIS!!		
             for (var i = 0; i < size; i++)
             {
                _newTour.SetCity(i, _tour.GetCity(i));
             }
    
             // repeat until no improvement is made 
             var improve = 0;
             var iteration = 0;
    
             while (improve < 500)
             {
                var bestDistance = _tour.TourDistance();
    
                for (var i = 1; i < size - 1; i++)
                {
                   for (var k = i + 1; k < size; k++)
                   {
                      TwoOptSwap(i, k);
                      iteration++;
    
                      var newDistance = _newTour.TourDistance();
    
                      if (!(newDistance < bestDistance)) continue;
    
                      // Improvement found so reset
                      improve = 0;
    
                      for (var j = 0; j < size; j++)
                      {
                         _tour.SetCity(j, _newTour.GetCity(j));
                      }
    
                      bestDistance = newDistance;
    
                      // Update the display
                      SetTourCoords();
    
                      TourUpdated.Raise(this, new Tuple<double, int>( bestDistance, iteration));
                   }
                }
    
                improve++;
             }         
          }
    

    And this is how the swap is done:

    private void TwoOptSwap(int i, int k)
          {
             var size = _tour.TourSize();
    
             // 1. take route[0] to route[i-1] and add them in order to new_route
             for (var c = 0; c <= i - 1; ++c)
             {
                _newTour.SetCity(c, _tour.GetCity(c));
             }
    
             // 2. take route[i] to route[k] and add them in reverse order to new_route
             var dec = 0;
             for (var c = i; c <= k; ++c)
             {
                _newTour.SetCity(c, _tour.GetCity(k - dec));
                dec++;
             }
    
             // 3. take route[k+1] to end and add them in order to new_route
             for (var c = k + 1; c < size; ++c)
             {
                _newTour.SetCity(c, _tour.GetCity(c));
             }
          }
    

    Trying out the program

    Att48.tsp

    I tend to always start out on a reasonably small test problem such as att48.tsp, available from here:

    http://elib.zib.de/pub/mp-testdata/tsp/tsplib/tsp/att48.tsp

    Click the Open button and navigate to the Att48.tsp test problem when prompted, which plots the city locations as a series of nodes:

    Upon pressing Run, we obtain the solution of length 10959:

    kroA200.tsp

    I then try out the program on a larger problem with 200 nodes, “kroA200.tsp”, available from here:

    http://elib.zib.de/pub/mp-testdata/tsp/tsplib/tsp/kroA200.tsp

    Giving the following result:

    lin318.tsp

    Finally I try one more test problem, “lin318.tsp”, available from here:

    http://elib.zib.de/pub/mp-testdata/tsp/tsplib/tsp/lin318.tsp

    Results as shown:

    Full code sample in the form of a Visual Studio 2015 project is available from here:


  • How to run processes and obtain the output in C#

    Example process: fsutil.

    Very useful link on obtaining and setting fsutil behaviour and properties at this following link:

    http://blogs.microsoft.co.il/skepper/2014/07/16/symbolic_link/

    Typically contained in the System32 folder: C:\Windows\System32

    It is quite simple to do and consists of two main steps:

    Step 1: Create Process object and set its StartInfo object accordingly

    var process = new Process
    {
    	StartInfo = new ProcessStartInfo
    	{
    		FileName = "C:\\Windows\\System32\\fsutil.exe",
    		Arguments = "behavior query SymlinkEvaluation",
    		UseShellExecute = false, RedirectStandardOutput = true,
    		CreateNoWindow = true
    	}
    };
    

    Step 2: Start the process and read each line obtained from it:

    process.Start();
    
    while (!process.StandardOutput.EndOfStream)
    {
    	var line = process.StandardOutput.ReadLine();
    	Console.WriteLine(line);
    }
    

    Full Code listing:

    using System;
    using System.Diagnostics;
    
    namespace RunProcess
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                try
                {
                    var process = new Process
                    {
                        StartInfo = new ProcessStartInfo
                        {
                            FileName = "C:\\Windows\\System32\\fsutil.exe",
                            Arguments = "behavior query SymlinkEvaluation",
                            UseShellExecute = false, RedirectStandardOutput = true,
                            CreateNoWindow = true
                        }
                    };
    
                    process.Start();
    
                    while (!process.StandardOutput.EndOfStream)
                    {
                        var line = process.StandardOutput.ReadLine();
                        Console.WriteLine(line);
                    }
    
                    process.WaitForExit();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }
    

    For our example I wanted to see what the SymbolicLinkStatus was for remote -> local etc:

    Console output as follows:

    fsutil

  • Getting started with Spire.XLS for .NET

    E-iceblue Ltd. is a vendor of powerful components for .NET, Silverlight and WPF development. These products enable the user to easily read and write different formats of office files.

    A quick an easy guide to setting up Spire.XLS for use in Visual Studio .NET projects is presented here.

    For the purpose of clarity and helping the user get started as soon as possible, a simple ‘HelloWorld’ example is presented.
    (more…)

  • Mixing Managed and Native Types in C++ / CLI

    Brief Introduction

    C++/CLI (Common Language Infrastructure) was designed to bring C++ to .NET as a means of developing managed code applications. Specifically it helps simplify writing managed code when using C++.

    Suppose you are writing a WinForms application in Microsoft Visual Studio with a view to using C++ to write managed code. You may prefer to reuse existing libraries and headers written in C and C++ but are a little unsure as to how this is achieved exactly.
    (more…)

  • Implementing Kruskal’s Algorithm in C#

    This post is essentially a blatant lifting of Omar Gamil’s CodeProject article on the same subject. I have been using the project as means of getting into C# programming and using things like Windows Forms etc in Visual Studio environments for the first time. (more…)