Inaccurate GPS data using Arduino and GPS/GPRS Module - mysql

For a project I´m following this tutorial on how to track the location and output the GPS data using an Arduino with this SIM908 shield. The Arduino correctly sends the GPS data to the database. However, the coordinates are all exactly the same and it seems that they have been rounded off.
For example:
Latitude: 52.216667
Longitude: 5.483333
This isn't because of the PHP script, all it does is put the data it receives in the database. My guess is that it has something to do with the conversion function convert2Degrees.
This is the code we´re running on our Arduino:
int8_t answer;
int onModulePin= 2;
char data[100];
int data_size;
char aux_str[100];
char aux;
int x = 0;
char N_S,W_E;
char url[] = "informatica-corlaer.nl";
char frame[200];
char pin[]="0000";
char apn[]="mmm.nl";
char user_name[]="";
char password[]="";
char latitude[15];
char longitude[15];
char altitude[10];
char date[16];
char time[7];
char satellites[3];
char speedOTG[10];
char course[10];
void setup(){
pinMode(onModulePin, OUTPUT);
Serial.begin(115200);
Serial.println("Starting...");
power_on();
delay(3000);
//sets the PIN code
snprintf(aux_str, sizeof(aux_str), "AT+CPIN=%s", pin);
sendATcommand(aux_str, "OK", 2000);
delay(3000);
// starts the GPS and waits for signal
while ( start_GPS() == 0);
while (sendATcommand("AT+CREG?", "+CREG: 0,1", 2000) == 0);
// sets APN , user name and password
sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 2000);
snprintf(aux_str, sizeof(aux_str), "AT+SAPBR=3,1,\"APN\",\"%s\"", apn);
sendATcommand(aux_str, "OK", 2000);
snprintf(aux_str, sizeof(aux_str), "AT+SAPBR=3,1,\"USER\",\"%s\"", user_name);
sendATcommand(aux_str, "OK", 2000);
snprintf(aux_str, sizeof(aux_str), "AT+SAPBR=3,1,\"PWD\",\"%s\"", password);
sendATcommand(aux_str, "OK", 2000);
// gets the GPRS bearer
while (sendATcommand("AT+SAPBR=1,1", "OK", 20000) == 0)
{
delay(5000);
}
}
void loop(){
// gets GPS data
get_GPS();
// sends GPS data to the script
send_HTTP();
delay(5000);
}
void power_on(){
uint8_t answer=0;
// checks if the module is started
answer = sendATcommand("AT", "OK", 2000);
if (answer == 0)
{
// power on pulse
digitalWrite(onModulePin,HIGH);
delay(3000);
digitalWrite(onModulePin,LOW);
// waits for an answer from the module
while(answer == 0){
// Send AT every two seconds and wait for the answer
answer = sendATcommand("AT", "OK", 2000);
}
}
}
int8_t start_GPS(){
unsigned long previous;
previous = millis();
// starts the GPS
sendATcommand("AT+CGPSPWR=1", "OK", 2000);
sendATcommand("AT+CGPSRST=0", "OK", 2000);
// waits for fix GPS
while(( (sendATcommand("AT+CGPSSTATUS?", "2D Fix", 5000) ||
sendATcommand("AT+CGPSSTATUS?", "3D Fix", 5000)) == 0 ) &&
((millis() - previous) < 90000));
if ((millis() - previous) < 90000)
{
return 1;
}
else
{
return 0;
}
}
int8_t get_GPS(){
int8_t counter, answer;
long previous;
// First get the NMEA string
// Clean the input buffer
while( Serial.available() > 0) Serial.read();
// request Basic string
sendATcommand("AT+CGPSINF=0", "AT+CGPSINF=0\r\n\r\n", 2000);
counter = 0;
answer = 0;
memset(frame, '\0', 100); // Initialize the string
previous = millis();
// this loop waits for the NMEA string
do{
if(Serial.available() != 0){
frame[counter] = Serial.read();
counter++;
// check if the desired answer is in the response of the module
if (strstr(frame, "OK") != NULL)
{
answer = 1;
}
}
// Waits for the asnwer with time out
}
while((answer == 0) && ((millis() - previous) < 2000));
frame[counter-3] = '\0';
// Parses the string
strtok(frame, ",");
strcpy(longitude,strtok(NULL, ",")); // Gets longitude
strcpy(latitude,strtok(NULL, ",")); // Gets latitude
strcpy(altitude,strtok(NULL, ".")); // Gets altitude
strtok(NULL, ",");
strcpy(date,strtok(NULL, ".")); // Gets date
strtok(NULL, ",");
strtok(NULL, ",");
strcpy(satellites,strtok(NULL, ",")); // Gets satellites
strcpy(speedOTG,strtok(NULL, ",")); // Gets speed over ground. Unit is knots.
strcpy(course,strtok(NULL, "\r")); // Gets course
convert2Degrees(latitude);
convert2Degrees(longitude);
return answer;
}
/* convert2Degrees ( input ) - performs the conversion from input
* parameters in DD°MM.mmm’ notation to DD.dddddd° notation.
*
* Sign '+' is set for positive latitudes/longitudes (North, East)
* Sign '-' is set for negative latitudes/longitudes (South, West)
*
*/
int8_t convert2Degrees(char* input){
float deg;
float minutes;
boolean neg = false;
//auxiliar variable
char aux[10];
if (input[0] == '-')
{
neg = true;
strcpy(aux, strtok(input+1, "."));
}
else
{
strcpy(aux, strtok(input, "."));
}
// convert string to integer and add it to final float variable
deg = atof(aux);
strcpy(aux, strtok(NULL, '\0'));
minutes=atof(aux);
minutes/=1000000;
if (deg < 100)
{
minutes += deg;
deg = 0;
}
else
{
minutes += int(deg) % 100;
deg = int(deg) / 100;
}
// add minutes to degrees
deg=deg+minutes/60;
if (neg == true)
{
deg*=-1.0;
}
neg = false;
if( deg < 0 ){
neg = true;
deg*=-1;
}
float numberFloat=deg;
int intPart[10];
int digit;
long newNumber=(long)numberFloat;
int size=0;
while(1){
size=size+1;
digit=newNumber%10;
newNumber=newNumber/10;
intPart[size-1]=digit;
if (newNumber==0){
break;
}
}
int index=0;
if( neg ){
index++;
input[0]='-';
}
for (int i=size-1; i >= 0; i--)
{
input[index]=intPart[i]+'0';
index++;
}
input[index]='.';
index++;
numberFloat=(numberFloat-(int)numberFloat);
for (int i=1; i<=10 ; i++)
{
numberFloat=numberFloat*10;
digit= (long)numberFloat;
numberFloat=numberFloat-digit;
input[index]=char(digit)+48;
index++;
}
input[index]='\0';
}
void send_HTTP(){
uint8_t answer=0;
// Initializes HTTP service
answer = sendATcommand("AT+HTTPINIT", "OK", 10000);
if (answer == 1)
{
// Sets CID parameter
answer = sendATcommand("AT+HTTPPARA=\"CID\",1", "OK", 5000);
if (answer == 1)
{
// Sets url
sprintf(aux_str, "AT+HTTPPARA=\"URL\",\"http://%s/vehicleLocationTransmitter.php?", url);
Serial.print(aux_str);
sprintf(frame, "vehicleID=1&latitude=%s&longitude=%s&altitude=%s&time=%s&satellites=%s",
latitude, longitude, altitude, date, satellites);
Serial.print(frame);
answer = sendATcommand("\"", "OK", 5000);
if (answer == 1)
{
// Starts GET action
answer = sendATcommand("AT+HTTPACTION=0", "+HTTPACTION:0,200", 30000);
if (answer == 1)
{
Serial.println(F("Done!"));
}
else
{
Serial.println(F("Error getting url"));
}
}
else
{
Serial.println(F("Error setting the url"));
}
}
else
{
Serial.println(F("Error setting the CID"));
}
}
else
{
Serial.println(F("Error initializating"));
}
sendATcommand("AT+HTTPTERM", "OK", 5000);
}
int8_t sendATcommand(char* ATcommand, char* expected_answer1, unsigned int timeout){
uint8_t x=0, answer=0;
char response[100];
unsigned long previous;
memset(response, '\0', 100); // Initialize the string
delay(100);
while( Serial.available() > 0) Serial.read(); // Clean the input buffer
Serial.println(ATcommand); // Send the AT command
x = 0;
previous = millis();
// this loop waits for the answer
do{
if(Serial.available() != 0){
response[x] = Serial.read();
x++;
// check if the desired answer is in the response of the module
if (strstr(response, expected_answer1) != NULL)
{
answer = 1;
}
}
// Waits for the asnwer with time out
}
while((answer == 0) && ((millis() - previous) < timeout));
return answer;
}

Write a test case for the function in doubt (convert2Degrees())
from the comment: "parameters in DD°MM.mmm’ notation to DD.dddddd°":
If you input: 52°27.123
Then the expected Output should be: 52.45205
Calculation: 52°27.123 = 52 + 27.123/60.0 =
= 52.45205
Further you should post here the value which is input to convert2Degrees()

Your use of strtok is incorrect, and the convert2degrees has major problems.
Here's something derived from NeoGPS that doesn't use the expensive (on AVRs) divide or modulo arithmetic:
//.................................................
// A special divide-by-3 function that avoids division.
// From http://www.hackersdelight.org/divcMore.pdf
static uint32_t divu3( uint32_t n )
{
uint32_t q = (n >> 2) + (n >> 4); // q = n*0.0101 (approx).
q = q + (q >> 4); // q = n*0.01010101.
q = q + (q >> 8);
q = q + (q >> 16);
uint32_t r = n - q*3; // 0 <= r <= 15.
return q + (11*r >> 5); // Returning q + r/3.
}
//------------------------------------------------------------
// Parse the NMEA "DDDMM.mmmm" format for lat and lon.
//
// returns degrees * 10^7
uint32_t parseDDMMmmmm( char *input )
{
uint8_t digits = 0;
uint8_t sixth_digit = 0;
char chr;
// Find the decimal point
while (isdigit( input[digits] ))
digits++;
// All but the last two are degrees.
uint32_t val = 0;
while (digits > 2) {
chr = *input++;
val = val*10 + (chr - '0');
digits--;
}
// convert from degrees to minutes
val *= 60;
// Add in the last 2 minutes digits
uint8_t minutes = 0;
while (digits > 0) {
chr = *input++;
minutes = minutes*10 + (chr - '0');
digits--;
}
val += minutes;
// Decimal point?
chr = *input++;
if (chr == '.') {
chr = *input++;
// Parse up to 6 digits of the fractional minutes.
while ((digits++ < 5) && isdigit( chr )) {
val = val*10 + (chr - '0');
chr = *input++;
}
if ((digits == 6) && isdigit(chr)) {
sixth_digit = chr - '0';
digits++;
}
// Scale the value up to minutes x 1000000.
while (digits < 4) {
val *= 10;
digits++;
}
}
// convert from minutes x 1000000 to degrees x 10000000.
val += divu3( val*2 + 1 ); // same as 10 * (val+30)/60 without truncation
if (digits >= 6) {
if (sixth_digit >= 9)
val += 2;
else if (sixth_digit >= 4)
val += 1;
}
return val;
} // parseDDMMmmmm
...and a floating-point version:
double parseDDMMmmmm_f( char *input )
{
uint8_t digits = 0;
char chr;
// Find the decimal point
while (isdigit( input[digits] ))
digits++;
// All but the last two are degrees.
double val = 0.0;
while (digits > 2) {
chr = *input++;
val = val*10 + (chr - '0');
digits--;
}
// convert from degrees to minutes
val *= 60;
// Add in the last 2 minutes digits
uint8_t minutes = 0;
while (digits > 0) {
chr = *input++;
minutes = minutes*10 + (chr - '0');
digits--;
}
val += minutes;
// Decimal point?
chr = *input++;
if (chr == '.') {
chr = *input++;
// Parse the fractional "mmmm" minutes.
while (isdigit( chr ) && (digits++ <= 4)) {
val = val*10 + (chr - '0');
chr = *input++;
}
// Scale the value up to minutes x 1000000.
while (digits < 4) {
val *= 10;
digits++;
}
}
// convert from minutes x 1000000 to degrees.
val *= 10.0/1000000.0 * 1.0/60.0;
return val;
} // parseDDMMmmmm_f
If you use these functions, you also need to pop the '-' off the front of your AT string, and negate the returned values:
bool south = (latitude[0] == '-');
if (south)
latitude++;
float lat = parseDDMMmmmm_f( latitude );
if (south)
lat = -lat;
convert2Degrees(longitude);
bool west = (longitude[0] == '-');
if (west)
longitude++;
float lon = parseDDMMmmmm_f( longitude );
if (west)
lon = -lon;[/code]

Related

Reading JSON from Serial port missing part of the starting data

When reading a JSON string from the serial port on an ESP8266 it cuts off the beginning of the data.
I have tried reading data from the Serial port and printing each character, however it is cutting off part of the begging of the data.
void setup() {
Serial.begin(115200);
while (!Serial) {
;
}
}
void loop() {
int curSize = 30;
char* buffer = new char[curSize];
std::fill_n(buffer, curSize, 0);
int pos = 0;
Serial.print("Sending: ");
while(Serial.available() == false) delay(500);
while (Serial.available()) {
char c = Serial.read();
Serial.print(c);
if(pos == curSize-1){
char* newBuffer = increaseBuffer(buffer, curSize, curSize + 30);
curSize += 30;
delete[] buffer;
buffer = newBuffer;
}
if(c == '\n'){
buffer[pos] = 0;
pos = 0;
break;
}
buffer[pos++] = c;
}
if(buffer[0] != 0) {
sendBuffer(buffer);
}
delete[] buffer;
}
char* increaseBuffer(char* orig, int oldSize, int newSize){
char* data = new char[newSize];
std::fill_n(data, newSize, 0);
for(int i = 0; i < newSize; i++){
if(i < oldSize) data[i] = orig[i];
else data[i] = '\0';
}
return data;
}
JSON data used (and expected output)
{"type":0,"ver":"0.0.1","T":[28,29,29,29,29,29,29,29,29,29],"H":[59.1608,59.1608,60,59.1608,60,60,60,59.1608,59.1608,59.1608],"DP":[20.36254,20.36254,20.59363,20.36254,20.59363,20.59363,20.59363,20.36254,20.36254],"HI":[30.90588,30.90588,31.0335,30.90588,31.0335,31.0335,31.0335,30.90588,30.90588]}
examples of what is actually output
Example 1: 9,29,29,29,29,29,29,29,29],"H":[59.1608,59.1608,60,59.1608,60,60,60,59.1608,59.1608,59.1608],"DP":[20.36254,20.36254,20.59363,20.36254,20.59363,20.59363,20.59363,20.36254,20.36254],"HI":[30.90588,30.90588,31.0335,30.90588,31.0335,31.0335,31.0335,30.90588,30.90588]}
Example 2: 29,29,29,29,29,29,29,29,29],"H":[59.1608,59.1608,60,59.1608,60,60,60,59.1608,59.1608,59.1608],"DP":[20.36254,20.36254,20.59363,20.36254,20.59363,20.59363,20.59363,20.36254,20.36254],"HI":[30.90588,30.90588,31.0335,30.90588,31.0335,31.0335,31.0335,30.90588,30.90588]}
Try making the delay 1 instead of 500 in the blocking loop that's waiting for data to start coming in. I'm going to guess what happens is that on one iteration of that loop Serial.available() is false and during the delay you start to get data coming in that ends up getting written over by the time your delay ends to check again.
What I'm picturing is the following. If you were to expand out that delay(500) to be delay(1) called 500 times.
while(Serial.available() == false){
delay(1);
delay(1);
// ...
delay(1); // first character comes in
delay(1);
delay(1); // second character comes in
// ...
delay(1); // n character comes in
}
Then after the delay is over you start actually collecting the characters that are coming in.

No NVENC capable devices found

I met a weird question.I have been using FFmpeg's NVENC to encode video .It is strange that I can use h264_nvenc smoothly without problem,but when I replace h264_nvenc with hevc_nvenc,I got the problem "No NVENC capable devices found".The FFmpeg version I am using is 3.2,and I use command line to encode with hevc_nvenc,it works ok.My code is here:
#include "stdafx.h"
int flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index)
{
int ret;
int got_frame;
AVPacket enc_pkt;
if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
CODEC_CAP_DELAY))
return 0;
while (1) {
printf("Flushing stream #%u encoder\n", stream_index);
//ret = encode_write_frame(NULL, stream_index, &got_frame);
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec, &enc_pkt,
NULL, &got_frame);
av_frame_free(NULL);
if (ret < 0)
break;
if (!got_frame){
ret = 0;
break;
}
printf("Succeed to encode 1 frame! 编码成功1帧!\n");
/* mux encoded frame */
ret = av_write_frame(fmt_ctx, &enc_pkt);
if (ret < 0)
break;
}
return ret;
}
int main(int argc, char* argv[])
{
AVFormatContext* pFormatCtx;
AVOutputFormat* fmt;
AVStream* video_st;
AVCodecContext* pCodecCtx;
AVCodec* pCodec;
uint8_t* picture_buf;
AVFrame* picture;
int size;
FILE *in_file = fopen("test_yuv420p_320x180.yuv", "rb"); //Input YUV data 视频YUV源文件
int in_w = 320, in_h = 180;//宽高
int framenum = 100;
const char* out_file = "ds.hevc";
av_register_all();
//Method1 方法1.组合使用几个函数
pFormatCtx = avformat_alloc_context();
//Guess Format 猜格式
fmt = av_guess_format(NULL, out_file, NULL);
pFormatCtx->oformat = fmt;
//Method 2 方法2.更加自动化一些
//avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);
//fmt = pFormatCtx->oformat;
//Output Format 注意输出路径
if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0)
{
printf("Failed to open output file! 输出文件打开失败");
return -1;
}
video_st = avformat_new_stream(pFormatCtx, 0);
video_st->time_base.num = 1;
video_st->time_base.den = 25;
if (video_st == NULL)
{
return -1;
}
//Param that must set
pCodecCtx = video_st->codec;
pCodecCtx->codec_id =AV_CODEC_ID_HEVC;
//pCodecCtx->codec_id = fmt->video_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
pCodecCtx->width = in_w;
pCodecCtx->height = in_h;
pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = 25;
pCodecCtx->bit_rate = 400000;
pCodecCtx->gop_size = 12;
//H264
//pCodecCtx->me_range = 16;
//pCodecCtx->max_qdiff = 4;
//pCodecCtx->qcompress = 0.6;
pCodecCtx->qmin = 10;
pCodecCtx->qmax = 51;
//Optional Param
pCodecCtx->max_b_frames = 3;
// Set Option
AVDictionary *param = 0;
//H.264
if (pCodecCtx->codec_id == AV_CODEC_ID_H264) {
av_dict_set(&param, "preset", "slow", 0);
av_dict_set(&param, "tune", "zerolatency", 0);
}
//H.265
if (pCodecCtx->codec_id == AV_CODEC_ID_H265){
av_dict_set(&param, "x265-params", "qp=20", 0);
av_dict_set(&param, "preset", "default", 0);
av_dict_set(&param, "tune", "zero-latency", 0);
}
//Dump Information 输出格式信息
av_dump_format(pFormatCtx, 0, out_file, 1);
//pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
pCodec = avcodec_find_encoder_by_name("hevc_nvenc");
if (!pCodec){
printf("Can not find encoder! 没有找到合适的编码器!\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, &param) < 0){
printf("Failed to open encoder! 编码器打开失败!\n");
return -1;
}
picture = av_frame_alloc();
size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
picture_buf = (uint8_t *)av_malloc(size);
avpicture_fill((AVPicture *)picture, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
//Write File Header 写文件头
avformat_write_header(pFormatCtx, NULL);
AVPacket pkt;
int y_size = pCodecCtx->width * pCodecCtx->height;
av_new_packet(&pkt, y_size * 3);
for (int i = 0; i<framenum; i++){
//Read YUV 读入YUV
if (fread(picture_buf, 1, y_size * 3 / 2, in_file) < 0){
printf("Failed to read YUV data! 文件读取错误\n");
return -1;
}
else if (feof(in_file)){
break;
}
picture->data[0] = picture_buf; // 亮度Y
picture->data[1] = picture_buf + y_size; // U
picture->data[2] = picture_buf + y_size * 5 / 4; // V
//PTS
picture->pts = i;
picture->format = pCodecCtx->pix_fmt;
picture->width = in_w;
picture->height = in_h;
int got_picture = 0;
//Encode 编码
int ret = avcodec_encode_video2(pCodecCtx, &pkt, picture, &got_picture);
if (ret < 0){
printf("Failed to encode! 编码错误!\n");
return -1;
}
if (got_picture == 1){
printf("Succeed to encode 1 frame! 编码成功1帧!\n");
pkt.stream_index = video_st->index;
ret = av_write_frame(pFormatCtx, &pkt);
av_free_packet(&pkt);
}
}
//Flush Encoder
int ret = flush_encoder(pFormatCtx, 0);
if (ret < 0) {
printf("Flushing encoder failed\n");
return -1;
}
//Write file trailer 写文件尾
av_write_trailer(pFormatCtx);
//Clean 清理
if (video_st){
avcodec_close(video_st->codec);
av_free(picture);
av_free(picture_buf);
}
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
fclose(in_file);
system("pause");
return 0;
}
Help!!!!
after a few days of strugglling,once again I try anwser the question myself.The key point is ,when encoding with hevc_nvenc,you must set pCodecCtx->max_b_frames = 0;(at least for version 3.2 of ffmpeg).

Who to talk to about non recursive Ackermann function?

I have written a non recursive solution to the Ackermann function, it seems to work perfectly and work faster than the common recursive solution. So I am confused as to why it is a non primitive recursive function if it can be solved iteratively? Could anyone tell me if I have misunderstood something about what primitive recursive functions are or who should I talk to about this to get an answer?
Below is the Java code:
import java.util.Scanner;
import java.util.ArrayList;
public class ackermann {
public static void main(String[] args){
Scanner in = new Scanner(System.in);
System.out.println("Enter m:");
int m = in.nextInt();
System.out.println("Enter n:");
int n = in.nextInt();
ack(m, n);
}
public static void ack(int inM, int inN){
if(inM < 0 || inN < 0) return;
ArrayList<ArrayList<Integer>> arr = new ArrayList<ArrayList<Integer>>();
for(int m = 0; m <= inM; m++){
arr.add(new ArrayList<Integer>());
}
Boolean done = false;
while(done == false){
for(int m = 0; m <= inM; m++){
int n = arr.get(m).size();
int a = 0;
if(m == 0) a = n + 1;
else if(n == 0){
if(arr.get(m - 1).size() <= 1) break;
a = arr.get(m - 1).get(1);
} else {
int k = arr.get(m).get(n - 1);
if(arr.get(m - 1).size() <= k) break;
a = arr.get(m - 1).get(k);
}
arr.get(m).add(a);
if(m == inM && n == inN){
System.out.println("Ack(" + inM + ", " + inN + ") = " + a);
done = true;
break;
}
}
}
}
}
Primitive recursive functions can be implemented using only assignment, +, and definite loops. By this I mean loops of the form:
for(int i = 0; i < n; i++) { ... }
Where n is a variable that isn't changed in the loop body. To get Ackermann's function, which majorizes all primitive recursive functions, one needs to add either a goto command or indefinite loops like your while loop.

How would you calculate all possible permutations of 0 through N iteratively?

I need to calculate permutations iteratively. The method signature looks like:
int[][] permute(int n)
For n = 3 for example, the return value would be:
[[0,1,2],
[0,2,1],
[1,0,2],
[1,2,0],
[2,0,1],
[2,1,0]]
How would you go about doing this iteratively in the most efficient way possible? I can do this recursively, but I'm interested in seeing lots of alternate ways to doing it iteratively.
see QuickPerm algorithm, it's iterative : http://www.quickperm.org/
Edit:
Rewritten in Ruby for clarity:
def permute_map(n)
results = []
a, p = (0...n).to_a, [0] * n
i, j = 0, 0
i = 1
results << yield(a)
while i < n
if p[i] < i
j = i % 2 * p[i] # If i is odd, then j = p[i], else j = 0
a[j], a[i] = a[i], a[j] # Swap
results << yield(a)
p[i] += 1
i = 1
else
p[i] = 0
i += 1
end
end
return results
end
The algorithm for stepping from one permutation to the next is very similar to elementary school addition - when an overflow occurs, "carry the one".
Here's an implementation I wrote in C:
#include <stdio.h>
//Convenience macro. Its function should be obvious.
#define swap(a,b) do { \
typeof(a) __tmp = (a); \
(a) = (b); \
(b) = __tmp; \
} while(0)
void perm_start(unsigned int n[], unsigned int count) {
unsigned int i;
for (i=0; i<count; i++)
n[i] = i;
}
//Returns 0 on wraparound
int perm_next(unsigned int n[], unsigned int count) {
unsigned int tail, i, j;
if (count <= 1)
return 0;
/* Find all terms at the end that are in reverse order.
Example: 0 3 (5 4 2 1) (i becomes 2) */
for (i=count-1; i>0 && n[i-1] >= n[i]; i--);
tail = i;
if (tail > 0) {
/* Find the last item from the tail set greater than
the last item from the head set, and swap them.
Example: 0 3* (5 4* 2 1)
Becomes: 0 4* (5 3* 2 1) */
for (j=count-1; j>tail && n[j] <= n[tail-1]; j--);
swap(n[tail-1], n[j]);
}
/* Reverse the tail set's order */
for (i=tail, j=count-1; i<j; i++, j--)
swap(n[i], n[j]);
/* If the entire list was in reverse order, tail will be zero. */
return (tail != 0);
}
int main(void)
{
#define N 3
unsigned int perm[N];
perm_start(perm, N);
do {
int i;
for (i = 0; i < N; i++)
printf("%d ", perm[i]);
printf("\n");
} while (perm_next(perm, N));
return 0;
}
Is using 1.9's Array#permutation an option?
>> a = [0,1,2].permutation(3).to_a
=> [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
Below is my generics version of the next permutation algorithm in C# closely resembling the STL's next_permutation function (but it doesn't reverse the collection if it is the max possible permutation already, like the C++ version does)
In theory it should work with any IList<> of IComparables.
static bool NextPermutation<T>(IList<T> a) where T: IComparable
{
if (a.Count < 2) return false;
var k = a.Count-2;
while (k >= 0 && a[k].CompareTo( a[k+1]) >=0) k--;
if(k<0)return false;
var l = a.Count - 1;
while (l > k && a[l].CompareTo(a[k]) <= 0) l--;
var tmp = a[k];
a[k] = a[l];
a[l] = tmp;
var i = k + 1;
var j = a.Count - 1;
while(i<j)
{
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
i++;
j--;
}
return true;
}
And the demo/test code:
var src = "1234".ToCharArray();
do
{
Console.WriteLine(src);
}
while (NextPermutation(src));
I also came across the QuickPerm algorithm referenced in another answer. I wanted to share this answer in addition, because I saw some immediate changes one can make to write it shorter. For example, if the index array "p" is initialized slightly differently, it saves having to return the first permutation before the loop. Also, all those while-loops and if's took up a lot more room.
void permute(char* s, size_t l) {
int* p = new int[l];
for (int i = 0; i < l; i++) p[i] = i;
for (size_t i = 0; i < l; printf("%s\n", s)) {
std::swap(s[i], s[i % 2 * --p[i]]);
for (i = 1; p[i] == 0; i++) p[i] = i;
}
}
I found Joey Adams' version to be the most readable, but I couldn't port it directly to C# because of how C# handles the scoping of for-loop variables. Hence, this is a slightly tweaked version of his code:
/// <summary>
/// Performs an in-place permutation of <paramref name="values"/>, and returns if there
/// are any more permutations remaining.
/// </summary>
private static bool NextPermutation(int[] values)
{
if (values.Length == 0)
throw new ArgumentException("Cannot permutate an empty collection.");
//Find all terms at the end that are in reverse order.
// Example: 0 3 (5 4 2 1) (i becomes 2)
int tail = values.Length - 1;
while(tail > 0 && values[tail - 1] >= values[tail])
tail--;
if (tail > 0)
{
//Find the last item from the tail set greater than the last item from the head
//set, and swap them.
// Example: 0 3* (5 4* 2 1)
// Becomes: 0 4* (5 3* 2 1)
int index = values.Length - 1;
while (index > tail && values[index] <= values[tail - 1])
index--;
Swap(ref values[tail - 1], ref values[index]);
}
//Reverse the tail set's order.
int limit = (values.Length - tail) / 2;
for (int index = 0; index < limit; index++)
Swap(ref values[tail + index], ref values[values.Length - 1 - index]);
//If the entire list was in reverse order, tail will be zero.
return (tail != 0);
}
private static void Swap<T>(ref T left, ref T right)
{
T temp = left;
left = right;
right = temp;
}
Here's an implementation in C#, as an extension method:
public static IEnumerable<List<T>> Permute<T>(this IList<T> items)
{
var indexes = Enumerable.Range(0, items.Count).ToArray();
yield return indexes.Select(idx => items[idx]).ToList();
var weights = new int[items.Count];
var idxUpper = 1;
while (idxUpper < items.Count)
{
if (weights[idxUpper] < idxUpper)
{
var idxLower = idxUpper % 2 * weights[idxUpper];
var tmp = indexes[idxLower];
indexes[idxLower] = indexes[idxUpper];
indexes[idxUpper] = tmp;
yield return indexes.Select(idx => items[idx]).ToList();
weights[idxUpper]++;
idxUpper = 1;
}
else
{
weights[idxUpper] = 0;
idxUpper++;
}
}
}
And a unit test:
[TestMethod]
public void Permute()
{
var ints = new[] { 1, 2, 3 };
var orderings = ints.Permute().ToList();
Assert.AreEqual(6, orderings.Count);
AssertUtil.SequencesAreEqual(new[] { 1, 2, 3 }, orderings[0]);
AssertUtil.SequencesAreEqual(new[] { 2, 1, 3 }, orderings[1]);
AssertUtil.SequencesAreEqual(new[] { 3, 1, 2 }, orderings[2]);
AssertUtil.SequencesAreEqual(new[] { 1, 3, 2 }, orderings[3]);
AssertUtil.SequencesAreEqual(new[] { 2, 3, 1 }, orderings[4]);
AssertUtil.SequencesAreEqual(new[] { 3, 2, 1 }, orderings[5]);
}
The method AssertUtil.SequencesAreEqual is a custom test helper which can be recreated easily enough.
How about a recursive algorithm you can call iteratively? If you'd actually need that stuff as a list like that (you should clearly inline that rather than allocate a bunch of pointless memory). You could simply calculate the permutation on the fly, by its index.
Much like the permutation is carry-the-one addition re-reversing the tail (rather than reverting to 0), indexing the specific permutation value is finding the digits of a number in base n then n-1 then n-2... through each iteration.
public static <T> boolean permutation(List<T> values, int index) {
return permutation(values, values.size() - 1, index);
}
private static <T> boolean permutation(List<T> values, int n, int index) {
if ((index == 0) || (n == 0)) return (index == 0);
Collections.swap(values, n, n-(index % n));
return permutation(values,n-1,index/n);
}
The boolean returns whether your index value was out of bounds. Namely that it ran out of n values but still had remaining index left over.
And it can't get all the permutations for more than 12 objects.
12! < Integer.MAX_VALUE < 13!
-- But, it's so very very pretty. And if you do a lot of things wrong might be useful.
I have implemented the algorithm in Javascript.
var all = ["a", "b", "c"];
console.log(permute(all));
function permute(a){
var i=1,j, temp = "";
var p = [];
var n = a.length;
var output = [];
output.push(a.slice());
for(var b=0; b <= n; b++){
p[b] = b;
}
while (i < n){
p[i]--;
if(i%2 == 1){
j = p[i];
}
else{
j = 0;
}
temp = a[j];
a[j] = a[i];
a[i] = temp;
i=1;
while (p[i] === 0){
p[i] = i;
i++;
}
output.push(a.slice());
}
return output;
}
I've used the algorithms from here. The page contains a lot of useful information.
Edit: Sorry, those were recursive. uray posted the link to the iterative algorithm in his answer.
I've created a PHP example. Unless you really need to return all of the results, I would only create an iterative class like the following:
<?php
class Permutator implements Iterator
{
private $a, $n, $p, $i, $j, $k;
private $stop;
public function __construct(array $a)
{
$this->a = array_values($a);
$this->n = count($this->a);
}
public function current()
{
return $this->a;
}
public function next()
{
++$this->k;
while ($this->i < $this->n)
{
if ($this->p[$this->i] < $this->i)
{
$this->j = ($this->i % 2) * $this->p[$this->i];
$tmp = $this->a[$this->j];
$this->a[$this->j] = $this->a[$this->i];
$this->a[$this->i] = $tmp;
$this->p[$this->i]++;
$this->i = 1;
return;
}
$this->p[$this->i++] = 0;
}
$this->stop = true;
}
public function key()
{
return $this->k;
}
public function valid()
{
return !$this->stop;
}
public function rewind()
{
if ($this->n) $this->p = array_fill(0, $this->n, 0);
$this->stop = $this->n == 0;
$this->i = 1;
$this->j = 0;
$this->k = 0;
}
}
foreach (new Permutator(array(1,2,3,4,5)) as $permutation)
{
var_dump($permutation);
}
?>
Note that it treats every PHP array as an indexed array.

How to decode HTML Entities in C?

I'm interested in unescaping text for example: \ maps to \ in C. Does anyone know of a good library?
As reference the Wikipedia List of XML and HTML Character Entity References.
For another open source reference in C to decoding these HTML entities you can check out the command line utility uni2ascii/ascii2uni. The relevant files are enttbl.{c,h} for entity lookup and putu8.c which down converts from UTF32 to UTF8.
uni2ascii
I wrote my own unescape code; very simplified, but does the job: pn_util.c
Function Description: Convert special HTML entities back to characters.
Need to do some modifications to fit your requirement.
char* HtmlSpecialChars_Decode(char* encodedHtmlSpecialEntities)
{
int encodedLen = 0;
int escapeArrayLen = 0;
static char decodedHtmlSpecialChars[TITLE_SIZE];
char innerHtmlSpecialEntities[MAX_CONFIG_ITEM_SIZE];
/* This mapping table can be extended if necessary. */
static const struct {
const char* encodedEntity;
const char decodedChar;
} entityToChars[] = {
{"<", '<'},
{">", '>'},
{"&", '&'},
{""", '"'},
{"'", '\''},
};
if(strchr(encodedHtmlSpecialEntities, '&') == NULL)
return encodedHtmlSpecialEntities;
memset(decodedHtmlSpecialChars, '\0', TITLE_SIZE);
memset(innerHtmlSpecialEntities, '\0', MAX_CONFIG_ITEM_SIZE);
escapeArrayLen = sizeof(entityToChars) / sizeof(entityToChars[0]);
strcpy(innerHtmlSpecialEntities, encodedHtmlSpecialEntities);
encodedLen = strlen(innerHtmlSpecialEntities);
for(int i = 0; i < encodedLen; i++)
{
if(innerHtmlSpecialEntities[i] == '&')
{
/* Potential encode char. */
char * tempEntities = innerHtmlSpecialEntities + i;
for(int j = 0; j < escapeArrayLen; j++)
{
if(strncmp(tempEntities, entityToChars[j].encodedEntity, strlen(entityToChars[j].encodedEntity)) == 0)
{
int index = 0;
strncat(decodedHtmlSpecialChars, innerHtmlSpecialEntities, i);
index = strlen(decodedHtmlSpecialChars);
decodedHtmlSpecialChars[index] = entityToChars[j].decodedChar;
if(strlen(tempEntities) > strlen(entityToChars[j].encodedEntity))
{
/* Not to the end, continue */
char temp[MAX_CONFIG_ITEM_SIZE] = {'\0'};
strcpy(temp, tempEntities + strlen(entityToChars[j].encodedEntity));
memset(innerHtmlSpecialEntities, '\0', MAX_CONFIG_ITEM_SIZE);
strcpy(innerHtmlSpecialEntities, temp);
encodedLen = strlen(innerHtmlSpecialEntities);
i = -1;
}
else
encodedLen = 0;
break;
}
}
}
}
if(encodedLen != 0)
strcat(decodedHtmlSpecialChars, innerHtmlSpecialEntities);
return decodedHtmlSpecialChars;
}
QString UNESC(const QString &txt) {
QStringList bld;
static QChar AMP = '&', SCL = ';';
static QMap<QString, QString> dec = {
{"<", "<"}, {">", ">"}
, {"&", "&"}, {""", R"(")"}, {"'", "'"} };
if(!txt.contains(AMP)) { return txt; }
int bgn = 0, pos = 0;
while((pos = txt.indexOf(AMP, pos)) != -1) {
int end = txt.indexOf(SCL, pos)+1;
QString val = dec[txt.mid(pos, end - pos)];
bld << txt.mid(bgn, pos - bgn);
if(val.isEmpty()) {
end = txt.indexOf(AMP, pos+1);
bld << txt.mid(pos, end - pos);
} else {
bld << val;
}// else // if(val.isEmpty())
bgn = end; pos = end;
}// while((pos = txt.indexOf(AMP, pos)) != -1)
return bld.join(QString());
}// UNESC